From b0bbfd1bb75794f6664334f60fa2bcf064ea3bd3 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 4 Aug 2025 01:53:10 +0800 Subject: [PATCH 001/251] Add assignment type analysis for ide-completion --- .../ide-completion/src/context/analysis.rs | 32 ++++++++++++ .../ide-completion/src/context/tests.rs | 50 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index ea5fb39338b2e..67fc79e8032c1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -562,6 +562,7 @@ fn expected_type_and_name<'db>( token: &SyntaxToken, name_like: &ast::NameLike, ) -> (Option>, Option) { + let token = prev_assign_token_at_whitespace(token.clone()); let mut node = match token.parent() { Some(it) => it, None => return (None, None), @@ -632,6 +633,17 @@ fn expected_type_and_name<'db>( .map(TypeInfo::original); (ty, None) }, + ast::BinExpr(it) => { + if let Some(ast::BinaryOp::Assignment { op: None }) = it.op_kind() { + let ty = it.lhs() + .and_then(|lhs| sema.type_of_expr(&lhs)) + .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs))) + .map(TypeInfo::original); + (ty, None) + } else { + (None, None) + } + }, ast::ArgList(_) => { cov_mark::hit!(expected_type_fn_param); ActiveParameter::at_token( @@ -1870,3 +1882,23 @@ fn next_non_trivia_sibling(ele: SyntaxElement) -> Option { } None } + +fn prev_assign_token_at_whitespace(mut token: SyntaxToken) -> SyntaxToken { + while token.kind() == SyntaxKind::WHITESPACE + && let Some(prev) = token.prev_token() + && let T![=] + | T![+=] + | T![/=] + | T![*=] + | T![%=] + | T![>>=] + | T![<<=] + | T![-=] + | T![|=] + | T![&=] + | T![^=] = prev.kind() + { + token = prev + } + token +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 75c20968e1e5f..7a8c70f190efc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -434,3 +434,53 @@ fn f(thing: u32) -> &u32 { expect!["ty: u32, name: ?"], ); } + +#[test] +fn expected_type_assign() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() { + let x: &mut State = &mut State::Stop; + x = $0; +} +"#, + expect![[r#"ty: &'_ mut State, name: ?"#]], + ); +} + +#[test] +fn expected_type_deref_assign() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() { + let x: &mut State = &mut State::Stop; + match x { + State::Stop => { + *x = $0; + }, + } +} +"#, + expect![[r#"ty: State, name: ?"#]], + ); +} + +#[test] +fn expected_type_deref_assign_at_block_end() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() { + let x: &mut State = &mut State::Stop; + match x { + State::Stop => { + *x = $0 + }, + } +} +"#, + expect![[r#"ty: State, name: ?"#]], + ); +} From bf500ec822cb27ec82a259c3edc0cba86e7b1ac4 Mon Sep 17 00:00:00 2001 From: skewb1k Date: Mon, 4 Aug 2025 14:11:06 +0300 Subject: [PATCH 002/251] chore: fix crates/ide/src/folding_ranges.rs file perms 755 -> 644 --- src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs old mode 100755 new mode 100644 From 1d817dc7a782e011797de3225037241eaabdf631 Mon Sep 17 00:00:00 2001 From: skewb1k Date: Mon, 4 Aug 2025 14:42:45 +0300 Subject: [PATCH 003/251] fix(hover): unify horizontal rule formatting to `---` Replaces all `___` with `---` in hover documentation markups. Both styles are valid per the GitHub Flavored Markdown spec, but `---` is less ambiguous and already more widely used in rust-analyzer --- .../crates/ide/src/hover/render.rs | 8 +- .../crates/ide/src/hover/tests.rs | 76 +++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 51b5900e8155a..653465e9ed5ba 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -361,7 +361,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option { let backtick_len = value.chars().filter(|c| *c == '`').count(); @@ -1026,7 +1026,7 @@ fn type_info( if let Some(extra) = render_notable_trait(db, ¬able_traits(db, &original), edition, display_target) { - desc.push_str("\n___\n"); + desc.push_str("\n---\n"); desc.push_str(&extra); }; desc.into() @@ -1094,7 +1094,7 @@ fn closure_ty( |_| None, |_| None, ) { - format_to!(markup, "\n___\n{layout}"); + format_to!(markup, "\n---\n{layout}"); } format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index c5480217a91e2..187fd1222e89b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -357,7 +357,7 @@ fn main() { ```rust impl Fn(i32) -> i32 ``` - ___ + --- size = 8, align = 8, niches = 1 ## Captures @@ -380,7 +380,7 @@ fn main() { ```rust impl Fn(i32) -> i32 ``` - ___ + --- size = 0, align = 1 ## Captures @@ -414,7 +414,7 @@ fn main() { ```rust impl FnOnce() ``` - ___ + --- size = 16 (0x10), align = 8, niches = 1 ## Captures @@ -443,7 +443,7 @@ fn main() { ```rust impl FnMut() ``` - ___ + --- size = 8, align = 8, niches = 1 ## Captures @@ -468,7 +468,7 @@ fn main() { ```rust impl FnOnce() -> S2 ``` - ___ + --- size = 8, align = 8, niches = 1 Coerced to: &impl FnOnce() -> S2 @@ -6829,7 +6829,7 @@ fn hover_lint() { ``` arithmetic_overflow ``` - ___ + --- arithmetic operation overflows "#]], @@ -6841,7 +6841,7 @@ fn hover_lint() { ``` arithmetic_overflow ``` - ___ + --- arithmetic operation overflows "#]], @@ -6857,7 +6857,7 @@ fn hover_clippy_lint() { ``` clippy::almost_swapped ``` - ___ + --- Checks for `foo = bar; bar = foo` sequences. "#]], @@ -6869,7 +6869,7 @@ fn hover_clippy_lint() { ``` clippy::almost_swapped ``` - ___ + --- Checks for `foo = bar; bar = foo` sequences. "#]], @@ -8567,7 +8567,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: ` 🦀🦀\A ` "#]], @@ -8583,7 +8583,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: ` 🦀\u{1f980}\\\x41 ` "#]], @@ -8605,7 +8605,7 @@ fsdghs"; ```rust &'static str ``` - ___ + --- value of literal (truncated up to newline): ` 🦀\u{1f980}\\\x41 ` "#]], @@ -8625,7 +8625,7 @@ fn main() { ```rust &'static {unknown} ``` - ___ + --- value of literal: ` 🦀🦀\A ` "#]], @@ -8644,7 +8644,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: ```` `[^`]*` ```` "#]], @@ -8659,7 +8659,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: `` ` `` "#]], @@ -8674,7 +8674,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: ` ` "#]], @@ -8690,7 +8690,7 @@ fn main() { ```rust &'static str ``` - ___ + --- value of literal: ` Hello World ` "#]], @@ -8710,7 +8710,7 @@ fn main() { ```rust &'static [u8; 5] ``` - ___ + --- value of literal: ` [240, 159, 166, 128, 92] ` "#]], @@ -8726,7 +8726,7 @@ fn main() { ```rust &'static [u8; 18] ``` - ___ + --- value of literal: ` [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] ` "#]], @@ -8746,7 +8746,7 @@ fn main() { ```rust u8 ``` - ___ + --- value of literal: ` 0xF0 ` "#]], @@ -8762,7 +8762,7 @@ fn main() { ```rust u8 ``` - ___ + --- value of literal: ` 0x5C ` "#]], @@ -8782,7 +8782,7 @@ fn main() { ```rust char ``` - ___ + --- value of literal: ` A ` "#]], @@ -8798,7 +8798,7 @@ fn main() { ```rust char ``` - ___ + --- value of literal: ` \ ` "#]], @@ -8814,7 +8814,7 @@ fn main() { ```rust char ``` - ___ + --- value of literal: ` 🦀 ` "#]], @@ -8834,7 +8834,7 @@ fn main() { ```rust f64 ``` - ___ + --- value of literal: ` 1 (bits: 0x3FF0000000000000) ` "#]], @@ -8850,7 +8850,7 @@ fn main() { ```rust f16 ``` - ___ + --- value of literal: ` 1 (bits: 0x3C00) ` "#]], @@ -8866,7 +8866,7 @@ fn main() { ```rust f32 ``` - ___ + --- value of literal: ` 1 (bits: 0x3F800000) ` "#]], @@ -8882,7 +8882,7 @@ fn main() { ```rust f128 ``` - ___ + --- value of literal: ` 1 (bits: 0x3FFF0000000000000000000000000000) ` "#]], @@ -8898,7 +8898,7 @@ fn main() { ```rust f64 ``` - ___ + --- value of literal: ` 134000000000000 (bits: 0x42DE77D399980000) ` "#]], @@ -8914,7 +8914,7 @@ fn main() { ```rust f64 ``` - ___ + --- value of literal: ` 1523527134274733600000000 (bits: 0x44F429E9249F629B) ` "#]], @@ -8930,7 +8930,7 @@ fn main() { ```rust f64 ``` - ___ + --- invalid literal: invalid float literal "#]], @@ -8950,7 +8950,7 @@ fn main() { ```rust i32 ``` - ___ + --- value of literal: ` 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) ` "#]], @@ -8966,7 +8966,7 @@ fn main() { ```rust i32 ``` - ___ + --- value of literal: ` 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) ` "#]], @@ -8982,7 +8982,7 @@ fn main() { ```rust i32 ``` - ___ + --- value of literal: ` 306328611 (0x12423423|0b10010010000100011010000100011) ` "#]], @@ -8998,7 +8998,7 @@ fn main() { ```rust i32 ``` - ___ + --- value of literal: ` 255 (0xFF|0b11111111) ` "#]], @@ -9014,7 +9014,7 @@ fn main() { ```rust i32 ``` - ___ + --- value of literal: ` 5349 (0x14E5|0b1010011100101) ` "#]], @@ -9030,7 +9030,7 @@ fn main() { ```rust i32 ``` - ___ + --- invalid literal: number too large to fit in target type "#]], @@ -9186,7 +9186,7 @@ fn main() { ```rust S ``` - ___ + --- Implements notable traits: `Future`, `Iterator`, `Notable`"#]], ); } From 6bc1d4d2aa996918838e2e9e39290756a37b8cc0 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Mon, 4 Aug 2025 14:38:17 +0900 Subject: [PATCH 004/251] remvoe add_attr edit_in_place.rs because it use ted. --- .../src/handlers/convert_bool_to_enum.rs | 37 ++++----- .../src/handlers/convert_closure_to_fn.rs | 1 + .../src/handlers/convert_from_to_tryfrom.rs | 1 + .../src/handlers/extract_function.rs | 1 + .../src/handlers/extract_module.rs | 2 + .../src/handlers/extract_type_alias.rs | 5 +- .../src/handlers/extract_variable.rs | 2 +- .../src/handlers/generate_delegate_methods.rs | 2 + .../src/handlers/generate_delegate_trait.rs | 79 +++++++++++++++---- .../src/handlers/generate_derive.rs | 25 ++++-- .../src/handlers/generate_fn_type_alias.rs | 1 + .../src/handlers/generate_function.rs | 3 +- .../src/handlers/generate_getter_or_setter.rs | 2 + .../ide-assists/src/handlers/generate_impl.rs | 1 + .../ide-assists/src/handlers/generate_new.rs | 1 + .../generate_single_field_struct_from.rs | 10 ++- .../src/handlers/promote_local_to_const.rs | 2 +- .../src/handlers/unmerge_imports.rs | 10 +-- .../crates/ide-assists/src/utils.rs | 26 ++---- .../crates/ide-db/src/imports/insert_use.rs | 2 +- .../crates/syntax/src/ast/edit_in_place.rs | 22 ------ .../crates/syntax/src/ast/make.rs | 38 +++++++-- .../src/ast/syntax_factory/constructors.rs | 27 +++++-- .../crates/syntax/src/syntax_editor.rs | 1 + 24 files changed, 185 insertions(+), 116 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index f73b8c4fd0f19..c208c8bf789a0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -13,12 +13,7 @@ use ide_db::{ use itertools::Itertools; use syntax::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, - ast::{ - self, HasName, - edit::IndentLevel, - edit_in_place::{AttrsOwnerEdit, Indent}, - make, - }, + ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, make}, }; use crate::{ @@ -506,18 +501,6 @@ fn node_to_insert_before(target_node: SyntaxNode) -> SyntaxNode { } fn make_bool_enum(make_pub: bool) -> ast::Enum { - let enum_def = make::enum_( - if make_pub { Some(make::visibility_pub()) } else { None }, - make::name("Bool"), - None, - None, - make::variant_list(vec![ - make::variant(None, make::name("True"), None, None), - make::variant(None, make::name("False"), None, None), - ]), - ) - .clone_for_update(); - let derive_eq = make::attr_outer(make::meta_token_tree( make::ext::ident_path("derive"), make::token_tree( @@ -529,11 +512,19 @@ fn make_bool_enum(make_pub: bool) -> ast::Enum { NodeOrToken::Token(make::tokens::ident("Eq")), ], ), - )) - .clone_for_update(); - enum_def.add_attr(derive_eq); - - enum_def + )); + make::enum_( + [derive_eq], + if make_pub { Some(make::visibility_pub()) } else { None }, + make::name("Bool"), + None, + None, + make::variant_list(vec![ + make::variant(None, make::name("True"), None, None), + make::variant(None, make::name("False"), None, None), + ]), + ) + .clone_for_update() } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 916bb67ebb405..5f526ec899404 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -235,6 +235,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>) Some(make::ret_type(make::ty(&ret_ty))) }; let mut fn_ = make::fn_( + None, None, closure_name_or_default.clone(), closure_type_params, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index f1cc3d90b9c56..7d8b763d8b87b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -96,6 +96,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> } let error_type = ast::AssocItem::TypeAlias(make::ty_alias( + None, "Error", None, None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 890b8dd64126e..d88e3311bd7bf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1641,6 +1641,7 @@ fn format_function( let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun); make::fn_( + None, None, fun_name, generic_params, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index c6a6b97df8245..da91d0ac28097 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -585,6 +585,7 @@ impl Module { if (def_out_sel || !is_item) && use_stmt_not_in_sel { let use_ = make::use_( + None, None, make::use_tree(make::join_paths(use_tree_paths), None, None, false), ); @@ -599,6 +600,7 @@ impl Module { let super_path = make::ext::ident_path("super"); let node_path = make::ext::ident_path(&node_syntax.to_string()); let use_ = make::use_( + None, None, make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index 79f22381952ae..7f93506685e18 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -69,8 +69,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> edit.replace(ty.syntax(), new_ty.syntax()); // Insert new alias - let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None))) - .clone_for_update(); + let ty_alias = + make::ty_alias(None, "Type", generic_params, None, None, Some((ty, None))) + .clone_for_update(); if let Some(cap) = ctx.config.snippet_cap && let Some(name) = ty_alias.name() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index c9c1969b9e023..bd88e8b09ced0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -200,7 +200,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } ExtractionKind::Constant => { let ast_ty = make.ty(&ty_string); - ast::Item::Const(make.item_const(None, pat_name, ast_ty, initializer)) + ast::Item::Const(make.item_const(None, None, pat_name, ast_ty, initializer)) .into() } ExtractionKind::Static => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 2c81e2883a34a..d8a2e038d33c2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -155,6 +155,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let ret_type = method_source.ret_type(); let f = make::fn_( + None, vis, fn_name, type_params, @@ -195,6 +196,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let assoc_item_list = make::assoc_item_list(Some(vec![item])); let impl_def = make::impl_( + None, ty_params, ty_args, make::ty_path(make::ext::ident_path(name)), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index e96250f3c50a5..e87dde5b8e427 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -20,7 +20,6 @@ use syntax::{ HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path, WherePred, edit::{self, AstNodeEdit}, - edit_in_place::AttrsOwnerEdit, make, }, ted::{self, Position}, @@ -266,6 +265,7 @@ fn generate_impl( let bound_params = bound_def.generic_param_list(); let delegate = make::impl_trait( + None, delegee.is_unsafe(db), bound_params.clone(), bound_params.map(|params| params.to_generic_args()), @@ -379,6 +379,7 @@ fn generate_impl( let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?; // 3) Generate delegate trait impl let delegate = make::impl_trait( + None, trait_.is_unsafe(db), trait_gen_params, trait_gen_args, @@ -652,8 +653,7 @@ fn process_assoc_item( qual_path_ty: ast::Path, base_name: &str, ) -> Option { - let attrs = item.attrs(); - let assoc = match item { + match item { AssocItem::Const(c) => const_assoc_item(c, qual_path_ty), AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name), AssocItem::MacroCall(_) => { @@ -662,18 +662,7 @@ fn process_assoc_item( None } AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty), - }; - if let Some(assoc) = &assoc { - attrs.for_each(|attr| { - assoc.add_attr(attr.clone()); - // fix indentations - if let Some(tok) = attr.syntax().next_sibling_or_token() { - let pos = Position::after(tok); - ted::insert(pos, make::tokens::whitespace(" ")); - } - }) } - assoc } fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option { @@ -687,6 +676,7 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap()); let qualified_path = qualified_path(qual_path_ty, path_expr_segment); let inner = make::item_const( + item.attrs(), item.visibility(), item.name()?, item.ty()?, @@ -755,6 +745,7 @@ fn func_assoc_item( let body = make::block_expr(vec![], Some(call.into())).clone_for_update(); let func = make::fn_( + item.attrs(), item.visibility(), item.name()?, item.generic_param_list(), @@ -779,13 +770,14 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option::t; + + #[cfg(not(test))] + type t = ::t; +} +"#, + ); + } + #[test] fn assoc_items_attributes_mutably_cloned() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs index 73a69c82fbcdd..06fef4af22382 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs @@ -1,6 +1,8 @@ use syntax::{ + SyntaxKind::{ATTR, COMMENT, WHITESPACE}, T, - ast::{self, AstNode, HasAttrs, edit_in_place::AttrsOwnerEdit, make}, + ast::{self, AstNode, HasAttrs, edit::IndentLevel, make}, + syntax_editor::{Element, Position}, }; use crate::{AssistContext, AssistId, Assists}; @@ -48,8 +50,20 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt )) .clone_for_update(); - let nominal = edit.make_mut(nominal); - nominal.add_attr(derive.clone()); + let mut editor = edit.make_editor(nominal.syntax()); + let indent = IndentLevel::from_node(nominal.syntax()); + let after_attrs_and_comments = nominal + .syntax() + .children_with_tokens() + .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) + .map_or(Position::first_child_of(nominal.syntax()), Position::before); + editor.insert_all( + after_attrs_and_comments, + vec![ + derive.syntax().syntax_element(), + make::tokens::whitespace(&format!("\n{indent}")).syntax_element(), + ], + ); let delimiter = derive .meta() @@ -58,8 +72,9 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt .expect("failed to get token tree out of Meta") .r_paren_token() .expect("make::attr_outer was expected to have a R_PAREN"); - - edit.add_tabstop_before_token(cap, delimiter); + let tabstop_before = edit.make_tabstop_before(cap); + editor.add_annotation(delimiter, tabstop_before); + edit.add_file_edits(ctx.vfs_file_id(), editor); } Some(_) => { // Just move the cursor. diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs index 3c327a63b0f0b..0b7eca2290f62 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -94,6 +94,7 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) // Insert new alias let ty_alias = make::ty_alias( + None, &alias_name, generic_params, None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 613b32fcc1653..efdb20c1e9317 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -189,7 +189,7 @@ fn add_func_to_accumulator( ))); // FIXME: adt may have generic params. - let impl_ = make::impl_(None, None, name, None, None).clone_for_update(); + let impl_ = make::impl_(None, None, None, name, None, None).clone_for_update(); func.indent(IndentLevel(1)); impl_.get_or_create_assoc_item_list().add_item(func.into()); @@ -365,6 +365,7 @@ impl FunctionBuilder { Visibility::Pub => Some(make::visibility_pub()), }; let fn_def = make::fn_( + None, visibility, self.fn_name, self.generic_param_list, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 807b9194b2df7..e42d0ed1b00b0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -263,6 +263,7 @@ fn generate_getter_from_info( let body = make::block_expr([], Some(body)); make::fn_( + None, strukt.visibility(), fn_name, None, @@ -299,6 +300,7 @@ fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldI // Make the setter fn make::fn_( + None, strukt.visibility(), fn_name, None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index b38ee6f7dce8e..77eb8efc6f6af 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -174,6 +174,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> let make_impl_ = |body| { make::impl_trait( + None, trait_.unsafe_token().is_some(), None, trait_gen_args.clone(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index 351f134612f00..ac4a54a89ef1f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -134,6 +134,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self"))); let fn_ = make::fn_( + None, strukt.visibility(), make::name("new"), None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 4e95ceb2e853e..6076d5cb5cedf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -6,13 +6,12 @@ use ide_db::{ }; use syntax::{ TokenText, - ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent}, + ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent}, }; use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::add_cfg_attrs_to, }; // Assist: generate_single_field_struct_from @@ -89,6 +88,7 @@ pub(crate) fn generate_single_field_struct_from( let body = make::block_expr([], Some(constructor)); let fn_ = make::fn_( + None, None, make::name("from"), None, @@ -110,8 +110,12 @@ pub(crate) fn generate_single_field_struct_from( .clone_for_update(); fn_.indent(1.into()); + let cfg_attrs = strukt + .attrs() + .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); let impl_ = make::impl_trait( + cfg_attrs, false, None, trait_gen_args, @@ -128,8 +132,6 @@ pub(crate) fn generate_single_field_struct_from( impl_.get_or_create_assoc_item_list().add_item(fn_.into()); - add_cfg_attrs_to(&strukt, &impl_); - impl_.reindent_to(indent); builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}")); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs index 603be4d66733d..547d3686e3909 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs @@ -88,7 +88,7 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>) } } - let item = make.item_const(None, make.name(&name), make.ty(&ty), initializer); + let item = make.item_const(None, None, make.name(&name), make.ty(&ty), initializer); if let Some((cap, name)) = ctx.config.snippet_cap.zip(item.name()) { let tabstop = edit.make_tabstop_before(cap); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs index c066f41ca47b7..accb5c28d6ed3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs @@ -1,9 +1,6 @@ use syntax::{ AstNode, SyntaxKind, - ast::{ - self, HasAttrs, HasVisibility, edit::IndentLevel, edit_in_place::AttrsOwnerEdit, make, - syntax_factory::SyntaxFactory, - }, + ast::{self, HasAttrs, HasVisibility, edit::IndentLevel, make, syntax_factory::SyntaxFactory}, syntax_editor::{Element, Position, Removable}, }; @@ -46,13 +43,10 @@ pub(crate) fn unmerge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt acc.add(AssistId::refactor_rewrite("unmerge_imports"), label, target, |builder| { let make = SyntaxFactory::with_mappings(); let new_use = make.use_( + use_.attrs(), use_.visibility(), make.use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()), ); - // Add any attributes that are present on the use tree - use_.attrs().for_each(|attr| { - new_use.add_attr(attr.clone_for_update()); - }); let mut editor = builder.make_editor(use_.syntax()); // Remove the use tree from the current use item diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 91aac9cf7b608..20e0302b57d70 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -736,8 +736,11 @@ fn generate_impl_inner( generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update()); let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text())); - let impl_ = match trait_ { + let cfg_attrs = + adt.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); + match trait_ { Some(trait_) => make::impl_trait( + cfg_attrs, is_unsafe, None, None, @@ -750,26 +753,9 @@ fn generate_impl_inner( adt.where_clause(), body, ), - None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), body), - } - .clone_for_update(); - - // Copy any cfg attrs from the original adt - add_cfg_attrs_to(adt, &impl_); - - impl_ -} - -pub(crate) fn add_cfg_attrs_to(from: &T, to: &U) -where - T: HasAttrs, - U: AttrsOwnerEdit, -{ - let cfg_attrs = - from.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); - for attr in cfg_attrs { - to.add_attr(attr.clone_for_update()); + None => make::impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body), } + .clone_for_update() } pub(crate) fn add_method_to_adt( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index 08cd8f28608ca..b174adfd7e448 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -194,7 +194,7 @@ fn insert_use_with_alias_option( use_tree = use_tree.clone_for_update(); use_tree.wrap_in_tree_list(); } - let use_item = make::use_(None, use_tree).clone_for_update(); + let use_item = make::use_(None, None, use_tree).clone_for_update(); for attr in scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update()) { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index b50ce6442432d..160f000387b3d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -273,28 +273,6 @@ pub trait AttrsOwnerEdit: ast::HasAttrs { } } } - - fn add_attr(&self, attr: ast::Attr) { - add_attr(self.syntax(), attr); - - fn add_attr(node: &SyntaxNode, attr: ast::Attr) { - let indent = IndentLevel::from_node(node); - attr.reindent_to(indent); - - let after_attrs_and_comments = node - .children_with_tokens() - .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) - .map_or(Position::first_child_of(node), Position::before); - - ted::insert_all( - after_attrs_and_comments, - vec![ - attr.syntax().clone().into(), - make::tokens::whitespace(&format!("\n{indent}")).into(), - ], - ) - } - } } impl AttrsOwnerEdit for T {} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index daeb79cf081dc..c5ca609760187 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -190,6 +190,7 @@ fn ty_from_text(text: &str) -> ast::Type { } pub fn ty_alias( + attrs: impl IntoIterator, ident: &str, generic_param_list: Option, type_param_bounds: Option, @@ -200,6 +201,7 @@ pub fn ty_alias( let assignment_where = assignment_where.flatten(); quote! { TypeAlias { + #(#attrs "\n")* [type] " " Name { [IDENT ident] } #generic_param_list @@ -277,12 +279,16 @@ fn merge_where_clause( } pub fn impl_( + attrs: impl IntoIterator, generic_params: Option, generic_args: Option, path_type: ast::Type, where_clause: Option, body: Option, ) -> ast::Impl { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); + let gen_args = generic_args.map_or_else(String::new, |it| it.to_string()); let gen_params = generic_params.map_or_else(String::new, |it| it.to_string()); @@ -295,10 +301,11 @@ pub fn impl_( }; let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string()); - ast_from_text(&format!("impl{gen_params} {path_type}{gen_args}{where_clause}{body}")) + ast_from_text(&format!("{attrs}impl{gen_params} {path_type}{gen_args}{where_clause}{body}")) } pub fn impl_trait( + attrs: impl IntoIterator, is_unsafe: bool, trait_gen_params: Option, trait_gen_args: Option, @@ -311,6 +318,8 @@ pub fn impl_trait( ty_where_clause: Option, body: Option, ) -> ast::Impl { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); let is_unsafe = if is_unsafe { "unsafe " } else { "" }; let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default(); @@ -334,7 +343,7 @@ pub fn impl_trait( let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string()); ast_from_text(&format!( - "{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}" + "{attrs}{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}" )) } @@ -452,12 +461,18 @@ pub fn use_tree_list(use_trees: impl IntoIterator) -> ast:: ast_from_text(&format!("use {{{use_trees}}};")) } -pub fn use_(visibility: Option, use_tree: ast::UseTree) -> ast::Use { +pub fn use_( + attrs: impl IntoIterator, + visibility: Option, + use_tree: ast::UseTree, +) -> ast::Use { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); let visibility = match visibility { None => String::new(), Some(it) => format!("{it} "), }; - ast_from_text(&format!("{visibility}use {use_tree};")) + ast_from_text(&format!("{attrs}{visibility}use {use_tree};")) } pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr { @@ -946,16 +961,19 @@ pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt { } pub fn item_const( + attrs: impl IntoIterator, visibility: Option, name: ast::Name, ty: ast::Type, expr: ast::Expr, ) -> ast::Const { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); let visibility = match visibility { None => String::new(), Some(it) => format!("{it} "), }; - ast_from_text(&format!("{visibility}const {name}: {ty} = {expr};")) + ast_from_text(&format!("{attrs}{visibility}const {name}: {ty} = {expr};")) } pub fn item_static( @@ -1162,6 +1180,7 @@ pub fn variant( } pub fn fn_( + attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, @@ -1174,6 +1193,8 @@ pub fn fn_( is_unsafe: bool, is_gen: bool, ) -> ast::Fn { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); let type_params = match type_params { Some(type_params) => format!("{type_params}"), None => "".into(), @@ -1197,7 +1218,7 @@ pub fn fn_( let gen_literal = if is_gen { "gen " } else { "" }; ast_from_text(&format!( - "{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}", + "{attrs}{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}", )) } pub fn struct_( @@ -1217,12 +1238,15 @@ pub fn struct_( } pub fn enum_( + attrs: impl IntoIterator, visibility: Option, enum_name: ast::Name, generic_param_list: Option, where_clause: Option, variant_list: ast::VariantList, ) -> ast::Enum { + let attrs = + attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr)); let visibility = match visibility { None => String::new(), Some(it) => format!("{it} "), @@ -1232,7 +1256,7 @@ pub fn enum_( let where_clause = where_clause.map(|it| format!(" {it}")).unwrap_or_default(); ast_from_text(&format!( - "{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}" + "{attrs}{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}" )) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 738a26fed5d82..8bf27f967482b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -2,8 +2,8 @@ use crate::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, ast::{ - self, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, - HasVisibility, RangeItem, make, + self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, + HasTypeBounds, HasVisibility, RangeItem, make, }, syntax_editor::SyntaxMappingBuilder, }; @@ -107,8 +107,13 @@ impl SyntaxFactory { ast } - pub fn use_(&self, visibility: Option, use_tree: ast::UseTree) -> ast::Use { - make::use_(visibility, use_tree).clone_for_update() + pub fn use_( + &self, + attrs: impl IntoIterator, + visibility: Option, + use_tree: ast::UseTree, + ) -> ast::Use { + make::use_(attrs, visibility, use_tree).clone_for_update() } pub fn use_tree( @@ -840,16 +845,20 @@ impl SyntaxFactory { pub fn item_const( &self, + attrs: impl IntoIterator, visibility: Option, name: ast::Name, ty: ast::Type, expr: ast::Expr, ) -> ast::Const { - let ast = make::item_const(visibility.clone(), name.clone(), ty.clone(), expr.clone()) - .clone_for_update(); + let (attrs, attrs_input) = iterator_input(attrs); + let ast = + make::item_const(attrs, visibility.clone(), name.clone(), ty.clone(), expr.clone()) + .clone_for_update(); if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone())); if let Some(visibility) = visibility { builder.map_node( visibility.syntax().clone(), @@ -1067,6 +1076,7 @@ impl SyntaxFactory { pub fn item_enum( &self, + attrs: impl IntoIterator, visibility: Option, name: ast::Name, generic_param_list: Option, @@ -1074,6 +1084,7 @@ impl SyntaxFactory { variant_list: ast::VariantList, ) -> ast::Enum { let ast = make::enum_( + attrs, visibility.clone(), name.clone(), generic_param_list.clone(), @@ -1182,6 +1193,7 @@ impl SyntaxFactory { pub fn fn_( &self, + attrs: impl IntoIterator, visibility: Option, fn_name: ast::Name, type_params: Option, @@ -1194,7 +1206,9 @@ impl SyntaxFactory { is_unsafe: bool, is_gen: bool, ) -> ast::Fn { + let (attrs, input) = iterator_input(attrs); let ast = make::fn_( + attrs, visibility.clone(), fn_name.clone(), type_params.clone(), @@ -1210,6 +1224,7 @@ impl SyntaxFactory { if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.attrs().map(|attr| attr.syntax().clone())); if let Some(visibility) = visibility { builder.map_node( diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 18f5015e9eabd..0b358878fcf23 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -618,6 +618,7 @@ mod tests { #[test] fn test_replace_token_in_parent() { let parent_fn = make::fn_( + None, None, make::name("it"), None, From 0ef8c6f2add02bf66108f3b80c204ad2b2a2c7ff Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 4 Aug 2025 17:41:00 +0300 Subject: [PATCH 005/251] Correctly goto `From` impl when on `into()` even when the call is inside a macro Descend into macros first. --- .../crates/ide/src/goto_definition.rs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 84e41277390ff..f768d4b68f469 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -83,14 +83,14 @@ pub(crate) fn goto_definition( return Some(RangeInfo::new(original_token.text_range(), navs)); } - if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &original_token) { - return Some(RangeInfo::new(original_token.text_range(), navs)); - } - let navs = sema .descend_into_macros_no_opaque(original_token.clone(), false) .into_iter() .filter_map(|token| { + if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) { + return Some(navs); + } + let parent = token.value.parent()?; let token_file_id = token.file_id; @@ -3275,6 +3275,32 @@ impl From for B { } } +fn f() { + let a = A; + let b: B = a.into$0(); +} + "#, + ); + } + + #[test] + fn into_call_to_from_definition_within_macro() { + check( + r#" +//- proc_macros: identity +//- minicore: from +struct A; + +struct B; + +impl From for B { + fn from(value: A) -> Self { + //^^^^ + B + } +} + +#[proc_macros::identity] fn f() { let a = A; let b: B = a.into$0(); From 0e44b50dbef4c8ac2520576543fcbfff7d6d99e6 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 4 Aug 2025 22:44:55 +0800 Subject: [PATCH 006/251] Add if..else completions in LetStmt and ArgList Example === ```rust let x = $0; ``` Old completions: ```rust let x = if $1 { $0 }; ``` This PR current completions: ```rust let x = if $1 { $2 } else { $0 }; ``` --- .../ide-completion/src/completions/expr.rs | 9 +- .../ide-completion/src/completions/keyword.rs | 116 ++++++++++++++++++ .../crates/ide-completion/src/context.rs | 1 + .../ide-completion/src/context/analysis.rs | 2 + 4 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 2133291b1de15..a84927f6e2c0f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -61,6 +61,7 @@ pub(crate) fn complete_expr_path( after_if_expr, in_condition, incomplete_let, + in_value, ref ref_expr_parent, after_amp, ref is_func_update, @@ -361,10 +362,16 @@ pub(crate) fn complete_expr_path( add_keyword("loop", "loop {\n $0\n}"); if in_match_guard { add_keyword("if", "if $0"); + } else if in_value { + add_keyword("if", "if $1 {\n $2\n} else {\n $0\n}"); } else { add_keyword("if", "if $1 {\n $0\n}"); } - add_keyword("if let", "if let $1 = $2 {\n $0\n}"); + if in_value { + add_keyword("if let", "if let $1 = $2 {\n $3\n} else {\n $0\n}"); + } else { + add_keyword("if let", "if let $1 = $2 {\n $0\n}"); + } add_keyword("for", "for $1 in $2 {\n $0\n}"); add_keyword("true", "true"); add_keyword("false", "false"); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 64bb1fce6ba02..aea4e119f2076 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -238,6 +238,8 @@ fn main() { r#" fn main() { let x = if $1 { + $2 +} else { $0 }; let y = 92; @@ -335,6 +337,120 @@ fn main() { ) } + #[test] + fn if_completion_in_parameter() { + check_edit( + "if", + r" +fn main() { + foo($0) +} +", + r" +fn main() { + foo(if $1 { + $2 +} else { + $0 +}) +} +", + ); + + check_edit( + "if", + r" +fn main() { + foo($0, 2) +} +", + r" +fn main() { + foo(if $1 { + $2 +} else { + $0 +}, 2) +} +", + ); + + check_edit( + "if", + r" +fn main() { + foo(2, $0) +} +", + r" +fn main() { + foo(2, if $1 { + $2 +} else { + $0 +}) +} +", + ); + + check_edit( + "if let", + r" +fn main() { + foo(2, $0) +} +", + r" +fn main() { + foo(2, if let $1 = $2 { + $3 +} else { + $0 +}) +} +", + ); + } + + #[test] + fn if_completion_in_let_statement() { + check_edit( + "if", + r" +fn main() { + let x = $0; +} +", + r" +fn main() { + let x = if $1 { + $2 +} else { + $0 +}; +} +", + ); + + check_edit( + "if let", + r" +fn main() { + let x = $0; +} +", + r" +fn main() { + let x = if let $1 = $2 { + $3 +} else { + $0 +}; +} +", + ); + } + #[test] fn completes_let_in_block() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index cfd7f80d40b30..bb6b13b8fb96b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -147,6 +147,7 @@ pub(crate) struct PathExprCtx<'db> { /// Whether this expression is the direct condition of an if or while expression pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, + pub(crate) in_value: bool, pub(crate) ref_expr_parent: Option, pub(crate) after_amp: bool, /// The surrounding RecordExpression we are completing a functional update diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index ea5fb39338b2e..59077237e7534 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1245,6 +1245,7 @@ fn classify_name_ref<'db>( .parent() .and_then(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()); + let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) { @@ -1265,6 +1266,7 @@ fn classify_name_ref<'db>( is_func_update, innermost_ret_ty, self_param, + in_value, incomplete_let, impl_, in_match_guard, From c91f9f094025d84f9b2e123b17309c2242607247 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Tue, 5 Aug 2025 00:36:14 +0900 Subject: [PATCH 007/251] remove `ted` from replace_named_generic_with_impl.rs --- .../replace_named_generic_with_impl.rs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index 3cd7b58f4ddd4..df7057835c346 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -7,11 +7,8 @@ use ide_db::{ }; use syntax::{ AstNode, - ast::{ - self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType, - make::impl_trait_type, - }, - match_ast, ted, + ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType, make}, + match_ast, }; use crate::{AssistContext, AssistId, Assists}; @@ -74,26 +71,31 @@ pub(crate) fn replace_named_generic_with_impl( "Replace named generic with impl trait", target, |edit| { - let type_param = edit.make_mut(type_param); - let fn_ = edit.make_mut(fn_); - - let path_types_to_replace = path_types_to_replace - .into_iter() - .map(|param| edit.make_mut(param)) - .collect::>(); + let mut editor = edit.make_editor(type_param.syntax()); // remove trait from generic param list if let Some(generic_params) = fn_.generic_param_list() { - generic_params.remove_generic_param(ast::GenericParam::TypeParam(type_param)); - if generic_params.generic_params().count() == 0 { - ted::remove(generic_params.syntax()); + let params: Vec = generic_params + .clone() + .generic_params() + .filter(|it| it.syntax() != type_param.syntax()) + .collect(); + if params.is_empty() { + editor.delete(generic_params.syntax()); + } else { + let new_generic_param_list = make::generic_param_list(params); + editor.replace( + generic_params.syntax(), + new_generic_param_list.syntax().clone_for_update(), + ); } } - let new_bounds = impl_trait_type(type_bound_list); + let new_bounds = make::impl_trait_type(type_bound_list); for path_type in path_types_to_replace.iter().rev() { - ted::replace(path_type.syntax(), new_bounds.clone_for_update().syntax()); + editor.replace(path_type.syntax(), new_bounds.clone_for_update().syntax()); } + edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) } From 67d099bf2f64715e37ee7efe1cf21c14f0d93316 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Tue, 5 Aug 2025 01:16:39 +0900 Subject: [PATCH 008/251] Migrate `expand_glob_import` assist to use `SyntaxEditor` --- .../ide-assists/src/handlers/expand_glob_import.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index 66552dd65f567..4b6d0b37854c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -9,7 +9,6 @@ use stdx::never; use syntax::{ AstNode, Direction, SyntaxNode, SyntaxToken, T, ast::{self, Use, UseTree, VisibilityKind, make}, - ted, }; use crate::{ @@ -165,8 +164,6 @@ fn build_expanded_import( let filtered_defs = if reexport_public_items { refs_in_target } else { refs_in_target.used_refs(ctx) }; - let use_tree = builder.make_mut(use_tree); - let names_to_import = find_names_to_import(filtered_defs, imported_defs); let expanded = make::use_tree_list(names_to_import.iter().map(|n| { let path = make::ext::ident_path( @@ -176,22 +173,24 @@ fn build_expanded_import( })) .clone_for_update(); + let mut editor = builder.make_editor(use_tree.syntax()); match use_tree.star_token() { Some(star) => { let needs_braces = use_tree.path().is_some() && names_to_import.len() != 1; if needs_braces { - ted::replace(star, expanded.syntax()) + editor.replace(star, expanded.syntax()) } else { let without_braces = expanded .syntax() .children_with_tokens() .filter(|child| !matches!(child.kind(), T!['{'] | T!['}'])) .collect(); - ted::replace_with_many(star, without_braces) + editor.replace_with_many(star, without_braces) } } None => never!(), } + builder.add_file_edits(ctx.vfs_file_id(), editor); } fn get_export_visibility_kind(use_item: &Use) -> VisibilityKind { From 069c953bdf94e9a75662157953b44e8ef7e215a2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 5 Aug 2025 00:10:21 +0300 Subject: [PATCH 009/251] Allow renaming when there are multiple definitions (due to macros) even when some cannot rename --- .../rust-analyzer/crates/ide/src/rename.rs | 124 ++++++++++-------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index aea4ae0fd9702..8922a8eb48580 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -27,6 +27,27 @@ pub use ide_db::rename::RenameError; type RenameResult = Result; +/// This is similar to `collect::, _>>`, but unlike it, it succeeds if there is *any* `Ok` item. +fn ok_if_any(iter: impl Iterator>) -> Result, E> { + let mut err = None; + let oks = iter + .filter_map(|item| match item { + Ok(it) => Some(it), + Err(it) => { + err = Some(it); + None + } + }) + .collect::>(); + if !oks.is_empty() { + Ok(oks) + } else if let Some(err) = err { + Err(err) + } else { + Ok(Vec::new()) + } +} + /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is /// being targeted for a rename. pub(crate) fn prepare_rename( @@ -95,58 +116,57 @@ pub(crate) fn rename( alias_fallback(syntax, position, &new_name.display(db, edition).to_string()); let ops: RenameResult> = match alias_fallback { - Some(_) => defs - // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can - // properly find "direct" usages/references. - .map(|(.., def, new_name, _)| { - match kind { - IdentifierKind::Ident => (), - IdentifierKind::Lifetime => { - bail!("Cannot alias reference to a lifetime identifier") - } - IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), - IdentifierKind::LowercaseSelf => { - bail!("Cannot rename alias reference to `self`") - } - }; - let mut usages = def.usages(&sema).all(); - - // FIXME: hack - removes the usage that triggered this rename operation. - match usages.references.get_mut(&file_id).and_then(|refs| { - refs.iter() - .position(|ref_| ref_.range.contains_inclusive(position.offset)) - .map(|idx| refs.remove(idx)) - }) { - Some(_) => (), - None => never!(), - }; - - let mut source_change = SourceChange::default(); - source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| { - ( - position.file_id, - source_edit_from_references(db, refs, def, &new_name, edition), - ) - })); - - Ok(source_change) - }) - .collect(), - None => defs - .map(|(.., def, new_name, rename_def)| { - if let Definition::Local(local) = def { - if let Some(self_param) = local.as_self_param(sema.db) { - cov_mark::hit!(rename_self_to_param); - return rename_self_to_param(&sema, local, self_param, &new_name, kind); - } - if kind == IdentifierKind::LowercaseSelf { - cov_mark::hit!(rename_to_self); - return rename_to_self(&sema, local); - } + Some(_) => ok_if_any( + defs + // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can + // properly find "direct" usages/references. + .map(|(.., def, new_name, _)| { + match kind { + IdentifierKind::Ident => (), + IdentifierKind::Lifetime => { + bail!("Cannot alias reference to a lifetime identifier") + } + IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), + IdentifierKind::LowercaseSelf => { + bail!("Cannot rename alias reference to `self`") + } + }; + let mut usages = def.usages(&sema).all(); + + // FIXME: hack - removes the usage that triggered this rename operation. + match usages.references.get_mut(&file_id).and_then(|refs| { + refs.iter() + .position(|ref_| ref_.range.contains_inclusive(position.offset)) + .map(|idx| refs.remove(idx)) + }) { + Some(_) => (), + None => never!(), + }; + + let mut source_change = SourceChange::default(); + source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| { + ( + position.file_id, + source_edit_from_references(db, refs, def, &new_name, edition), + ) + })); + + Ok(source_change) + }), + ), + None => ok_if_any(defs.map(|(.., def, new_name, rename_def)| { + if let Definition::Local(local) = def { + if let Some(self_param) = local.as_self_param(sema.db) { + cov_mark::hit!(rename_self_to_param); + return rename_self_to_param(&sema, local, self_param, &new_name, kind); } - def.rename(&sema, new_name.as_str(), rename_def) - }) - .collect(), + if kind == IdentifierKind::LowercaseSelf { + cov_mark::hit!(rename_to_self); + return rename_to_self(&sema, local); + } + } + def.rename(&sema, new_name.as_str(), rename_def) + })), }; ops?.into_iter() @@ -320,7 +340,7 @@ fn find_definitions( }) }); - let res: RenameResult> = symbols.filter_map(Result::transpose).collect(); + let res: RenameResult> = ok_if_any(symbols.filter_map(Result::transpose)); match res { Ok(v) => { // remove duplicates, comparing `Definition`s From d064aca3c4bb3a5b0e14b267bd859864257f2e6e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 5 Aug 2025 01:04:21 +0300 Subject: [PATCH 010/251] Do not remove the original token when descending into derives This caused rename to remove both, because it couldn't rename the derive-expanded one. I spent some time trying to create a test for this, before giving up. But I checked manually that this works. --- .../rust-analyzer/crates/hir/src/semantics.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index d207305b4c61f..05f06f97fdc26 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1241,29 +1241,27 @@ impl<'db> SemanticsImpl<'db> { adt, )) })?; - let mut res = None; for (_, derive_attr, derives) in derives { // as there may be multiple derives registering the same helper // name, we gotta make sure to call this for all of them! // FIXME: We need to call `f` for all of them as well though! - res = res.or(process_expansion_for_token( - ctx, - &mut stack, - derive_attr, - )); + process_expansion_for_token(ctx, &mut stack, derive_attr); for derive in derives.into_iter().flatten() { - res = res - .or(process_expansion_for_token(ctx, &mut stack, derive)); + process_expansion_for_token(ctx, &mut stack, derive); } } // remove all tokens that are within the derives expansion filter_duplicates(tokens, adt.syntax().text_range()); - Some(res) + Some(()) }); // if we found derives, we can early exit. There is no way we can be in any // macro call at this point given we are not in a token tree - if let Some(res) = res { - return res; + if let Some(()) = res { + // Note: derives do not remap the original token. Furthermore, we want + // the original token to be before the derives in the list, because if they + // upmap to the same token and we deduplicate them (e.g. in rename), we + // want the original token to remain, not the derive. + return None; } } // Then check for token trees, that means we are either in a function-like macro or From a0ca79e2eff61e4aa5d9d31f7d7e008c6587ba5d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 5 Aug 2025 10:45:54 +0200 Subject: [PATCH 011/251] Slim down compile time artifact progress reports --- .../crates/project-model/src/build_dependencies.rs | 8 ++------ .../rust-analyzer/crates/rust-analyzer/src/main_loop.rs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index 5bea74bed7ed2..203173c11be40 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -347,9 +347,7 @@ impl WorkspaceBuildScripts { match message { Message::BuildScriptExecuted(mut message) => { with_output_for(&message.package_id.repr, &mut |name, data| { - progress(format!( - "building compile-time-deps: build script {name} run" - )); + progress(format!("build script {name} run")); let cfgs = { let mut acc = Vec::new(); for cfg in &message.cfgs { @@ -380,9 +378,7 @@ impl WorkspaceBuildScripts { } Message::CompilerArtifact(message) => { with_output_for(&message.package_id.repr, &mut |name, data| { - progress(format!( - "building compile-time-deps: proc-macro {name} built" - )); + progress(format!("proc-macro {name} built")); if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt { data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 61c758d5e86e1..f5932d8cff026 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -812,7 +812,7 @@ impl GlobalState { }; if let Some(state) = state { - self.report_progress("Building build-artifacts", state, msg, None, None); + self.report_progress("Building compile-time-deps", state, msg, None, None); } } Task::LoadProcMacros(progress) => { From b24866e619e83d1dae63ef1c2e16a91cc8e9c260 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 5 Aug 2025 20:54:38 +0800 Subject: [PATCH 012/251] Change prev whitespace to prev trivia --- .../crates/ide-completion/src/context/analysis.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 67fc79e8032c1..6c2edc3849982 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -562,7 +562,7 @@ fn expected_type_and_name<'db>( token: &SyntaxToken, name_like: &ast::NameLike, ) -> (Option>, Option) { - let token = prev_assign_token_at_whitespace(token.clone()); + let token = prev_assign_token_at_trivia(token.clone()); let mut node = match token.parent() { Some(it) => it, None => return (None, None), @@ -1883,8 +1883,8 @@ fn next_non_trivia_sibling(ele: SyntaxElement) -> Option { None } -fn prev_assign_token_at_whitespace(mut token: SyntaxToken) -> SyntaxToken { - while token.kind() == SyntaxKind::WHITESPACE +fn prev_assign_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { + while token.kind().is_trivia() && let Some(prev) = token.prev_token() && let T![=] | T![+=] From 6a20b6d0221e4a311d61ad4f39827d6c30dca48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?vin=C3=ADcius=20x?= Date: Mon, 4 Aug 2025 13:13:07 -0300 Subject: [PATCH 013/251] fix external docs for exported macros add test --- .../rust-analyzer/crates/ide/src/doc_links.rs | 3 ++- .../crates/ide/src/doc_links/tests.rs | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index a5d9a10d2e5fe..d47cc65079384 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -390,7 +390,8 @@ fn get_doc_links( let (mut web_url, mut local_url) = get_doc_base_urls(db, target, target_dir, sysroot); - if let Some(path) = mod_path_of_def(db, target) { + let append_mod = !matches!(def, Definition::Macro(m) if m.is_macro_export(db)); + if append_mod && let Some(path) = mod_path_of_def(db, target) { web_url = join_url(web_url, &path); local_url = join_url(local_url, &path); } diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index 6af156fa668f5..c2f08f8ca2e6b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -414,6 +414,30 @@ fn foo() { ) } +#[test] +fn external_docs_macro_export() { + check_external_docs( + r#" +//- /lib.rs crate:foo +pub mod inner { + #[macro_export] + macro_rules! my_macro { + () => {}; + } +} + +//- /main.rs crate:bar deps:foo +fn main() { + foo::my_m$0acro!(); +} + "#, + Some("/home/user/project"), + Some(expect![[r#"https://docs.rs/foo/*/foo/macro.my_macro.html"#]]), + Some(expect![[r#"file:///home/user/project/doc/foo/macro.my_macro.html"#]]), + Some("/sysroot"), + ); +} + #[test] fn doc_links_items_simple() { check_doc_links( From 0aa105740c1f9341a816e7f34ec94a4855f6158a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 1 Aug 2025 17:37:33 +0800 Subject: [PATCH 014/251] Add remove simple dbg stmt for remove_dbg Remove only contain literals dbg statement ```rust fn foo() { let n = 2; $0dbg!(3); dbg!(2.6); dbg!(1, 2.5); dbg!('x'); dbg!(&n); dbg!(n); // needless comment dbg!("foo");$0 } ``` -> ```rust fn foo() { // needless comment } ``` Old: ```rust fn foo() { 3; 2.6; (1, 2.5); 'x'; &n; n; // needless comment "foo"; } ``` --- .../ide-assists/src/handlers/remove_dbg.rs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 9356d02706c93..414f6746d4404 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -112,6 +112,16 @@ fn compute_dbg_replacement( } } } + // dbg!(2, 'x', &x, x, ...); + exprs if ast::ExprStmt::can_cast(parent.kind()) && exprs.iter().all(pure_expr) => { + let mut replace = vec![parent.clone().into()]; + if let Some(prev_sibling) = parent.prev_sibling_or_token() + && prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE + { + replace.push(prev_sibling); + } + (replace, None) + } // dbg!(expr0) [expr] => { // dbg!(expr, &parent); @@ -163,6 +173,20 @@ fn compute_dbg_replacement( }) } +fn pure_expr(expr: &ast::Expr) -> bool { + match_ast! { + match (expr.syntax()) { + ast::Literal(_) => true, + ast::RefExpr(it) => { + matches!(it.expr(), Some(ast::Expr::PathExpr(p)) + if p.path().and_then(|p| p.as_single_name_ref()).is_some()) + }, + ast::PathExpr(it) => it.path().and_then(|it| it.as_single_name_ref()).is_some(), + _ => false, + } + } +} + fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr { if let ast::Expr::MacroExpr(mac) = &expanded { // Special-case when `expanded` itself is `dbg!()` since we cannot replace the whole tree @@ -231,6 +255,32 @@ mod tests { check("dbg!{$01 + 1}", "1 + 1"); } + #[test] + fn test_remove_simple_dbg_statement() { + check_assist( + remove_dbg, + r#" +fn foo() { + let n = 2; + $0dbg!(3); + dbg!(2.6); + dbg!(1, 2.5); + dbg!('x'); + dbg!(&n); + dbg!(n); + // needless comment + dbg!("foo");$0 +} +"#, + r#" +fn foo() { + let n = 2; + // needless comment +} +"#, + ); + } + #[test] fn test_remove_dbg_not_applicable() { check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}"); From d339009cbfc59f04be15a9ca6c8f2d9ff98aa0f7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 6 Aug 2025 17:30:18 +0200 Subject: [PATCH 015/251] Report the incorrect payload when failing to deserialize lsp messages --- src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs | 4 ++-- .../rust-analyzer/crates/ide/src/inlay_hints/param_name.rs | 6 +++++- src/tools/rust-analyzer/lib/lsp-server/src/msg.rs | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 7a8514c47af95..8c2a2f6f72f5e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -228,9 +228,9 @@ fn hints( chaining::hints(hints, famous_defs, config, display_target, &expr); adjustment::hints(hints, famous_defs, config, display_target, &expr); match expr { - ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, ast::Expr::from(it)), + ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { - param_name::hints(hints, famous_defs, config, ast::Expr::from(it)) + param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)) } ast::Expr::ClosureExpr(it) => { closure_captures::hints(hints, famous_defs, config, it.clone()); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index ec0a4c46c7fec..754707784055a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -7,7 +7,7 @@ use std::iter::zip; use either::Either; -use hir::Semantics; +use hir::{EditionedFileId, Semantics}; use ide_db::{RootDatabase, famous_defs::FamousDefs}; use stdx::to_lower_snake_case; @@ -19,6 +19,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, krate): &FamousDefs<'_, '_>, config: &InlayHintsConfig, + file_id: EditionedFileId, expr: ast::Expr, ) -> Option<()> { if !config.parameter_hints { @@ -39,6 +40,9 @@ pub(super) fn hints( .filter_map(|(p, arg)| { // Only annotate hints for expressions that exist in the original file let range = sema.original_range_opt(arg.syntax())?; + if range.file_id != file_id { + return None; + } let param_name = p.name(sema.db)?; Some((p, param_name, arg, range)) }) diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs index 399d674e41d25..b20337fdbfff0 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs @@ -175,7 +175,7 @@ impl Message { let msg = match serde_json::from_str(&text) { Ok(msg) => msg, Err(e) => { - return Err(invalid_data!("malformed LSP payload: {:?}", e)); + return Err(invalid_data!("malformed LSP payload `{e:?}`: {text:?}")); } }; From 51c6272baee4e60a525959c2fc9b96103ad5de74 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 6 Aug 2025 17:46:39 +0200 Subject: [PATCH 016/251] Fix non-lsp compliant `Response` definition --- src/tools/rust-analyzer/Cargo.lock | 8 ++-- src/tools/rust-analyzer/Cargo.toml | 38 +++++++++---------- .../rust-analyzer/lib/lsp-server/Cargo.toml | 6 +-- .../rust-analyzer/lib/lsp-server/src/msg.rs | 6 +-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5a29379ba4818..80a311a74abe4 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1294,7 +1294,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lsp-server" -version = "0.7.8" +version = "0.7.9" dependencies = [ "anyhow", "crossbeam-channel", @@ -1310,9 +1310,9 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9462c4dc73e17f971ec1f171d44bfffb72e65a130117233388a0ebc7ec5656f9" +checksum = "7d6ada348dbc2703cbe7637b2dda05cff84d3da2819c24abcb305dd613e0ba2e" dependencies = [ "crossbeam-channel", "log", @@ -2007,7 +2007,7 @@ dependencies = [ "intern", "itertools 0.14.0", "load-cargo", - "lsp-server 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lsp-server 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", "memchr", "mimalloc", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index e7cf0212bf2a8..01a13a39f7b40 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -100,7 +100,7 @@ ra-ap-rustc_pattern_analysis = { version = "0.123", default-features = false } # in-tree crates that are published separately and follow semver. See lib/README.md line-index = { version = "0.1.2" } la-arena = { version = "0.3.1" } -lsp-server = { version = "0.7.8" } +lsp-server = { version = "0.7.9" } # non-local crates anyhow = "1.0.98" @@ -125,11 +125,11 @@ memmap2 = "0.9.5" nohash-hasher = "0.2.0" oorandom = "11.1.5" object = { version = "0.36.7", default-features = false, features = [ - "std", - "read_core", - "elf", - "macho", - "pe", + "std", + "read_core", + "elf", + "macho", + "pe", ] } process-wrap = { version = "8.2.1", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" @@ -139,9 +139,9 @@ rowan = "=0.15.15" # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work # on impls without it salsa = { version = "0.23.0", default-features = true, features = [ - "rayon", - "salsa_unstable", - "macros", + "rayon", + "salsa_unstable", + "macros", ] } salsa-macros = "0.23.0" semver = "1.0.26" @@ -151,9 +151,9 @@ serde_json = "1.0.140" rustc-hash = "2.1.1" rustc-literal-escaper = "0.0.4" smallvec = { version = "1.15.1", features = [ - "const_new", - "union", - "const_generics", + "const_new", + "union", + "const_generics", ] } smol_str = "0.3.2" temp-dir = "0.1.16" @@ -161,12 +161,12 @@ text-size = "1.1.1" tracing = "0.1.41" tracing-tree = "0.4.0" tracing-subscriber = { version = "0.3.19", default-features = false, features = [ - "registry", - "fmt", - "local-time", - "std", - "time", - "tracing-log", + "registry", + "fmt", + "local-time", + "std", + "time", + "tracing-log", ] } triomphe = { version = "0.1.14", default-features = false, features = ["std"] } url = "2.5.4" @@ -176,7 +176,7 @@ xshell = "0.2.7" dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } # We need to freeze the version of the crate, as it needs to match with dashmap hashbrown = { version = "0.14.*", features = [ - "inline-more", + "inline-more", ], default-features = false } [workspace.lints.rust] diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml index 1fc1da50a0a03..f56a0de616376 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml +++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lsp-server" -version = "0.7.8" +version = "0.7.9" description = "Generic LSP server scaffold." license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server" @@ -16,9 +16,9 @@ crossbeam-channel.workspace = true [dev-dependencies] lsp-types = "=0.95" ctrlc = "3.4.7" -anyhow.workspace = true +anyhow.workspace = true rustc-hash.workspace = true -toolchain.workspace = true +toolchain.workspace = true [lints] workspace = true diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs index 399d674e41d25..0b8f8da4c7d07 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs @@ -84,9 +84,9 @@ pub struct Response { // request id. We fail deserialization in that case, so we just // make this field mandatory. pub id: RequestId, - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", default)] pub result: Option, - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", default)] pub error: Option, } @@ -94,7 +94,7 @@ pub struct Response { pub struct ResponseError { pub code: i32, pub message: String, - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", default)] pub data: Option, } From 92b8797a0968de124d120a77252b6df4939a1fce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 17:11:37 +0000 Subject: [PATCH 017/251] Bump tmp from 0.2.3 to 0.2.4 in /editors/code Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.3 to 0.2.4. - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.4) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/editors/code/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 534c24be52e8d..1dc11ee4e4b81 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -5588,9 +5588,9 @@ } }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", + "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", "dev": true, "license": "MIT", "engines": { From 95440527af50ed95e1c4f9fcf7b8a5ebf7a992a7 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Sun, 3 Aug 2025 23:32:35 +0900 Subject: [PATCH 018/251] In extract_module.rs, generate ast::Module instead of String --- .../src/handlers/extract_module.rs | 175 +++++++++++------- .../crates/syntax/src/ast/make.rs | 17 ++ 2 files changed, 126 insertions(+), 66 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index da91d0ac28097..e783b8693456c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -1,6 +1,5 @@ -use std::iter; +use std::ops::RangeInclusive; -use either::Either; use hir::{HasSource, ModuleSource}; use ide_db::{ FileId, FxHashMap, FxHashSet, @@ -82,7 +81,15 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti curr_parent_module = ast::Module::cast(mod_syn_opt); } - let mut module = extract_target(&node, ctx.selection_trimmed())?; + let selection_range = ctx.selection_trimmed(); + let (mut module, module_text_range) = if let Some(item) = ast::Item::cast(node.clone()) { + let module = extract_single_target(&item); + (module, node.text_range()) + } else { + let (module, range) = extract_child_target(&node, selection_range)?; + let module_text_range = range.start().text_range().cover(range.end().text_range()); + (module, module_text_range) + }; if module.body_items.is_empty() { return None; } @@ -92,7 +99,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti acc.add( AssistId::refactor_extract("extract_module"), "Extract Module", - module.text_range, + module_text_range, |builder| { //This takes place in three steps: // @@ -110,17 +117,17 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti //for change_visibility and usages for first point mentioned above in the process let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) = - module.get_usages_and_record_fields(ctx); + module.get_usages_and_record_fields(ctx, module_text_range); builder.edit_file(ctx.vfs_file_id()); use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| { builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}")); }); - let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx); + let import_items = module.resolve_imports(curr_parent_module, ctx); module.change_visibility(record_fields); - let module_def = generate_module_def(&impl_parent, &mut module, old_item_indent); + let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string(); let mut usages_to_be_processed_for_cur_file = vec![]; for (file_id, usages) in usages_to_be_processed { @@ -157,15 +164,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}")); } else { - for import_path_text_range in import_paths_to_be_removed { - if module.text_range.intersect(import_path_text_range).is_some() { - module.text_range = module.text_range.cover(import_path_text_range); - } else { - builder.delete(import_path_text_range); + for import_item in import_items { + if !module_text_range.contains_range(import_item) { + builder.delete(import_item); } } - - builder.replace(module.text_range, module_def) + builder.replace(module_text_range, module_def) } }, ) @@ -173,38 +177,50 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti fn generate_module_def( parent_impl: &Option, - module: &mut Module, + module: Module, old_indent: IndentLevel, -) -> String { - let (items_to_be_processed, new_item_indent) = if parent_impl.is_some() { - (Either::Left(module.body_items.iter()), old_indent + 2) +) -> ast::Module { + let Module { name, body_items, use_items } = module; + let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) { + let assoc_items = body_items + .into_iter() + .map(|item| item.syntax().clone()) + .filter_map(ast::AssocItem::cast) + .map(|it| it.indent(IndentLevel(1))) + .collect_vec(); + let assoc_item_list = make::assoc_item_list(Some(assoc_items)); + let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list)); + // Add the import for enum/struct corresponding to given impl block + let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax()); + let mut module_body_items = use_items; + module_body_items.insert(0, use_impl); + module_body_items.push(ast::Item::Impl(impl_)); + module_body_items } else { - (Either::Right(module.use_items.iter().chain(module.body_items.iter())), old_indent + 1) + [use_items, body_items].concat() }; - let mut body = items_to_be_processed - .map(|item| item.indent(IndentLevel(1))) - .map(|item| format!("{new_item_indent}{item}")) - .join("\n\n"); + let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec(); + let module_body = make::item_list(Some(items)); - if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) { - let impl_indent = old_indent + 1; - body = format!("{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}"); + let module_name = make::name(name); + make::mod_(module_name, Some(module_body)).indent(old_indent) +} - // Add the import for enum/struct corresponding to given impl block - module.make_use_stmt_of_node_with_super(self_ty.syntax()); - for item in module.use_items.iter() { - body = format!("{impl_indent}{item}\n\n{body}"); - } - } +fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item { + let super_path = make::ext::ident_path("super"); + let node_path = make::ext::ident_path(&node_syntax.to_string()); + let use_ = make::use_( + None, + None, + make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), + ); - let module_name = module.name; - format!("mod {module_name} {{\n{body}\n{old_indent}}}") + ast::Item::from(use_) } #[derive(Debug)] struct Module { - text_range: TextRange, name: &'static str, /// All items except use items. body_items: Vec, @@ -214,22 +230,37 @@ struct Module { use_items: Vec, } -fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option { +fn extract_single_target(node: &ast::Item) -> Module { + let (body_items, use_items) = if matches!(node, ast::Item::Use(_)) { + (Vec::new(), vec![node.clone()]) + } else { + (vec![node.clone()], Vec::new()) + }; + let name = "modname"; + Module { name, body_items, use_items } +} + +fn extract_child_target( + node: &SyntaxNode, + selection_range: TextRange, +) -> Option<(Module, RangeInclusive)> { let selected_nodes = node .children() .filter(|node| selection_range.contains_range(node.text_range())) - .chain(iter::once(node.clone())); - let (use_items, body_items) = selected_nodes .filter_map(ast::Item::cast) - .partition(|item| matches!(item, ast::Item::Use(..))); - - Some(Module { text_range: selection_range, name: "modname", body_items, use_items }) + .collect_vec(); + let start = selected_nodes.first()?.syntax().clone(); + let end = selected_nodes.last()?.syntax().clone(); + let (use_items, body_items): (Vec, Vec) = + selected_nodes.into_iter().partition(|item| matches!(item, ast::Item::Use(..))); + Some((Module { name: "modname", body_items, use_items }, start..=end)) } impl Module { fn get_usages_and_record_fields( &self, ctx: &AssistContext<'_>, + replace_range: TextRange, ) -> (FxHashMap>, Vec, FxHashMap) { let mut adt_fields = Vec::new(); @@ -247,7 +278,7 @@ impl Module { ast::Adt(it) => { if let Some( nod ) = ctx.sema.to_def(&it) { let node_def = Definition::Adt(nod); - self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx, replace_range,node_def, &mut refs, &mut use_stmts_to_be_inserted); //Enum Fields are not allowed to explicitly specify pub, it is implied match it { @@ -281,30 +312,30 @@ impl Module { ast::TypeAlias(it) => { if let Some( nod ) = ctx.sema.to_def(&it) { let node_def = Definition::TypeAlias(nod); - self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); } }, ast::Const(it) => { if let Some( nod ) = ctx.sema.to_def(&it) { let node_def = Definition::Const(nod); - self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); } }, ast::Static(it) => { if let Some( nod ) = ctx.sema.to_def(&it) { let node_def = Definition::Static(nod); - self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); } }, ast::Fn(it) => { if let Some( nod ) = ctx.sema.to_def(&it) { let node_def = Definition::Function(nod); - self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); } }, ast::Macro(it) => { if let Some(nod) = ctx.sema.to_def(&it) { - self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted); + self.expand_and_group_usages_file_wise(ctx,replace_range, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted); } }, _ => (), @@ -318,6 +349,7 @@ impl Module { fn expand_and_group_usages_file_wise( &self, ctx: &AssistContext<'_>, + replace_range: TextRange, node_def: Definition, refs_in_files: &mut FxHashMap>, use_stmts_to_be_inserted: &mut FxHashMap, @@ -327,7 +359,7 @@ impl Module { syntax::NodeOrToken::Node(node) => node, syntax::NodeOrToken::Token(tok) => tok.parent().unwrap(), // won't panic }; - let out_of_sel = |node: &SyntaxNode| !self.text_range.contains_range(node.text_range()); + let out_of_sel = |node: &SyntaxNode| !replace_range.contains_range(node.text_range()); let mut use_stmts_set = FxHashSet::default(); for (file_id, refs) in node_def.usages(&ctx.sema).all() { @@ -527,7 +559,8 @@ impl Module { // mod -> ust_stmt transversal // true | false -> super import insertion // true | true -> super import insertion - self.make_use_stmt_of_node_with_super(use_node); + let super_use_node = make_use_stmt_of_node_with_super(use_node); + self.use_items.insert(0, super_use_node); } None => {} } @@ -556,7 +589,8 @@ impl Module { use_tree_paths = Some(use_tree_str); } else if def_in_mod && def_out_sel { - self.make_use_stmt_of_node_with_super(use_node); + let super_use_node = make_use_stmt_of_node_with_super(use_node); + self.use_items.insert(0, super_use_node); } } @@ -596,20 +630,6 @@ impl Module { import_path_to_be_removed } - fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item { - let super_path = make::ext::ident_path("super"); - let node_path = make::ext::ident_path(&node_syntax.to_string()); - let use_ = make::use_( - None, - None, - make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), - ); - - let item = ast::Item::from(use_); - self.use_items.insert(0, item.clone()); - item - } - fn process_use_stmt_for_import_resolve( &self, use_stmt: Option, @@ -1424,10 +1444,10 @@ $0fn foo(x: B) {}$0 struct B {} mod modname { - use super::B; - use super::A; + use super::B; + impl A { pub(crate) fn foo(x: B) {} } @@ -1739,4 +1759,27 @@ fn main() { "#, ); } + + #[test] + fn test_miss_select_item() { + check_assist( + extract_module, + r#" +mod foo { + mod $0bar { + fn foo(){}$0 + } +} +"#, + r#" +mod foo { + mod modname { + pub(crate) mod bar { + fn foo(){} + } + } +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index c5ca609760187..9897fd0941570 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -231,6 +231,23 @@ pub fn ty_fn_ptr>( } } +pub fn item_list(body: Option>) -> ast::ItemList { + let is_break_braces = body.is_some(); + let body_newline = if is_break_braces { "\n" } else { "" }; + let body_indent = if is_break_braces { " " } else { "" }; + + let body = match body { + Some(bd) => bd.iter().map(|elem| elem.to_string()).join("\n\n "), + None => String::new(), + }; + ast_from_text(&format!("mod C {{{body_newline}{body_indent}{body}{body_newline}}}")) +} + +pub fn mod_(name: ast::Name, body: Option) -> ast::Module { + let body = body.map_or(";".to_owned(), |body| format!(" {body}")); + ast_from_text(&format!("mod {name}{body}")) +} + pub fn assoc_item_list(body: Option>) -> ast::AssocItemList { let is_break_braces = body.is_some(); let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() }; From 47cc8b75f0148b1c4f6f95571fbfda7b2d8b3e9d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 7 Aug 2025 15:12:26 +0200 Subject: [PATCH 019/251] Enable warning logs by default --- src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ab045e0bf9ff1..7602d379c0df9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -160,9 +160,9 @@ fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { rust_analyzer::tracing::Config { writer, - // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually + // Deliberately enable all `warn` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. - filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()), + filter: env::var("RA_LOG").ok().unwrap_or_else(|| "warn".to_owned()), chalk_filter: env::var("CHALK_DEBUG").ok(), profile_filter: env::var("RA_PROFILE").ok(), json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), From 1a73720b8051a533b402ac67e35f84d405ccb28d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 7 Aug 2025 15:14:22 +0200 Subject: [PATCH 020/251] Disable error log for position clamping, its too noisy due to ease of triggering --- .../crates/rust-analyzer/src/lsp/from_proto.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs index 02757616d4ffd..333826a1790e4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs @@ -40,12 +40,13 @@ pub(crate) fn offset( })?; let col = TextSize::from(line_col.col); let clamped_len = col.min(line_range.len()); - if clamped_len < col { - tracing::error!( - "Position {line_col:?} column exceeds line length {}, clamping it", - u32::from(line_range.len()), - ); - } + // FIXME: The cause for this is likely our request retrying. Commented out as this log is just too chatty and very easy to trigger. + // if clamped_len < col { + // tracing::error!( + // "Position {line_col:?} column exceeds line length {}, clamping it", + // u32::from(line_range.len()), + // ); + // } Ok(line_range.start() + clamped_len) } From 5b9e6f1b75f14d916bc3d43c21e1e845cc049dbf Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 8 Aug 2025 23:48:12 +0800 Subject: [PATCH 021/251] Add write! and writeln! to minicore --- .../crates/test-utils/src/minicore.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 7b719b5dec754..c1f2b08be942c 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -70,6 +70,7 @@ //! tuple: //! unpin: sized //! unsize: sized +//! write: fmt //! todo: panic //! unimplemented: panic //! column: @@ -1769,6 +1770,26 @@ mod macros { } // endregion:panic + // region:write + #[macro_export] + macro_rules! write { + ($dst:expr, $($arg:tt)*) => { + $dst.write_fmt($crate::format_args!($($arg)*)) + }; + } + + #[macro_export] + #[allow_internal_unstable(format_args_nl)] + macro_rules! writeln { + ($dst:expr $(,)?) => { + $crate::write!($dst, "\n") + }; + ($dst:expr, $($arg:tt)*) => { + $dst.write_fmt($crate::format_args_nl!($($arg)*)) + }; + } + // endregion:write + // region:assert #[macro_export] #[rustc_builtin_macro] From bb4fded8a35a961b749846df45f6caf55d98e5d3 Mon Sep 17 00:00:00 2001 From: BenjaminBrienen Date: Fri, 8 Aug 2025 23:46:28 +0200 Subject: [PATCH 022/251] remove duplicate field in Debug --- src/tools/rust-analyzer/crates/project-model/src/workspace.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 5b36e10fd6925..00032bcf1d2e4 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -157,7 +157,6 @@ impl fmt::Debug for ProjectWorkspace { .field("file", &file) .field("cargo_script", &cargo_script.is_some()) .field("n_sysroot_crates", &sysroot.num_packages()) - .field("cargo_script", &cargo_script.is_some()) .field("n_rustc_cfg", &rustc_cfg.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) From e3d99ddcbc010de4942df34e6d5491c4b664152c Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Sat, 9 Aug 2025 14:53:34 +0900 Subject: [PATCH 023/251] fix: generate function by indet token --- .../src/handlers/generate_function.rs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index efdb20c1e9317..88ed6f9ce124d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -316,7 +316,7 @@ impl FunctionBuilder { let current_module = ctx.sema.scope(call.syntax())?.module(); let visibility = calculate_necessary_visibility(current_module, target_module, ctx); - let fn_name = make::name(&name.text()); + let fn_name = make::name(name.ident_token()?.text()); let mut necessary_generic_params = FxHashSet::default(); necessary_generic_params.extend(receiver_ty.generic_params(ctx.db())); let params = fn_args( @@ -3131,4 +3131,32 @@ fn main() { "#, ) } + + #[test] + fn no_generate_method_by_keyword() { + check_assist_not_applicable( + generate_function, + r#" +fn main() { + s.super$0(); +} + "#, + ); + check_assist_not_applicable( + generate_function, + r#" +fn main() { + s.Self$0(); +} + "#, + ); + check_assist_not_applicable( + generate_function, + r#" +fn main() { + s.self$0(); +} + "#, + ); + } } From eb2bbbb9134ae3fc4d043ea12b3546b73cd90efd Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 1 Aug 2025 14:29:21 +0000 Subject: [PATCH 024/251] Implement next trait solver --- src/tools/rust-analyzer/Cargo.lock | 83 +- src/tools/rust-analyzer/Cargo.toml | 11 +- .../crates/hir-def/src/lang_item.rs | 7 +- .../crates/hir-def/src/signatures.rs | 6 +- .../rust-analyzer/crates/hir-ty/Cargo.toml | 10 +- .../crates/hir-ty/src/autoderef.rs | 4 +- .../crates/hir-ty/src/chalk_db.rs | 610 +---- .../crates/hir-ty/src/chalk_ext.rs | 9 +- .../crates/hir-ty/src/consteval/tests.rs | 3 +- .../crates/hir-ty/src/consteval_nextsolver.rs | 256 ++ .../rust-analyzer/crates/hir-ty/src/db.rs | 159 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 2 +- .../crates/hir-ty/src/dyn_compatibility.rs | 41 +- .../hir-ty/src/dyn_compatibility/tests.rs | 25 +- .../crates/hir-ty/src/generics.rs | 17 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 107 +- .../crates/hir-ty/src/infer/closure.rs | 9 +- .../crates/hir-ty/src/infer/coerce.rs | 31 +- .../crates/hir-ty/src/infer/expr.rs | 11 +- .../crates/hir-ty/src/infer/unify.rs | 192 +- .../crates/hir-ty/src/interner.rs | 25 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 364 +-- .../crates/hir-ty/src/layout/adt.rs | 46 +- .../crates/hir-ty/src/layout/tests.rs | 3 + .../rust-analyzer/crates/hir-ty/src/lib.rs | 133 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 49 +- .../crates/hir-ty/src/lower_nextsolver.rs | 1609 ++++++++++++ .../hir-ty/src/lower_nextsolver/path.rs | 1459 +++++++++++ .../crates/hir-ty/src/method_resolution.rs | 135 +- .../crates/hir-ty/src/mir/eval/tests.rs | 5 +- .../crates/hir-ty/src/mir/lower.rs | 4 +- .../crates/hir-ty/src/next_solver.rs | 46 + .../crates/hir-ty/src/next_solver/abi.rs | 68 + .../crates/hir-ty/src/next_solver/consts.rs | 404 +++ .../crates/hir-ty/src/next_solver/def_id.rs | 96 + .../crates/hir-ty/src/next_solver/fold.rs | 129 + .../crates/hir-ty/src/next_solver/fulfill.rs | 229 ++ .../hir-ty/src/next_solver/generic_arg.rs | 525 ++++ .../crates/hir-ty/src/next_solver/generics.rs | 147 ++ .../crates/hir-ty/src/next_solver/infer/at.rs | 333 +++ .../infer/canonical/instantiate.rs | 106 + .../src/next_solver/infer/canonical/mod.rs | 156 ++ .../hir-ty/src/next_solver/infer/context.rs | 316 +++ .../hir-ty/src/next_solver/infer/mod.rs | 1066 ++++++++ .../src/next_solver/infer/opaque_types/mod.rs | 56 + .../next_solver/infer/opaque_types/table.rs | 166 ++ .../infer/region_constraints/mod.rs | 640 +++++ .../next_solver/infer/relate/generalize.rs | 720 ++++++ .../next_solver/infer/relate/higher_ranked.rs | 89 + .../src/next_solver/infer/relate/mod.rs | 13 + .../hir-ty/src/next_solver/infer/resolve.rs | 62 + .../src/next_solver/infer/snapshot/mod.rs | 111 + .../next_solver/infer/snapshot/undo_log.rs | 198 ++ .../hir-ty/src/next_solver/infer/traits.rs | 175 ++ .../src/next_solver/infer/type_variable.rs | 268 ++ .../hir-ty/src/next_solver/infer/unify_key.rs | 176 ++ .../crates/hir-ty/src/next_solver/interner.rs | 2173 +++++++++++++++++ .../crates/hir-ty/src/next_solver/ir_print.rs | 267 ++ .../crates/hir-ty/src/next_solver/mapping.rs | 1368 +++++++++++ .../crates/hir-ty/src/next_solver/opaques.rs | 167 ++ .../hir-ty/src/next_solver/predicate.rs | 894 +++++++ .../crates/hir-ty/src/next_solver/project.rs | 3 + .../next_solver/project/solve_normalize.rs | 264 ++ .../crates/hir-ty/src/next_solver/region.rs | 332 +++ .../crates/hir-ty/src/next_solver/solver.rs | 289 +++ .../crates/hir-ty/src/next_solver/ty.rs | 943 +++++++ .../crates/hir-ty/src/next_solver/util.rs | 1064 ++++++++ .../rust-analyzer/crates/hir-ty/src/tests.rs | 23 +- .../hir-ty/src/tests/closure_captures.rs | 3 +- .../crates/hir-ty/src/tests/coercion.rs | 16 +- .../crates/hir-ty/src/tests/incremental.rs | 20 +- .../crates/hir-ty/src/tests/macros.rs | 24 +- .../hir-ty/src/tests/method_resolution.rs | 34 +- .../crates/hir-ty/src/tests/regression.rs | 37 +- .../crates/hir-ty/src/tests/simple.rs | 4 +- .../crates/hir-ty/src/tests/traits.rs | 100 +- .../rust-analyzer/crates/hir-ty/src/tls.rs | 2 + .../rust-analyzer/crates/hir-ty/src/traits.rs | 252 +- src/tools/rust-analyzer/crates/hir/Cargo.toml | 5 + src/tools/rust-analyzer/crates/hir/src/lib.rs | 172 +- .../handlers/generate_from_impl_for_enum.rs | 24 +- .../generate_single_field_struct_from.rs | 17 +- .../crates/ide-assists/src/lib.rs | 9 +- .../crates/ide-assists/src/tests.rs | 9 +- .../ide-completion/src/completions/dot.rs | 7 +- .../crates/ide-completion/src/lib.rs | 5 +- .../crates/ide-completion/src/tests.rs | 4 +- .../ide-completion/src/tests/flyimport.rs | 39 +- .../ide-completion/src/tests/special.rs | 3 + .../src/handlers/moved_out_of_ref.rs | 4 +- .../crates/ide-diagnostics/src/lib.rs | 12 +- .../crates/ide-diagnostics/src/tests.rs | 3 + .../crates/ide-ssr/src/resolving.rs | 26 +- .../crates/ide/src/doc_links/tests.rs | 7 +- .../crates/ide/src/goto_definition.rs | 4 +- .../crates/ide/src/goto_implementation.rs | 2 +- .../rust-analyzer/crates/ide/src/hover.rs | 5 +- .../crates/ide/src/hover/render.rs | 3 +- .../crates/ide/src/hover/tests.rs | 3 + .../crates/ide/src/inlay_hints.rs | 6 +- .../crates/ide/src/inlay_hints/adjustment.rs | 10 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 2 +- .../crates/ide/src/signature_help.rs | 4 +- .../crates/ide/src/syntax_highlighting.rs | 22 +- .../test_data/highlight_general.html | 12 +- .../crates/intern/src/symbol/symbols.rs | 5 + .../crates/profile/src/stop_watch.rs | 8 +- .../crates/query-group-macro/src/queries.rs | 3 +- .../crates/test-utils/src/minicore.rs | 15 +- 109 files changed, 19140 insertions(+), 1309 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 80a311a74abe4..f72e698f60631 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -259,9 +259,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chalk-derive" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb4899682de915ca7c0b025bdd0a3d34c75fe12184122fda6805a7baddaa293c" +checksum = "9ea9b1e80910f66ae87c772247591432032ef3f6a67367ff17f8343db05beafa" dependencies = [ "proc-macro2", "quote", @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a37d2ab99352b4caca135061e7b4ac67024b648c28ed0b787feec4bea4caed" +checksum = "7047a516de16226cd17344d41a319d0ea1064bf9e60bd612ab341ab4a34bbfa8" dependencies = [ "bitflags 2.9.1", "chalk-derive", @@ -281,9 +281,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c855be60e646664bc37c2496d3dc81ca5ef60520930e5e0f0057a0575aff6c19" +checksum = "882959c242558cc686de7ff0aa59860295598d119e84a4b100215f44c3d606c4" dependencies = [ "chalk-derive", "chalk-ir", @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "477ac6cdfd2013e9f93b09b036c2b607a67b2e728f4777b8422d55a79e9e3a34" +checksum = "72860086494ccfa05bbd3779a74babb8ace27da9a0cbabffa1315223c7290927" dependencies = [ "chalk-derive", "chalk-ir", @@ -445,6 +445,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive-where" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_arbitrary" version = "1.4.1" @@ -696,6 +707,7 @@ dependencies = [ "indexmap", "intern", "itertools 0.14.0", + "ra-ap-rustc_type_ir", "rustc-hash 2.1.1", "smallvec", "span", @@ -705,6 +717,8 @@ dependencies = [ "test-fixture", "test-utils", "tracing", + "tracing-subscriber", + "tracing-tree", "triomphe", "tt", ] @@ -801,8 +815,11 @@ dependencies = [ "project-model", "query-group-macro", "ra-ap-rustc_abi", + "ra-ap-rustc_ast_ir", "ra-ap-rustc_index", + "ra-ap-rustc_next_trait_solver", "ra-ap-rustc_pattern_analysis", + "ra-ap-rustc_type_ir", "rustc-hash 2.1.1", "rustc_apfloat", "salsa", @@ -1856,6 +1873,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "ra-ap-rustc_ast_ir" +version = "0.123.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc17e8ce797f2a8d03b838fbf166749b876164432ce81e37d283bf69e3cf80" + [[package]] name = "ra-ap-rustc_hashes" version = "0.123.0" @@ -1908,6 +1931,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ra-ap-rustc_next_trait_solver" +version = "0.123.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7dfbdf1d045ff4e385e1efdfc3799379895e9c3f3b9b379a0bef4cb238441" +dependencies = [ + "derive-where", + "ra-ap-rustc_index", + "ra-ap-rustc_type_ir", + "ra-ap-rustc_type_ir_macros", + "tracing", +] + [[package]] name = "ra-ap-rustc_parse_format" version = "0.121.0" @@ -1931,6 +1967,37 @@ dependencies = [ "tracing", ] +[[package]] +name = "ra-ap-rustc_type_ir" +version = "0.123.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bc59fb10a922c38a24cb8a1494f799b0af30bd041acbea689378d3bf330534b" +dependencies = [ + "bitflags 2.9.1", + "derive-where", + "ena", + "indexmap", + "ra-ap-rustc_ast_ir", + "ra-ap-rustc_index", + "ra-ap-rustc_type_ir_macros", + "rustc-hash 2.1.1", + "smallvec", + "thin-vec", + "tracing", +] + +[[package]] +name = "ra-ap-rustc_type_ir_macros" +version = "0.123.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58878914b6dac7499baeecc8dbb4b9d9dda88030e4ab90cd3b4e87523fbedafe" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "rayon" version = "1.10.0" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 01a13a39f7b40..bb8444ed73422 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -94,6 +94,9 @@ ra-ap-rustc_parse_format = { version = "0.121", default-features = false } ra-ap-rustc_index = { version = "0.123", default-features = false } ra-ap-rustc_abi = { version = "0.123", default-features = false } ra-ap-rustc_pattern_analysis = { version = "0.123", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.123", default-features = false } +ra-ap-rustc_type_ir = { version = "0.123", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.123", default-features = false } # local crates that aren't published to crates.io. These should not have versions. @@ -108,10 +111,10 @@ arrayvec = "0.7.6" bitflags = "2.9.1" cargo_metadata = "0.21.0" camino = "1.1.10" -chalk-solve = { version = "0.103.0", default-features = false } -chalk-ir = "0.103.0" -chalk-recursive = { version = "0.103.0", default-features = false } -chalk-derive = "0.103.0" +chalk-solve = { version = "0.104.0", default-features = false } +chalk-ir = "0.104.0" +chalk-recursive = { version = "0.104.0", default-features = false } +chalk-derive = "0.104.0" crossbeam-channel = "0.5.15" dissimilar = "1.0.10" dot = "0.1.4" 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 d431f2140165e..a0be69cb2f96e 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 @@ -383,12 +383,17 @@ language_item_table! { AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); - AsyncFnOnceOutput, sym::async_fn_once_output,async_fn_once_output, Target::AssocTy, GenericRequirement::None; + CallRefFuture, sym::call_ref_future, call_ref_future_ty, Target::AssocTy, GenericRequirement::None; + CallOnceFuture, sym::call_once_future, call_once_future_ty, Target::AssocTy, GenericRequirement::None; + AsyncFnOnceOutput, sym::async_fn_once_output, async_fn_once_output_ty, Target::AssocTy, GenericRequirement::None; + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + CoroutineReturn, sym::coroutine_return, coroutine_return_ty, Target::AssocTy, GenericRequirement::None; + CoroutineYield, sym::coroutine_yield, coroutine_yield_ty, Target::AssocTy, GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 92e610b36acd0..598b2c0314a94 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -395,7 +395,7 @@ impl ImplSignature { bitflags::bitflags! { #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] - pub struct TraitFlags: u8 { + pub struct TraitFlags: u16 { const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1; const FUNDAMENTAL = 1 << 2; const UNSAFE = 1 << 3; @@ -403,6 +403,7 @@ bitflags::bitflags! { const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 5; const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 6; const RUSTC_PAREN_SUGAR = 1 << 7; + const COINDUCTIVE = 1 << 8; } } @@ -436,6 +437,9 @@ impl TraitSignature { if attrs.by_key(sym::rustc_paren_sugar).exists() { flags |= TraitFlags::RUSTC_PAREN_SUGAR; } + if attrs.by_key(sym::rustc_coinductive).exists() { + flags |= TraitFlags::COINDUCTIVE; + } let mut skip_array_during_method_dispatch = attrs.by_key(sym::rustc_skip_array_during_method_dispatch).exists(); let mut skip_boxed_slice_during_method_dispatch = false; diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 7cc0a26d37c80..64182110e1862 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -40,7 +40,14 @@ salsa-macros.workspace = true ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true ra-ap-rustc_pattern_analysis.workspace = true +ra-ap-rustc_ast_ir.workspace = true +ra-ap-rustc_type_ir.workspace = true +ra-ap-rustc_next_trait_solver.workspace = true +# These moved to dev deps if `setup_tracing` was a macro and dependents also +# included these +tracing-subscriber.workspace = true +tracing-tree.workspace = true # local deps stdx.workspace = true @@ -53,9 +60,6 @@ span.workspace = true [dev-dependencies] expect-test = "1.5.1" -tracing.workspace = true -tracing-subscriber.workspace = true -tracing-tree.workspace = true project-model.workspace = true # local deps diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 26ca7fb9a15ec..4ea0156e1248a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -225,7 +225,9 @@ pub(crate) fn deref_by_trait( // Check that the type implements Deref at all let trait_ref = projection.trait_ref(db); let implements_goal: Goal = trait_ref.cast(Interner); - table.try_obligation(implements_goal.clone())?; + if table.try_obligation(implements_goal.clone()).no_solution() { + return None; + } table.register_obligation(implements_goal); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 3ba7c93d4fb76..f523a5e8bfa05 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -1,47 +1,36 @@ //! The implementation of `RustIrDatabase` for Chalk, which provides information //! about the code that Chalk needs. -use core::ops; -use std::{iter, ops::ControlFlow, sync::Arc}; +use std::sync::Arc; -use hir_expand::name::Name; -use intern::sym; -use span::Edition; use tracing::debug; -use chalk_ir::{CanonicalVarKinds, cast::Caster, fold::shift::Shift}; -use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; +use chalk_ir::{cast::Caster, fold::shift::Shift}; +use chalk_solve::rust_ir::{self, WellKnownTrait}; use base_db::Crate; use hir_def::{ - AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, - TypeAliasId, VariantId, - hir::Movability, + AssocItemId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, + VariantId, lang_item::LangItem, signatures::{ImplFlags, StructFlags, TraitFlags}, }; use crate::{ - AliasEq, AliasTy, BoundVar, DebruijnIndex, Interner, ProjectionTy, ProjectionTyExt, - QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, - WhereClause, - db::{HirDatabase, InternedCoroutine}, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + AliasEq, AliasTy, DebruijnIndex, Interner, ProjectionTyExt, QuantifiedWhereClause, + Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, + db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, generics::generics, lower::LifetimeElisionKind, - make_binders, make_single_type_binders, + make_binders, mapping::{ToChalk, TypeAliasAsValue, from_chalk}, - method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TraitImpls, TyFingerprint}, to_assoc_type_id, to_chalk_trait_id, - traits::ChalkContext, - utils::ClosureSubst, - wrap_empty_binders, }; pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum; pub(crate) type AdtDatum = chalk_solve::rust_ir::AdtDatum; pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum; -pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum; pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; pub(crate) type TraitId = chalk_ir::TraitId; @@ -52,551 +41,6 @@ pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue; pub(crate) type Variances = chalk_ir::Variances; -impl chalk_solve::RustIrDatabase for ChalkContext<'_> { - fn associated_ty_data(&self, id: AssocTypeId) -> Arc { - self.db.associated_ty_data(from_assoc_type_id(id)) - } - fn associated_ty_from_impl( - &self, - impl_id: chalk_ir::ImplId, - assoc_type_id: chalk_ir::AssocTypeId, - ) -> Option> { - let alias_id = from_assoc_type_id(assoc_type_id); - let trait_sig = self.db.type_alias_signature(alias_id); - hir_def::ImplId::from_chalk(self.db, impl_id).impl_items(self.db).items.iter().find_map( - |(name, item)| match item { - AssocItemId::TypeAliasId(alias) if &trait_sig.name == name => { - Some(TypeAliasAsValue(*alias).to_chalk(self.db)) - } - _ => None, - }, - ) - } - fn trait_datum(&self, trait_id: TraitId) -> Arc { - self.db.trait_datum(self.krate, trait_id) - } - fn adt_datum(&self, struct_id: AdtId) -> Arc { - self.db.adt_datum(self.krate, struct_id) - } - fn adt_repr(&self, _struct_id: AdtId) -> Arc> { - // FIXME: keep track of these - Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None }) - } - fn discriminant_type(&self, ty: chalk_ir::Ty) -> chalk_ir::Ty { - if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) - && let hir_def::AdtId::EnumId(e) = id.0 - { - let enum_data = self.db.enum_signature(e); - let ty = enum_data.repr.unwrap_or_default().discr_type(); - return chalk_ir::TyKind::Scalar(match ty { - hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed { - true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize), - false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize), - }, - hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed { - true => chalk_ir::Scalar::Int(match size { - hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8, - hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16, - hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32, - hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64, - hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128, - }), - false => chalk_ir::Scalar::Uint(match size { - hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8, - hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16, - hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32, - hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64, - hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128, - }), - }, - }) - .intern(Interner); - } - chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8)).intern(Interner) - } - fn impl_datum(&self, impl_id: ImplId) -> Arc { - self.db.impl_datum(self.krate, impl_id) - } - - fn fn_def_datum( - &self, - fn_def_id: chalk_ir::FnDefId, - ) -> Arc> { - self.db.fn_def_datum(from_chalk(self.db, fn_def_id)) - } - - fn impls_for_trait( - &self, - trait_id: TraitId, - parameters: &[chalk_ir::GenericArg], - binders: &CanonicalVarKinds, - ) -> Vec { - debug!("impls_for_trait {:?}", trait_id); - let trait_: hir_def::TraitId = from_chalk_trait_id(trait_id); - - let ty: Ty = parameters[0].assert_ty_ref(Interner).clone(); - - fn binder_kind( - ty: &Ty, - binders: &CanonicalVarKinds, - ) -> Option { - if let TyKind::BoundVar(bv) = ty.kind(Interner) { - let binders = binders.as_slice(Interner); - if bv.debruijn == DebruijnIndex::INNERMOST - && let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind - { - return Some(tk); - } - } - None - } - - let self_ty_fp = TyFingerprint::for_trait_impl(&ty); - let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { - Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS, - Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS, - _ => self_ty_fp.as_slice(), - }; - - let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); - - let mut result = vec![]; - if fps.is_empty() { - debug!("Unrestricted search for {:?} impls...", trait_); - _ = self.for_trait_impls(trait_, self_ty_fp, |impls| { - result.extend(impls.for_trait(trait_).map(id_to_chalk)); - ControlFlow::Continue(()) - }); - } else { - _ = - self.for_trait_impls(trait_, self_ty_fp, |impls| { - result.extend(fps.iter().flat_map(move |fp| { - impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) - })); - ControlFlow::Continue(()) - }); - }; - - debug!("impls_for_trait returned {} impls", result.len()); - result - } - - fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind) -> bool { - debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind); - - let trait_id = from_chalk_trait_id(auto_trait_id); - let self_ty = kind.clone().intern(Interner); - // We cannot filter impls by `TyFingerprint` for the following types: - let self_ty_fp = match kind { - // because we need to find any impl whose Self type is a ref with the same mutability - // (we don't care about the inner type). - TyKind::Ref(..) => None, - // because we need to find any impl whose Self type is a tuple with the same arity. - TyKind::Tuple(..) => None, - _ => TyFingerprint::for_trait_impl(&self_ty), - }; - - let check_kind = |impl_id| { - let impl_self_ty = self.db.impl_self_ty(impl_id); - // NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions. - let impl_self_kind = impl_self_ty.skip_binders().kind(Interner); - - match (kind, impl_self_kind) { - (TyKind::Adt(id_a, _), TyKind::Adt(id_b, _)) => id_a == id_b, - (TyKind::AssociatedType(id_a, _), TyKind::AssociatedType(id_b, _)) => id_a == id_b, - (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b, - (TyKind::Error, TyKind::Error) - | (TyKind::Str, TyKind::Str) - | (TyKind::Slice(_), TyKind::Slice(_)) - | (TyKind::Never, TyKind::Never) - | (TyKind::Array(_, _), TyKind::Array(_, _)) => true, - (TyKind::Tuple(arity_a, _), TyKind::Tuple(arity_b, _)) => arity_a == arity_b, - (TyKind::OpaqueType(id_a, _), TyKind::OpaqueType(id_b, _)) => id_a == id_b, - (TyKind::FnDef(id_a, _), TyKind::FnDef(id_b, _)) => id_a == id_b, - (TyKind::Ref(id_a, _, _), TyKind::Ref(id_b, _, _)) - | (TyKind::Raw(id_a, _), TyKind::Raw(id_b, _)) => id_a == id_b, - (TyKind::Closure(id_a, _), TyKind::Closure(id_b, _)) => id_a == id_b, - (TyKind::Coroutine(id_a, _), TyKind::Coroutine(id_b, _)) - | (TyKind::CoroutineWitness(id_a, _), TyKind::CoroutineWitness(id_b, _)) => { - id_a == id_b - } - (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a == id_b, - (_, _) => false, - } - }; - - if let Some(fp) = self_ty_fp { - self.for_trait_impls(trait_id, self_ty_fp, |impls| { - match impls.for_trait_and_self_ty(trait_id, fp).any(check_kind) { - true => ControlFlow::Break(()), - false => ControlFlow::Continue(()), - } - }) - } else { - self.for_trait_impls(trait_id, self_ty_fp, |impls| { - match impls.for_trait(trait_id).any(check_kind) { - true => ControlFlow::Break(()), - false => ControlFlow::Continue(()), - } - }) - } - .is_break() - } - - fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc { - self.db.associated_ty_value(self.krate, id) - } - - fn custom_clauses(&self) -> Vec> { - vec![] - } - fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec { - // We don't do coherence checking (yet) - unimplemented!() - } - fn interner(&self) -> Interner { - Interner - } - fn well_known_trait_id( - &self, - well_known_trait: WellKnownTrait, - ) -> Option> { - let lang_item = lang_item_from_well_known_trait(well_known_trait); - let trait_ = lang_item.resolve_trait(self.db, self.krate)?; - Some(to_chalk_trait_id(trait_)) - } - fn well_known_assoc_type_id( - &self, - assoc_type: rust_ir::WellKnownAssocType, - ) -> Option> { - let lang_item = match assoc_type { - rust_ir::WellKnownAssocType::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, - }; - let alias = lang_item.resolve_type_alias(self.db, self.krate)?; - Some(to_assoc_type_id(alias)) - } - - fn program_clauses_for_env( - &self, - environment: &chalk_ir::Environment, - ) -> chalk_ir::ProgramClauses { - self.db.program_clauses_for_chalk_env(self.krate, self.block, environment.clone()) - } - - fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId) -> Arc { - let full_id = self.db.lookup_intern_impl_trait_id(id.into()); - let bound = match full_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let datas = self - .db - .return_type_impl_traits(func) - .expect("impl trait id without impl traits"); - let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders(); - let data = &datas.impl_traits[idx]; - let bound = OpaqueTyDatumBound { - bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - chalk_ir::Binders::new(binders, bound) - } - crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => { - let datas = self - .db - .type_alias_impl_traits(alias) - .expect("impl trait id without impl traits"); - let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders(); - let data = &datas.impl_traits[idx]; - let bound = OpaqueTyDatumBound { - bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - chalk_ir::Binders::new(binders, bound) - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = - LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| { - let alias = trait_ - .trait_items(self.db) - .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; - Some((trait_, alias)) - }) - { - // Making up Symbol’s value as variable is void: AsyncBlock: - // - // |--------------------OpaqueTyDatum-------------------| - // |-------------OpaqueTyDatumBound--------------| - // for [Future, Future::Output = T] - // ^1 ^0 ^0 ^0 ^1 - let impl_bound = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(future_trait), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar { - debruijn: DebruijnIndex::INNERMOST, - index: 0, - }) - .intern(Interner), - ), - }); - let mut binder = vec![]; - binder.push(crate::wrap_empty_binders(impl_bound)); - let sized_trait = LangItem::Sized.resolve_trait(self.db, self.krate); - if let Some(sized_trait_) = sized_trait { - let sized_bound = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(sized_trait_), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar { - debruijn: DebruijnIndex::INNERMOST, - index: 0, - }) - .intern(Interner), - ), - }); - binder.push(crate::wrap_empty_binders(sized_bound)); - } - let proj_bound = WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(future_output), - // Self type as the first parameter. - substitution: Substitution::from1( - Interner, - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - ), - }), - // The parameter of the opaque type. - ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }) - .intern(Interner), - }); - binder.push(crate::wrap_empty_binders(proj_bound)); - let bound = OpaqueTyDatumBound { - bounds: make_single_type_binders(binder), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - // The opaque type has 1 parameter. - make_single_type_binders(bound) - } else { - // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. - let bound = OpaqueTyDatumBound { - bounds: chalk_ir::Binders::empty(Interner, vec![]), - where_clauses: chalk_ir::Binders::empty(Interner, vec![]), - }; - // The opaque type has 1 parameter. - make_single_type_binders(bound) - } - } - }; - - Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound }) - } - - fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { - // FIXME: actually provide the hidden type; it is relevant for auto traits - TyKind::Error.intern(Interner) - } - - // object safety was renamed to dyn-compatibility but still remains here in chalk. - // This will be removed since we are going to migrate to next-gen trait solver. - fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> bool { - let trait_ = from_chalk_trait_id(trait_id); - crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none() - } - - fn closure_kind( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> rust_ir::ClosureKind { - // Fn is the closure kind that implements all three traits - rust_ir::ClosureKind::Fn - } - fn closure_inputs_and_output( - &self, - _closure_id: chalk_ir::ClosureId, - substs: &chalk_ir::Substitution, - ) -> chalk_ir::Binders> { - let sig_ty = ClosureSubst(substs).sig_ty(); - let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); - let io = rust_ir::FnDefInputsAndOutputDatum { - argument_types: sig.params().to_vec(), - return_type: sig.ret().clone(), - }; - chalk_ir::Binders::empty(Interner, io.shifted_in(Interner)) - } - fn closure_upvars( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> chalk_ir::Binders> { - let ty = TyBuilder::unit(); - chalk_ir::Binders::empty(Interner, ty) - } - fn closure_fn_substitution( - &self, - _closure_id: chalk_ir::ClosureId, - _substs: &chalk_ir::Substitution, - ) -> chalk_ir::Substitution { - Substitution::empty(Interner) - } - - fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { - let id = from_chalk_trait_id(trait_id); - self.db.trait_signature(id).name.display(self.db, self.edition()).to_string() - } - fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { - let edition = self.edition(); - match adt_id { - hir_def::AdtId::StructId(id) => { - self.db.struct_signature(id).name.display(self.db, edition).to_string() - } - hir_def::AdtId::EnumId(id) => { - self.db.enum_signature(id).name.display(self.db, edition).to_string() - } - hir_def::AdtId::UnionId(id) => { - self.db.union_signature(id).name.display(self.db, edition).to_string() - } - } - } - fn adt_size_align(&self, _id: chalk_ir::AdtId) -> Arc { - // FIXME - Arc::new(rust_ir::AdtSizeAlign::from_one_zst(false)) - } - fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { - let id = self.db.associated_ty_data(from_assoc_type_id(assoc_ty_id)).name; - self.db.type_alias_signature(id).name.display(self.db, self.edition()).to_string() - } - fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { - format!("Opaque_{:?}", opaque_ty_id.0) - } - fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId) -> String { - format!("fn_{:?}", fn_def_id.0) - } - fn coroutine_datum( - &self, - id: chalk_ir::CoroutineId, - ) -> Arc> { - let InternedCoroutine(parent, expr) = self.db.lookup_intern_coroutine(id.into()); - - // We fill substitution with unknown type, because we only need to know whether the generic - // params are types or consts to build `Binders` and those being filled up are for - // `resume_type`, `yield_type`, and `return_type` of the coroutine in question. - let subst = TyBuilder::subst_for_coroutine(self.db, parent).fill_with_unknown().build(); - - let len = subst.len(Interner); - let input_output = rust_ir::CoroutineInputOutputDatum { - resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3)) - .intern(Interner), - yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2)) - .intern(Interner), - return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1)) - .intern(Interner), - // FIXME: calculate upvars - upvars: vec![], - }; - - let it = subst - .iter(Interner) - .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone())); - let input_output = crate::make_type_and_const_binders(it, input_output); - - let movability = match self.db.body(parent)[expr] { - hir_def::hir::Expr::Closure { - closure_kind: hir_def::hir::ClosureKind::Coroutine(movability), - .. - } => movability, - _ => unreachable!("non coroutine expression interned as coroutine"), - }; - let movability = match movability { - Movability::Static => rust_ir::Movability::Static, - Movability::Movable => rust_ir::Movability::Movable, - }; - - Arc::new(rust_ir::CoroutineDatum { movability, input_output }) - } - fn coroutine_witness_datum( - &self, - id: chalk_ir::CoroutineId, - ) -> Arc> { - // FIXME: calculate inner types - let inner_types = - rust_ir::CoroutineWitnessExistential { types: wrap_empty_binders(vec![]) }; - - let InternedCoroutine(parent, _) = self.db.lookup_intern_coroutine(id.into()); - // See the comment in `coroutine_datum()` for unknown types. - let subst = TyBuilder::subst_for_coroutine(self.db, parent).fill_with_unknown().build(); - let it = subst - .iter(Interner) - .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone())); - let inner_types = crate::make_type_and_const_binders(it, inner_types); - - Arc::new(rust_ir::CoroutineWitnessDatum { inner_types }) - } - - fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase { - &self.db - } -} - -impl ChalkContext<'_> { - fn edition(&self) -> Edition { - self.krate.data(self.db).edition - } - - fn for_trait_impls( - &self, - trait_id: hir_def::TraitId, - self_ty_fp: Option, - mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>, - ) -> ControlFlow<()> { - // Note: Since we're using `impls_for_trait` and `impl_provided_for`, - // only impls where the trait can be resolved should ever reach Chalk. - // `impl_datum` relies on that and will panic if the trait can't be resolved. - let in_deps = self.db.trait_impls_in_deps(self.krate); - let in_self = self.db.trait_impls_in_crate(self.krate); - let trait_module = trait_id.module(self.db); - let type_module = match self_ty_fp { - Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db)), - Some(TyFingerprint::ForeignType(type_id)) => { - Some(from_foreign_def_id(type_id).module(self.db)) - } - Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db)), - _ => None, - }; - - let mut def_blocks = - [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]; - - let block_impls = iter::successors(self.block, |&block_id| { - cov_mark::hit!(block_local_impls); - block_id.loc(self.db).module.containing_block() - }) - .inspect(|&block_id| { - // make sure we don't search the same block twice - def_blocks.iter_mut().for_each(|block| { - if *block == Some(block_id) { - *block = None; - } - }); - }) - .filter_map(|block_id| self.db.trait_impls_in_block(block_id)); - f(&in_self)?; - for it in in_deps.iter().map(ops::Deref::deref) { - f(it)?; - } - for it in block_impls { - f(&it)?; - } - for it in def_blocks.into_iter().flatten().filter_map(|it| self.db.trait_impls_in_block(it)) - { - f(&it)?; - } - ControlFlow::Continue(()) - } -} - impl chalk_ir::UnificationDatabase for &dyn HirDatabase { fn fn_def_variance( &self, @@ -610,15 +54,6 @@ impl chalk_ir::UnificationDatabase for &dyn HirDatabase { } } -pub(crate) fn program_clauses_for_chalk_env_query( - db: &dyn HirDatabase, - krate: Crate, - block: Option, - environment: chalk_ir::Environment, -) -> chalk_ir::ProgramClauses { - chalk_solve::program_clauses_for_env(&ChalkContext { db, krate, block }, &environment) -} - pub(crate) fn associated_ty_data_query( db: &dyn HirDatabase, type_alias: TypeAliasId, @@ -749,31 +184,6 @@ fn well_known_trait_from_lang_item(item: LangItem) -> Option { }) } -fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem { - match trait_ { - WellKnownTrait::Clone => LangItem::Clone, - WellKnownTrait::CoerceUnsized => LangItem::CoerceUnsized, - WellKnownTrait::Copy => LangItem::Copy, - WellKnownTrait::DiscriminantKind => LangItem::DiscriminantKind, - WellKnownTrait::DispatchFromDyn => LangItem::DispatchFromDyn, - WellKnownTrait::Drop => LangItem::Drop, - WellKnownTrait::Fn => LangItem::Fn, - WellKnownTrait::FnMut => LangItem::FnMut, - WellKnownTrait::FnOnce => LangItem::FnOnce, - WellKnownTrait::AsyncFn => LangItem::AsyncFn, - WellKnownTrait::AsyncFnMut => LangItem::AsyncFnMut, - WellKnownTrait::AsyncFnOnce => LangItem::AsyncFnOnce, - WellKnownTrait::Coroutine => LangItem::Coroutine, - WellKnownTrait::Sized => LangItem::Sized, - WellKnownTrait::Tuple => LangItem::Tuple, - WellKnownTrait::Unpin => LangItem::Unpin, - WellKnownTrait::Unsize => LangItem::Unsize, - WellKnownTrait::Pointee => LangItem::PointeeTrait, - WellKnownTrait::FnPtr => LangItem::FnPtrTrait, - WellKnownTrait::Future => LangItem::Future, - } -} - pub(crate) fn adt_datum_query( db: &dyn HirDatabase, krate: Crate, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 836cc96233eb8..8fa1aff0ef636 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -14,10 +14,9 @@ use hir_def::{ use crate::{ AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, - QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, - db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, generics::generics, mapping::ToChalk, to_chalk_trait_id, - utils::ClosureSubst, + QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, + WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, }; pub trait TyExt { @@ -371,7 +370,7 @@ impl TyExt for Ty { value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), binders: CanonicalVarKinds::empty(Interner), }; - db.trait_solve(crate_id, None, goal).is_some() + !db.trait_solve(crate_id, None, goal).no_solution() } fn equals_ctor(&self, other: &Ty) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 6449a4dc7e8c6..22b152fe034a6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -11,7 +11,7 @@ use test_utils::skip_slow_tests; use crate::{ Const, ConstScalar, Interner, MemoryMap, consteval::try_const_usize, db::HirDatabase, - display::DisplayTarget, mir::pad16, test_db::TestDB, + display::DisplayTarget, mir::pad16, setup_tracing, test_db::TestDB, }; use super::{ @@ -116,6 +116,7 @@ fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { } fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result { + let _tracing = setup_tracing(); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); let scope = &def_map[module_id.local_id].scope; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs new file mode 100644 index 0000000000000..da4aff54de378 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -0,0 +1,256 @@ +//! Constant evaluation details +// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir +#![allow(unused)] + +use base_db::Crate; +use hir_def::{ + EnumVariantId, GeneralConstId, + expr_store::{Body, HygieneId, path::Path}, + hir::{Expr, ExprId}, + resolver::{Resolver, ValueNs}, + type_ref::LiteralConstRef, +}; +use hir_expand::Lookup; +use rustc_type_ir::{ + UnevaluatedConst, + inherent::{IntoKind, SliceLike}, +}; +use stdx::never; +use triomphe::Arc; + +use crate::{ + ConstScalar, Interner, MemoryMap, Substitution, TraitEnvironment, + consteval::ConstEvalError, + db::HirDatabase, + generics::Generics, + infer::InferenceContext, + next_solver::{ + Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + ParamConst, SolverDefId, Ty, ValueConst, + mapping::{ChalkToNextSolver, convert_args_for_result, convert_binder_to_early_binder}, + }, +}; + +use super::mir::{interpret_mir, lower_to_mir, pad16}; + +pub(crate) fn path_to_const<'a, 'g>( + db: &'a dyn HirDatabase, + resolver: &Resolver<'a>, + path: &Path, + args: impl FnOnce() -> &'g Generics, + expected_ty: Ty<'a>, +) -> Option> { + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) { + Some(ValueNs::GenericParam(p)) => { + let args = args(); + match args + .type_or_const_param(p.into()) + .and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone()))) + { + Some((idx, _param)) => { + Some(Const::new_param(interner, ParamConst { index: idx as u32 })) + } + None => { + never!( + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", + args, + path, + p + ); + None + } + } + } + Some(ValueNs::ConstId(c)) => { + let args = GenericArgs::new_from_iter(interner, []); + Some(Const::new( + interner, + rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new( + SolverDefId::ConstId(c), + args, + )), + )) + } + _ => None, + } +} + +pub fn unknown_const<'db>(ty: Ty<'db>) -> Const<'db> { + Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) +} + +pub fn unknown_const_as_generic<'db>(ty: Ty<'db>) -> GenericArg<'db> { + unknown_const(ty).into() +} + +/// Interns a constant scalar with the given type +pub fn intern_const_ref<'a>( + db: &'a dyn HirDatabase, + value: &LiteralConstRef, + ty: Ty<'a>, + krate: Crate, +) -> Const<'a> { + let interner = DbInterner::new_with(db, Some(krate), None); + let layout = db.layout_of_ty_ns(ty, TraitEnvironment::empty(krate)); + let kind = match value { + LiteralConstRef::Int(i) => { + // FIXME: We should handle failure of layout better. + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()), + )) + } + LiteralConstRef::UInt(i) => { + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()), + )) + } + LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes(Box::new([*b as u8]), MemoryMap::default()), + )), + LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes((*c as u32).to_le_bytes().into(), MemoryMap::default()), + )), + LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + }; + Const::new(interner, kind) +} + +/// Interns a possibly-unknown target usize +pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Crate) -> Const<'db> { + intern_const_ref( + db, + &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), + Ty::new_uint(DbInterner::new_with(db, Some(krate), None), rustc_type_ir::UintTy::Usize), + krate, + ) +} + +pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option { + let interner = DbInterner::new_with(db, None, None); + match (*c).kind() { + ConstKind::Param(_) => None, + ConstKind::Infer(_) => None, + ConstKind::Bound(_, _) => None, + ConstKind::Placeholder(_) => None, + ConstKind::Unevaluated(unevaluated_const) => { + let c = match unevaluated_const.def { + SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), + SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); + let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); + try_const_usize(db, &ec) + } + ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().0, false))), + ConstKind::Error(_) => None, + ConstKind::Expr(_) => None, + } +} + +pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option { + let interner = DbInterner::new_with(db, None, None); + match (*c).kind() { + ConstKind::Param(_) => None, + ConstKind::Infer(_) => None, + ConstKind::Bound(_, _) => None, + ConstKind::Placeholder(_) => None, + ConstKind::Unevaluated(unevaluated_const) => { + let c = match unevaluated_const.def { + SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), + SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); + let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); + try_const_isize(db, &ec) + } + ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().0, true))), + ConstKind::Error(_) => None, + ConstKind::Expr(_) => None, + } +} + +pub(crate) fn const_eval_discriminant_variant( + db: &dyn HirDatabase, + variant_id: EnumVariantId, +) -> Result { + let interner = DbInterner::new_with(db, None, None); + let def = variant_id.into(); + let body = db.body(def); + let loc = variant_id.lookup(db); + if matches!(body[body.body_expr], Expr::Missing) { + let prev_idx = loc.index.checked_sub(1); + let value = match prev_idx { + Some(prev_idx) => { + 1 + db.const_eval_discriminant( + loc.parent.enum_variants(db).variants[prev_idx as usize].0, + )? + } + _ => 0, + }; + return Ok(value); + } + + let repr = db.enum_signature(loc.parent).repr; + let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed()); + + let mir_body = db.monomorphized_mir_body( + def, + Substitution::empty(Interner), + db.trait_environment_for_body(def), + )?; + let c = interpret_mir(db, mir_body, false, None)?.0?; + let c = c.to_nextsolver(interner); + let c = if is_signed { + try_const_isize(db, &c).unwrap() + } else { + try_const_usize(db, &c).unwrap() as i128 + }; + Ok(c) +} + +// FIXME: Ideally constants in const eval should have separate body (issue #7434), and this function should +// get an `InferenceResult` instead of an `InferenceContext`. And we should remove `ctx.clone().resolve_all()` here +// and make this function private. See the fixme comment on `InferenceContext::resolve_all`. +pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) -> Const<'db> { + let interner = DbInterner::new_with(ctx.db, None, None); + let infer = ctx.clone().resolve_all(); + fn has_closure(body: &Body, expr: ExprId) -> bool { + if matches!(body[expr], Expr::Closure { .. }) { + return true; + } + let mut r = false; + body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx)); + r + } + if has_closure(ctx.body, expr) { + // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic. + return unknown_const(infer[expr].clone().to_nextsolver(interner)); + } + if let Expr::Path(p) = &ctx.body[expr] { + let resolver = &ctx.resolver; + if let Some(c) = path_to_const( + ctx.db, + resolver, + p, + || ctx.generics(), + infer[expr].to_nextsolver(interner), + ) { + return c; + } + } + if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) + && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) + { + return result.to_nextsolver(interner); + } + unknown_const(infer[expr].to_nextsolver(interner)) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index b3d46845c443a..18b8db21161fd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -17,7 +17,7 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Interner, PolyFnSig, Substitution, + Binders, Const, ImplTraitId, ImplTraits, InferenceResult, PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db, consteval::ConstEvalError, drop::DropGlue, @@ -26,6 +26,7 @@ use crate::{ lower::{Diagnostics, GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, + traits::NextTraitSolveResult, }; #[query_group::query_group] @@ -295,24 +296,162 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { ) -> Ty; #[salsa::invoke(crate::traits::trait_solve_query)] + #[salsa::transparent] fn trait_solve( &self, krate: Crate, block: Option, goal: crate::Canonical>, - ) -> Option; - - #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] - fn program_clauses_for_chalk_env( - &self, - krate: Crate, - block: Option, - env: chalk_ir::Environment, - ) -> chalk_ir::ProgramClauses; + ) -> NextTraitSolveResult; #[salsa::invoke(crate::drop::has_drop_glue)] #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)] fn has_drop_glue(&self, ty: Ty, env: Arc) -> DropGlue; + + // next trait solver + + #[salsa::invoke(crate::layout::layout_of_adt_ns_query)] + #[salsa::cycle(cycle_result = crate::layout::layout_of_adt_ns_cycle_result)] + fn layout_of_adt_ns<'db>( + &'db self, + def: AdtId, + args: crate::next_solver::GenericArgs<'db>, + trait_env: Arc, + ) -> Result, LayoutError>; + + #[salsa::invoke(crate::layout::layout_of_ty_ns_query)] + #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_ns_cycle_result)] + fn layout_of_ty_ns<'db>( + &'db self, + ty: crate::next_solver::Ty<'db>, + env: Arc, + ) -> Result, LayoutError>; + + #[salsa::invoke(crate::lower_nextsolver::ty_query)] + #[salsa::transparent] + fn ty_ns<'db>( + &'db self, + def: TyDefId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; + + #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] + fn type_for_type_alias_with_diagnostics_ns<'db>( + &'db self, + def: TypeAliasId, + ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); + + #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)] + fn impl_self_ty_with_diagnostics_ns<'db>( + &'db self, + def: ImplId, + ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); + + #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)] + #[salsa::transparent] + fn impl_self_ty_ns<'db>( + &'db self, + def: ImplId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; + + // FIXME: Make this a non-interned query. + #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)] + fn const_param_ty_with_diagnostics_ns<'db>( + &'db self, + def: ConstParamId, + ) -> (crate::next_solver::Ty<'db>, Diagnostics); + + #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)] + #[salsa::transparent] + fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>; + + #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)] + fn impl_trait_with_diagnostics_ns<'db>( + &'db self, + def: ImplId, + ) -> Option<( + crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>, + Diagnostics, + )>; + + #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)] + #[salsa::transparent] + fn impl_trait_ns<'db>( + &'db self, + def: ImplId, + ) -> Option>>; + + #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)] + fn field_types_with_diagnostics_ns<'db>( + &'db self, + var: VariantId, + ) -> ( + Arc< + ArenaMap< + LocalFieldId, + crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, + >, + >, + Diagnostics, + ); + + #[salsa::invoke(crate::lower_nextsolver::field_types_query)] + #[salsa::transparent] + fn field_types_ns<'db>( + &'db self, + var: VariantId, + ) -> Arc< + ArenaMap>>, + >; + + #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)] + fn callable_item_signature_ns<'db>( + &'db self, + def: CallableDefId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>; + + #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)] + fn return_type_impl_traits_ns<'db>( + &'db self, + def: FunctionId, + ) -> Option>>>; + + #[salsa::invoke(crate::lower_nextsolver::type_alias_impl_traits)] + fn type_alias_impl_traits_ns<'db>( + &'db self, + def: TypeAliasId, + ) -> Option>>>; + + #[salsa::invoke(crate::lower_nextsolver::generic_predicates_for_param_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_predicates_for_param_cycle_result)] + fn generic_predicates_for_param_ns<'db>( + &'db self, + def: GenericDefId, + param_id: TypeOrConstParamId, + assoc_name: Option, + ) -> crate::lower_nextsolver::GenericPredicates<'db>; + + #[salsa::invoke(crate::lower_nextsolver::generic_predicates_query)] + fn generic_predicates_ns<'db>( + &'db self, + def: GenericDefId, + ) -> crate::lower_nextsolver::GenericPredicates<'db>; + + #[salsa::invoke( + crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query + )] + fn generic_predicates_without_parent_with_diagnostics_ns<'db>( + &'db self, + def: GenericDefId, + ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics); + + #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)] + #[salsa::transparent] + fn generic_predicates_without_parent_ns<'db>( + &'db self, + def: GenericDefId, + ) -> crate::lower_nextsolver::GenericPredicates<'db>; } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 5577be890da34..a7e942d92442c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -187,7 +187,7 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), binders: CanonicalVarKinds::empty(Interner), }; - db.trait_solve(env.krate, env.block, goal).is_some() + db.trait_solve(env.krate, env.block, goal).certain() } pub(crate) fn has_drop_glue_cycle_result( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 6294d683e6c02..2d21947ec60fc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -16,8 +16,8 @@ use rustc_hash::FxHashSet; use smallvec::SmallVec; use crate::{ - AliasEq, AliasTy, Binders, BoundVar, CallableSig, GoalData, ImplTraitId, Interner, OpaqueTyId, - ProjectionTyExt, Solution, Substitution, TraitRef, Ty, TyKind, WhereClause, all_super_traits, + AliasEq, AliasTy, Binders, BoundVar, CallableSig, DomainGoal, GoalData, ImplTraitId, Interner, + OpaqueTyId, ProjectionTyExt, Substitution, TraitRef, Ty, TyKind, WhereClause, all_super_traits, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, generics::{generics, trait_self_param_idx}, @@ -510,6 +510,8 @@ fn receiver_is_dispatchable( trait_id: to_chalk_trait_id(unsize_did), substitution: Substitution::from_iter(Interner, [self_ty.clone(), unsized_self_ty.clone()]), }); + let unsized_predicate = + Binders::empty(Interner, unsized_predicate.cast::(Interner)); let trait_predicate = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: Substitution::from_iter( @@ -518,18 +520,32 @@ fn receiver_is_dispatchable( .chain(placeholder_subst.iter(Interner).skip(1).cloned()), ), }); + let trait_predicate = Binders::empty(Interner, trait_predicate.cast::(Interner)); let generic_predicates = &*db.generic_predicates(func.into()); - let clauses = std::iter::once(unsized_predicate) - .chain(std::iter::once(trait_predicate)) - .chain(generic_predicates.iter().map(|pred| { - pred.clone().substitute(Interner, &placeholder_subst).into_value_and_skipped_binders().0 - })) - .map(|pred| { - pred.cast::>(Interner).into_from_env_clause(Interner) - }); - let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); + let goals = std::iter::once(unsized_predicate).chain(std::iter::once(trait_predicate)).chain( + generic_predicates.iter().map(|pred| { + pred.clone() + .substitute(Interner, &placeholder_subst) + .map(|g| g.cast::(Interner)) + }), + ); + let clauses = chalk_ir::ProgramClauses::from_iter( + Interner, + goals.into_iter().map(|g| { + chalk_ir::ProgramClause::new( + Interner, + chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication { + consequence: g, + conditions: chalk_ir::Goals::empty(Interner), + constraints: chalk_ir::Constraints::empty(Interner), + priority: chalk_ir::ClausePriority::High, + })), + ) + }), + ); + let env: chalk_ir::Environment = chalk_ir::Environment { clauses }; let obligation = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(dispatch_from_dyn_did), @@ -541,9 +557,8 @@ fn receiver_is_dispatchable( let mut table = chalk_solve::infer::InferenceTable::::new(); let canonicalized = table.canonicalize(Interner, in_env); - let solution = db.trait_solve(krate, None, canonicalized.quantified); - matches!(solution, Some(Solution::Unique(_))) + db.trait_solve(krate, None, canonicalized.quantified).certain() } fn receiver_for_self_ty(db: &dyn HirDatabase, func: FunctionId, ty: Ty) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 5078e8cfaa8b9..4ffa455084971 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -56,18 +56,21 @@ fn check_dyn_compatibility<'a>( continue; }; let mut osvs = FxHashSet::default(); - _ = dyn_compatibility_with_callback(&db, trait_id, &mut |osv| { - osvs.insert(match osv { - DynCompatibilityViolation::SizedSelf => SizedSelf, - DynCompatibilityViolation::SelfReferential => SelfReferential, - DynCompatibilityViolation::Method(_, mvc) => Method(mvc), - DynCompatibilityViolation::AssocConst(_) => AssocConst, - DynCompatibilityViolation::GAT(_) => GAT, - DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => { - HasNonCompatibleSuperTrait - } + let db = &db; + salsa::attach(db, || { + _ = dyn_compatibility_with_callback(db, trait_id, &mut |osv| { + osvs.insert(match osv { + DynCompatibilityViolation::SizedSelf => SizedSelf, + DynCompatibilityViolation::SelfReferential => SelfReferential, + DynCompatibilityViolation::Method(_, mvc) => Method(mvc), + DynCompatibilityViolation::AssocConst(_) => AssocConst, + DynCompatibilityViolation::GAT(_) => GAT, + DynCompatibilityViolation::HasNonCompatibleSuperTrait(_) => { + HasNonCompatibleSuperTrait + } + }); + ControlFlow::Continue(()) }); - ControlFlow::Continue(()) }); assert_eq!(osvs, expected, "dyn-compatibility violations for `{name}` do not match;"); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index f14872e68c3f5..e6470e5272d05 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -165,6 +165,21 @@ impl Generics { (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) } + pub(crate) fn type_or_const_param( + &self, + param: TypeOrConstParamId, + ) -> Option<(usize, TypeOrConstParamData)> { + let idx = self.find_type_or_const_param(param)?; + self.iter().nth(idx).and_then(|p| { + let data = match p.1 { + GenericParamDataRef::TypeParamData(p) => p.clone().into(), + GenericParamDataRef::ConstParamData(p) => p.clone().into(), + _ => return None, + }; + Some((idx, data)) + }) + } + pub fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { self.find_type_or_const_param(param) } @@ -272,7 +287,7 @@ pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> O } } -fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { +pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { let container = match def { GenericDefId::FunctionId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 86345b23364d3..7a11ec660d04b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -88,52 +88,54 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = tracing::info_span!("infer_query").entered(); - let resolver = def.resolver(db); - let body = db.body(def); - let mut ctx = InferenceContext::new(db, def, &body, resolver); - - match def { - DefWithBodyId::FunctionId(f) => { - ctx.collect_fn(f); - } - DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), - DefWithBodyId::VariantId(v) => { - ctx.return_ty = TyBuilder::builtin( - match db.enum_signature(v.lookup(db).parent).variant_body_type() { - hir_def::layout::IntegerType::Pointer(signed) => match signed { - true => BuiltinType::Int(BuiltinInt::Isize), - false => BuiltinType::Uint(BuiltinUint::Usize), - }, - hir_def::layout::IntegerType::Fixed(size, signed) => match signed { - true => BuiltinType::Int(match size { - Integer::I8 => BuiltinInt::I8, - Integer::I16 => BuiltinInt::I16, - Integer::I32 => BuiltinInt::I32, - Integer::I64 => BuiltinInt::I64, - Integer::I128 => BuiltinInt::I128, - }), - false => BuiltinType::Uint(match size { - Integer::I8 => BuiltinUint::U8, - Integer::I16 => BuiltinUint::U16, - Integer::I32 => BuiltinUint::U32, - Integer::I64 => BuiltinUint::U64, - Integer::I128 => BuiltinUint::U128, - }), + crate::next_solver::with_new_cache(|| { + let _p = tracing::info_span!("infer_query").entered(); + let resolver = def.resolver(db); + let body = db.body(def); + let mut ctx = InferenceContext::new(db, def, &body, resolver); + + match def { + DefWithBodyId::FunctionId(f) => { + ctx.collect_fn(f); + } + DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), + DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), + DefWithBodyId::VariantId(v) => { + ctx.return_ty = TyBuilder::builtin( + match db.enum_signature(v.lookup(db).parent).variant_body_type() { + hir_def::layout::IntegerType::Pointer(signed) => match signed { + true => BuiltinType::Int(BuiltinInt::Isize), + false => BuiltinType::Uint(BuiltinUint::Usize), + }, + hir_def::layout::IntegerType::Fixed(size, signed) => match signed { + true => BuiltinType::Int(match size { + Integer::I8 => BuiltinInt::I8, + Integer::I16 => BuiltinInt::I16, + Integer::I32 => BuiltinInt::I32, + Integer::I64 => BuiltinInt::I64, + Integer::I128 => BuiltinInt::I128, + }), + false => BuiltinType::Uint(match size { + Integer::I8 => BuiltinUint::U8, + Integer::I16 => BuiltinUint::U16, + Integer::I32 => BuiltinUint::U32, + Integer::I64 => BuiltinUint::U64, + Integer::I128 => BuiltinUint::U128, + }), + }, }, - }, - ); + ); + } } - } - ctx.infer_body(); + ctx.infer_body(); - ctx.infer_mut_body(); + ctx.infer_mut_body(); - ctx.infer_closures(); + ctx.infer_closures(); - Arc::new(ctx.resolve_all()) + Arc::new(ctx.resolve_all()) + }) } pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc { @@ -144,6 +146,7 @@ pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc, ty: Ty) -> Ty { // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only // works for the type case, so we check array unconditionally. Remove the array part @@ -1077,14 +1080,22 @@ impl<'db> InferenceContext<'db> { // Functions might be defining usage sites of TAITs. // To define an TAITs, that TAIT must appear in the function's signatures. // So, it suffices to check for params and return types. - if self - .return_ty - .data(Interner) - .flags - .intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) - { - tait_candidates.insert(self.return_ty.clone()); - } + fold_tys( + self.return_ty.clone(), + |ty, _| { + match ty.kind(Interner) { + TyKind::OpaqueType(..) + | TyKind::Alias(AliasTy::Opaque(..)) + | TyKind::InferenceVar(..) => { + tait_candidates.insert(self.return_ty.clone()); + } + _ => {} + } + ty + }, + DebruijnIndex::INNERMOST, + ); + self.make_tait_coercion_table(tait_candidates.iter()); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 8024c1a9a4e92..d8fc20e8741cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -3,12 +3,13 @@ use std::{cmp, convert::Infallible, mem, ops::ControlFlow}; use chalk_ir::{ - BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind, + BoundVar, DebruijnIndex, FnSubst, GenericArg, Mutability, TyKind, cast::Cast, fold::{FallibleTypeFolder, Shift, TypeFoldable}, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, }; use either::Either; +use hir_def::Lookup; use hir_def::{ DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, expr_store::path::Path, @@ -19,8 +20,8 @@ use hir_def::{ item_tree::FieldsShape, lang_item::LangItem, resolver::ValueNs, + type_ref::TypeRefId, }; -use hir_def::{Lookup, type_ref::TypeRefId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; @@ -30,8 +31,8 @@ use syntax::utils::is_raw_identifier; use crate::{ Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, - DynTyExt, FnAbi, FnPointer, FnSig, GenericArg, Interner, OpaqueTy, ProjectionTy, - ProjectionTyExt, Substitution, Ty, TyBuilder, TyExt, WhereClause, + DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTy, ProjectionTyExt, + Substitution, Ty, TyBuilder, TyExt, WhereClause, db::{HirDatabase, InternedClosure, InternedCoroutine}, error_lifetime, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx, generics::Generics, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 761a2564aa799..631a91bac481b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -13,14 +13,15 @@ use stdx::always; use triomphe::Arc; use crate::{ - Canonical, DomainGoal, FnAbi, FnPointer, FnSig, Guidance, InEnvironment, Interner, Lifetime, - Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, + Canonical, DomainGoal, FnAbi, FnPointer, FnSig, InEnvironment, Interner, Lifetime, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, autoderef::{Autoderef, AutoderefKind}, db::HirDatabase, infer::{ Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, TypeError, TypeMismatch, }, + traits::NextTraitSolveResult, utils::ClosureSubst, }; @@ -715,13 +716,18 @@ impl InferenceTable<'_> { // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the // rest for later. Also, there's some logic about sized type variables. // Need to find out in what cases this is necessary - let solution = self - .db - .trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner)) - .ok_or(TypeError)?; + let solution = self.db.trait_solve( + krate, + self.trait_env.block, + canonicalized.value.clone().cast(Interner), + ); match solution { - Solution::Unique(v) => { + // FIXME: this is a weaker guarantee than Chalk's `Guidance::Unique` + // was. Chalk's unique guidance at least guarantees that the real solution + // is some "subset" of the solutions matching the guidance, but the + // substs for `Certainty::No` don't have that same guarantee (I think). + NextTraitSolveResult::Certain(v) => { canonicalized.apply_solution( self, Canonical { @@ -731,13 +737,12 @@ impl InferenceTable<'_> { }, ); } - Solution::Ambig(Guidance::Definite(subst)) => { - // FIXME need to record an obligation here - canonicalized.apply_solution(self, subst) + // ...so, should think about how to get some actually get some guidance here + NextTraitSolveResult::Uncertain(..) | NextTraitSolveResult::NoSolution => { + return Err(TypeError); } - // FIXME actually we maybe should also accept unknown guidance here - _ => return Err(TypeError), - }; + } + let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() }; let adjustments = match reborrow { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 16fc2bfc0631f..261c02386822d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -278,6 +278,7 @@ impl InferenceContext<'_> { } } + #[tracing::instrument(level = "debug", skip(self, is_read), ret)] fn infer_expr_inner( &mut self, tgt_expr: ExprId, @@ -286,7 +287,9 @@ impl InferenceContext<'_> { ) -> Ty { self.db.unwind_if_revision_cancelled(); - let ty = match &self.body[tgt_expr] { + let expr = &self.body[tgt_expr]; + tracing::trace!(?expr); + let ty = match expr { Expr::Missing => self.err_ty(), &Expr::If { condition, then_branch, else_branch } => { let expected = &expected.adjust_for_branches(&mut self.table); @@ -1949,7 +1952,11 @@ impl InferenceContext<'_> { sig.ret().clone(), sig.is_varargs, ), - None => ((self.err_ty(), Vec::new()), self.err_ty(), true), + None => { + let formal_receiver_ty = self.table.new_type_var(); + let ret_ty = self.table.new_type_var(); + ((formal_receiver_ty, Vec::new()), ret_ty, true) + } }; self.unify(&formal_receiver_ty, &receiver_ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index c07755535f2a6..a709aebfa9c1b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -19,11 +19,13 @@ use triomphe::Arc; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, - GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment, InferenceVar, Interner, - Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, - consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, - to_chalk_trait_id, traits::FnTrait, + GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, + OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, + TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, + consteval::unknown_const, + db::HirDatabase, + fold_generic_args, fold_tys_and_consts, to_chalk_trait_id, + traits::{FnTrait, NextTraitSolveResult}, }; impl InferenceContext<'_> { @@ -116,9 +118,12 @@ impl> Canonicalized { // eagerly replace projections in the type; we may be getting types // e.g. from where clauses where this hasn't happened yet let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); + tracing::debug!("unifying {:?} {:?}", var, ty); ctx.unify(var.assert_ty_ref(Interner), &ty); } else { - let _ = ctx.try_unify(var, &new_vars.apply(v.clone(), Interner)); + let v = new_vars.apply(v.clone(), Interner); + tracing::debug!("try_unifying {:?} {:?}", var, v); + let _ = ctx.try_unify(var, &v); } } } @@ -326,6 +331,7 @@ impl<'a> InferenceTable<'a> { /// type annotation (e.g. from a let type annotation, field type or function /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. + #[tracing::instrument(skip(self), ret)] pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where T: HasInterner + TypeFoldable, @@ -333,12 +339,88 @@ impl<'a> InferenceTable<'a> { fold_tys_and_consts( ty, |e, _| match e { - Either::Left(ty) => Either::Left(match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - self.normalize_projection_ty(proj_ty.clone()) - } - _ => ty, - }), + Either::Left(ty) => { + let ty = self.resolve_ty_shallow(&ty); + tracing::debug!(?ty); + Either::Left(match ty.kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj_ty)) => { + let ty = self.normalize_projection_ty(proj_ty.clone()); + self.resolve_ty_shallow(&ty) + } + TyKind::AssociatedType(id, subst) => { + if ty.data(Interner).flags.intersects( + chalk_ir::TypeFlags::HAS_TY_INFER + | chalk_ir::TypeFlags::HAS_CT_INFER, + ) { + return Either::Left(ty); + } + let var = self.new_type_var(); + let proj_ty = chalk_ir::ProjectionTy { + associated_ty_id: *id, + substitution: subst.clone(), + }; + let normalize = chalk_ir::Normalize { + alias: AliasTy::Projection(proj_ty), + ty: var.clone(), + }; + let goal = chalk_ir::Goal::new( + Interner, + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Normalize( + normalize, + )), + ); + let in_env = InEnvironment::new(&self.trait_env.env, goal); + + let canonicalized = { + let result = + self.var_unification_table.canonicalize(Interner, in_env); + let free_vars = result + .free_vars + .into_iter() + .map(|free_var| free_var.to_generic_arg(Interner)) + .collect(); + Canonicalized { value: result.quantified, free_vars } + }; + let solution = self.db.trait_solve( + self.trait_env.krate, + self.trait_env.block, + canonicalized.value.clone(), + ); + if let NextTraitSolveResult::Certain(canonical_subst) = solution { + // This is not great :) But let's just assert this for now and come back to it later. + if canonical_subst.value.subst.len(Interner) != 1 { + ty + } else { + let normalized = canonical_subst.value.subst.as_slice(Interner) + [0] + .assert_ty_ref(Interner); + match normalized.kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj_ty)) => { + if id == &proj_ty.associated_ty_id + && subst == &proj_ty.substitution + { + ty + } else { + normalized.clone() + } + } + TyKind::AssociatedType(new_id, new_subst) => { + if new_id == id && new_subst == subst { + ty + } else { + normalized.clone() + } + } + _ => normalized.clone(), + } + } + } else { + ty + } + } + _ => ty, + }) + } Either::Right(c) => Either::Right(match &c.data(Interner).value { chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { crate::ConstScalar::UnevaluatedConst(c_id, subst) => { @@ -588,7 +670,6 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - #[tracing::instrument(skip_all)] pub(crate) fn unify>(&mut self, ty1: &T, ty2: &T) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, @@ -606,7 +687,7 @@ impl<'a> InferenceTable<'a> { }; result.goals.iter().all(|goal| { let canonicalized = self.canonicalize_with_free_vars(goal.clone()); - self.try_resolve_obligation(&canonicalized).is_some() + self.try_resolve_obligation(&canonicalized).certain() }) } @@ -633,6 +714,9 @@ impl<'a> InferenceTable<'a> { /// If `ty` is a type variable with known type, returns that type; /// otherwise, return ty. pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { + if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) { + return ty.clone(); + } self.resolve_obligations_as_possible(); self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone()) } @@ -662,7 +746,8 @@ impl<'a> InferenceTable<'a> { /// Checks an obligation without registering it. Useful mostly to check /// whether a trait *might* be implemented before deciding to 'lock in' the /// choice (during e.g. method resolution or deref). - pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option { + #[tracing::instrument(level = "debug", skip(self))] + pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult { let in_env = InEnvironment::new(&self.trait_env.env, goal); let canonicalized = self.canonicalize(in_env); @@ -674,10 +759,45 @@ impl<'a> InferenceTable<'a> { self.register_obligation_in_env(in_env) } + #[tracing::instrument(level = "debug", skip(self))] fn register_obligation_in_env(&mut self, goal: InEnvironment) { - let canonicalized = self.canonicalize_with_free_vars(goal); + match goal.goal.data(Interner) { + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), + )) => { + if ty.inference_var(Interner).is_some() { + match alias { + chalk_ir::AliasTy::Opaque(opaque) => { + if self.unify( + &chalk_ir::TyKind::OpaqueType( + opaque.opaque_ty_id, + opaque.substitution.clone(), + ) + .intern(Interner), + ty, + ) { + return; + } + } + _ => {} + } + } + } + _ => {} + } + let canonicalized = { + let result = self.var_unification_table.canonicalize(Interner, goal); + let free_vars = result + .free_vars + .into_iter() + .map(|free_var| free_var.to_generic_arg(Interner)) + .collect(); + Canonicalized { value: result.quantified, free_vars } + }; + tracing::debug!(?canonicalized); let solution = self.try_resolve_obligation(&canonicalized); - if matches!(solution, Some(Solution::Ambig(_))) { + tracing::debug!(?solution); + if solution.uncertain() { self.pending_obligations.push(canonicalized); } } @@ -694,7 +814,9 @@ impl<'a> InferenceTable<'a> { mem::swap(&mut self.pending_obligations, &mut obligations); for canonicalized in obligations.drain(..) { + tracing::debug!(obligation = ?canonicalized); if !self.check_changed(&canonicalized) { + tracing::debug!("not changed"); self.pending_obligations.push(canonicalized); continue; } @@ -799,37 +921,36 @@ impl<'a> InferenceTable<'a> { }) } + #[tracing::instrument(level = "debug", skip(self))] fn try_resolve_obligation( &mut self, canonicalized: &Canonicalized>, - ) -> Option> { + ) -> NextTraitSolveResult { let solution = self.db.trait_solve( self.trait_env.krate, self.trait_env.block, canonicalized.value.clone(), ); + tracing::debug!(?solution, ?canonicalized); match &solution { - Some(Solution::Unique(canonical_subst)) => { + NextTraitSolveResult::Certain(v) => { canonicalized.apply_solution( self, Canonical { - binders: canonical_subst.binders.clone(), - // FIXME: handle constraints - value: canonical_subst.value.subst.clone(), + binders: v.binders.clone(), + // FIXME handle constraints + value: v.value.subst.clone(), }, ); } - Some(Solution::Ambig(Guidance::Definite(substs))) => { - canonicalized.apply_solution(self, substs.clone()); - } - Some(_) => { - // FIXME use this when trying to resolve everything at the end - } - None => { - // FIXME obligation cannot be fulfilled => diagnostic + // ...so, should think about how to get some actually get some guidance here + NextTraitSolveResult::Uncertain(v) => { + canonicalized.apply_solution(self, v.clone()); } + NextTraitSolveResult::NoSolution => {} } + solution } @@ -896,7 +1017,10 @@ impl<'a> InferenceTable<'a> { environment: trait_env.clone(), }; let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() + if !self + .db + .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) + .no_solution() { self.register_obligation(obligation.goal); let return_ty = self.normalize_projection_ty(projection); @@ -909,10 +1033,10 @@ impl<'a> InferenceTable<'a> { environment: trait_env.clone(), }; let canonical = self.canonicalize(obligation.clone()); - if self + if !self .db .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .is_some() + .no_solution() { return Some((fn_x, arg_tys, return_ty)); } @@ -1032,7 +1156,7 @@ impl<'a> InferenceTable<'a> { substitution: Substitution::from1(Interner, ty), }); let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); - matches!(self.try_obligation(goal), Some(Solution::Unique(_))) + self.try_obligation(goal).certain() } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs index fecb3f4242a92..57ef5523b4332 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs @@ -2,11 +2,10 @@ //! representation of the various objects Chalk deals with (types, goals etc.). use crate::{ - AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, - Constraint, Constraints, FnAbi, FnDefId, GenericArg, GenericArgData, Goal, GoalData, Goals, - InEnvironment, Lifetime, LifetimeData, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseData, - ProgramClauses, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, Ty, - TyData, TyKind, VariableKind, VariableKinds, chalk_db, tls, + AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, FnAbi, + FnDefId, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, Lifetime, LifetimeData, + OpaqueTy, OpaqueTyId, ProgramClause, ProjectionTy, QuantifiedWhereClause, + QuantifiedWhereClauses, Substitution, Ty, TyKind, VariableKind, chalk_db, tls, }; use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance}; use hir_def::TypeAliasId; @@ -15,11 +14,19 @@ use smallvec::SmallVec; use std::fmt; use triomphe::Arc; +type TyData = chalk_ir::TyData; +type VariableKinds = chalk_ir::VariableKinds; +type Goals = chalk_ir::Goals; +type ProgramClauseData = chalk_ir::ProgramClauseData; +type Constraint = chalk_ir::Constraint; +type Constraints = chalk_ir::Constraints; +type ProgramClauses = chalk_ir::ProgramClauses; + #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct Interner; -#[derive(PartialEq, Eq, Hash)] -pub struct InternedWrapper(T); +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] +pub struct InternedWrapper(pub(crate) T); impl fmt::Debug for InternedWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -27,6 +34,9 @@ impl fmt::Debug for InternedWrapper { } } +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] +pub struct InternedWrapperNoDebug(pub(crate) T); + impl std::ops::Deref for InternedWrapper { type Target = T; @@ -124,6 +134,7 @@ impl chalk_ir::interner::Interner for Interner { fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) + .or_else(|| Some(fmt.write_str("ProjectionTy"))) } fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 107da6a5af6d6..819bd583deaed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -2,33 +2,43 @@ use std::fmt; -use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ - LocalFieldId, StructId, - layout::{ - Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, - ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange, - }, + AdtId, LocalFieldId, StructId, + layout::{LayoutCalculatorError, LayoutData}, }; use la_arena::{Idx, RawIdx}; -use rustc_abi::AddressSpace; -use rustc_index::IndexVec; +use rustc_abi::{ + AddressSpace, Float, Integer, LayoutCalculator, Primitive, ReprOptions, Scalar, StructKind, + TargetDataLayout, WrappingRange, +}; +use rustc_index::IndexVec; +use rustc_type_ir::{ + FloatTy, IntTy, UintTy, + inherent::{IntoKind, SliceLike}, +}; use triomphe::Arc; use crate::{ - Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, - consteval::try_const_usize, - db::{HirDatabase, InternedClosure}, - infer::normalize, - utils::ClosureSubst, + TraitEnvironment, + consteval_nextsolver::try_const_usize, + db::HirDatabase, + next_solver::{ + DbInterner, GenericArgs, ParamEnv, SolverDefId, Ty, TyKind, TypingMode, + infer::{DbInternerInferExt, traits::ObligationCause}, + mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, + project::solve_normalize::deeply_normalize, + }, }; -pub(crate) use self::adt::layout_of_adt_cycle_result; -pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; +pub(crate) use self::adt::{layout_of_adt_cycle_result, layout_of_adt_ns_cycle_result}; +pub use self::{ + adt::{layout_of_adt_ns_query, layout_of_adt_query}, + target::target_data_layout_query, +}; -mod adt; -mod target; +pub(crate) mod adt; +pub(crate) mod target; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RustcEnumVariantIdx(pub usize); @@ -119,11 +129,12 @@ impl<'a> LayoutCx<'a> { } } -fn layout_of_simd_ty( - db: &dyn HirDatabase, +// FIXME: move this to the `rustc_abi`. +fn layout_of_simd_ty<'db>( + db: &'db dyn HirDatabase, id: StructId, repr_packed: bool, - subst: &Substitution, + args: &GenericArgs<'db>, env: Arc, dl: &TargetDataLayout, ) -> Result, LayoutError> { @@ -132,18 +143,18 @@ fn layout_of_simd_ty( // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - let fields = db.field_types(id.into()); + let fields = db.field_types_ns(id.into()); let mut fields = fields.iter(); let Some(TyKind::Array(e_ty, e_len)) = fields .next() .filter(|_| fields.next().is_none()) - .map(|f| f.1.clone().substitute(Interner, subst).kind(Interner).clone()) + .map(|f| (*f.1).instantiate(DbInterner::new_with(db, None, None), args).kind()) else { return Err(LayoutError::InvalidSimdType); }; let e_len = try_const_usize(db, &e_len).ok_or(LayoutError::HasErrorConst)? as u64; - let e_ly = db.layout_of_ty(e_ty, env)?; + let e_ly = db.layout_of_ty_ns(e_ty, env)?; let cx = LayoutCx::new(dl); Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) @@ -151,108 +162,122 @@ fn layout_of_simd_ty( pub fn layout_of_ty_query( db: &dyn HirDatabase, - ty: Ty, + ty: crate::Ty, trait_env: Arc, ) -> Result, LayoutError> { let krate = trait_env.krate; + let interner = DbInterner::new_with(db, Some(krate), trait_env.block); + db.layout_of_ty_ns(ty.to_nextsolver(interner), trait_env) +} + +pub fn layout_of_ty_ns_query<'db>( + db: &'db dyn HirDatabase, + ty: Ty<'db>, + trait_env: Arc, +) -> Result, LayoutError> { + let krate = trait_env.krate; + let interner = DbInterner::new_with(db, Some(krate), trait_env.block); let Ok(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable); }; let dl = &*target; let cx = LayoutCx::new(dl); - let ty = normalize(db, trait_env.clone(), ty); - let kind = ty.kind(Interner); - let result = match kind { - TyKind::Adt(AdtId(def), subst) => { - if let hir_def::AdtId::StructId(s) = def { - let data = db.struct_signature(*s); - let repr = data.repr.unwrap_or_default(); - if repr.simd() { - return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target); + let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let cause = ObligationCause::dummy(); + let ty = deeply_normalize(infer_ctxt.at(&cause, ParamEnv::empty()), ty).unwrap_or(ty); + let result = match ty.kind() { + TyKind::Adt(def, args) => { + match def.inner().id { + hir_def::AdtId::StructId(s) => { + let data = db.struct_signature(s); + let repr = data.repr.unwrap_or_default(); + if repr.simd() { + return layout_of_simd_ty(db, s, repr.packed(), &args, trait_env, &target); + } } - }; - return db.layout_of_adt(*def, subst.clone(), trait_env); + _ => {} + } + return db.layout_of_adt_ns(def.inner().id, args, trait_env); } - TyKind::Scalar(s) => match s { - chalk_ir::Scalar::Bool => Layout::scalar( - dl, - Scalar::Initialized { - value: Primitive::Int(Integer::I8, false), - valid_range: WrappingRange { start: 0, end: 1 }, - }, - ), - chalk_ir::Scalar::Char => Layout::scalar( - dl, - Scalar::Initialized { - value: Primitive::Int(Integer::I32, false), - valid_range: WrappingRange { start: 0, end: 0x10FFFF }, - }, - ), - chalk_ir::Scalar::Int(i) => Layout::scalar( + TyKind::Bool => Layout::scalar( + dl, + Scalar::Initialized { + value: Primitive::Int(Integer::I8, false), + valid_range: WrappingRange { start: 0, end: 1 }, + }, + ), + TyKind::Char => Layout::scalar( + dl, + Scalar::Initialized { + value: Primitive::Int(Integer::I32, false), + valid_range: WrappingRange { start: 0, end: 0x10FFFF }, + }, + ), + TyKind::Int(i) => Layout::scalar( + dl, + scalar_unit( dl, - scalar_unit( - dl, - Primitive::Int( - match i { - IntTy::Isize => dl.ptr_sized_integer(), - IntTy::I8 => Integer::I8, - IntTy::I16 => Integer::I16, - IntTy::I32 => Integer::I32, - IntTy::I64 => Integer::I64, - IntTy::I128 => Integer::I128, - }, - true, - ), + Primitive::Int( + match i { + IntTy::Isize => dl.ptr_sized_integer(), + IntTy::I8 => Integer::I8, + IntTy::I16 => Integer::I16, + IntTy::I32 => Integer::I32, + IntTy::I64 => Integer::I64, + IntTy::I128 => Integer::I128, + }, + true, ), ), - chalk_ir::Scalar::Uint(i) => Layout::scalar( + ), + TyKind::Uint(i) => Layout::scalar( + dl, + scalar_unit( dl, - scalar_unit( - dl, - Primitive::Int( - match i { - UintTy::Usize => dl.ptr_sized_integer(), - UintTy::U8 => Integer::I8, - UintTy::U16 => Integer::I16, - UintTy::U32 => Integer::I32, - UintTy::U64 => Integer::I64, - UintTy::U128 => Integer::I128, - }, - false, - ), + Primitive::Int( + match i { + UintTy::Usize => dl.ptr_sized_integer(), + UintTy::U8 => Integer::I8, + UintTy::U16 => Integer::I16, + UintTy::U32 => Integer::I32, + UintTy::U64 => Integer::I64, + UintTy::U128 => Integer::I128, + }, + false, ), ), - chalk_ir::Scalar::Float(f) => Layout::scalar( + ), + TyKind::Float(f) => Layout::scalar( + dl, + scalar_unit( dl, - scalar_unit( - dl, - Primitive::Float(match f { - FloatTy::F16 => Float::F16, - FloatTy::F32 => Float::F32, - FloatTy::F64 => Float::F64, - FloatTy::F128 => Float::F128, - }), - ), + Primitive::Float(match f { + FloatTy::F16 => Float::F16, + FloatTy::F32 => Float::F32, + FloatTy::F64 => Float::F64, + FloatTy::F128 => Float::F128, + }), ), - }, - TyKind::Tuple(len, tys) => { - let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; + ), + TyKind::Tuple(tys) => { + let kind = + if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; let fields = tys - .iter(Interner) - .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone())) + .iter() + .map(|k| db.layout_of_ty_ns(k, trait_env.clone())) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); cx.calc.univariant(&fields, &ReprOptions::default(), kind)? } TyKind::Array(element, count) => { - let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; - let element = db.layout_of_ty(element.clone(), trait_env)?; + let count = try_const_usize(db, &count).ok_or(LayoutError::HasErrorConst)? as u64; + let element = db.layout_of_ty_ns(element, trait_env)?; cx.calc.array_like::<_, _, ()>(&element, Some(count))? } TyKind::Slice(element) => { - let element = db.layout_of_ty(element.clone(), trait_env)?; + let element = db.layout_of_ty_ns(element, trait_env)?; cx.calc.array_like::<_, _, ()>(&element, None)? } TyKind::Str => { @@ -260,18 +285,21 @@ pub fn layout_of_ty_query( cx.calc.array_like::<_, _, ()>(&Layout::scalar(dl, element), None)? } // Potentially-wide pointers. - TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => { + TyKind::Ref(_, pointee, _) | TyKind::RawPtr(pointee, _) => { let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO)); - if matches!(ty.kind(Interner), TyKind::Ref(..)) { + if matches!(ty.kind(), TyKind::Ref(..)) { data_ptr.valid_range_mut().start = 1; } + // FIXME(next-solver) // let pointee = tcx.normalize_erasing_regions(param_env, pointee); // if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { - // return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); + // return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); // } - let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone()); + let unsized_part = struct_tail_erasing_lifetimes(db, pointee); + // FIXME(next-solver) + /* if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) { unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { associated_ty_id: *id, @@ -280,11 +308,12 @@ pub fn layout_of_ty_query( .intern(Interner); } unsized_part = normalize(db, trait_env, unsized_part); - let metadata = match unsized_part.kind(Interner) { + */ + let metadata = match unsized_part.kind() { TyKind::Slice(_) | TyKind::Str => { scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false)) } - TyKind::Dyn(..) => { + TyKind::Dynamic(..) => { let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::ZERO)); vtable.valid_range_mut().start = 1; vtable @@ -299,97 +328,110 @@ pub fn layout_of_ty_query( LayoutData::scalar_pair(dl, data_ptr, metadata) } TyKind::Never => LayoutData::never_type(dl), - TyKind::FnDef(..) | TyKind::Dyn(_) | TyKind::Foreign(_) => { - let sized = matches!(kind, TyKind::FnDef(..)); - LayoutData::unit(dl, sized) - } - TyKind::Function(_) => { + TyKind::FnDef(..) => LayoutData::unit(dl, true), + TyKind::Dynamic(..) | TyKind::Foreign(_) => LayoutData::unit(dl, false), + TyKind::FnPtr(..) => { let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; Layout::scalar(dl, ptr) } - TyKind::OpaqueType(opaque_ty_id, _) => { - let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); - match impl_trait_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let infer = db.infer(func.into()); - return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); - } - crate::ImplTraitId::TypeAliasImplTrait(..) => { - return Err(LayoutError::NotImplemented); - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { - return Err(LayoutError::NotImplemented); + TyKind::Alias(_, ty) => match ty.def_id { + SolverDefId::TypeAliasId(_) => { + return Err(LayoutError::HasPlaceholder); + } + SolverDefId::InternedOpaqueTyId(opaque) => { + let impl_trait_id = db.lookup_intern_impl_trait_id(opaque); + match impl_trait_id { + crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { + let infer = db.infer(func.into()); + return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); + } + crate::ImplTraitId::TypeAliasImplTrait(..) => { + return Err(LayoutError::NotImplemented); + } + crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + return Err(LayoutError::NotImplemented); + } } } - } - TyKind::Closure(c, subst) => { - let InternedClosure(def, _) = db.lookup_intern_closure((*c).into()); - let infer = db.infer(def); - let (captures, _) = infer.closure_info(c); + _ => unreachable!(), + }, + TyKind::Closure(c, args) => { + let id = match c { + SolverDefId::InternedClosureId(id) => id, + _ => unreachable!(), + }; + let def = db.lookup_intern_closure(id); + let infer = db.infer(def.0); + let (captures, _) = infer.closure_info(&id.into()); let fields = captures .iter() .map(|it| { - db.layout_of_ty( - it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), - trait_env.clone(), - ) + let ty = + convert_binder_to_early_binder(interner, it.ty.to_nextsolver(interner)) + .instantiate(interner, args); + db.layout_of_ty_ns(ty, trait_env.clone()) }) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); cx.calc.univariant(&fields, &ReprOptions::default(), StructKind::AlwaysSized)? } - TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => { + + TyKind::Coroutine(_, _) + | TyKind::CoroutineWitness(_, _) + | TyKind::CoroutineClosure(_, _) => { return Err(LayoutError::NotImplemented); } - TyKind::Error => return Err(LayoutError::HasErrorType), - TyKind::AssociatedType(id, subst) => { - // Try again with `TyKind::Alias` to normalize the associated type. - // Usually we should not try to normalize `TyKind::AssociatedType`, but layout calculation is used - // in monomorphized MIR where this is okay. If outside monomorphization, this will lead to cycle, - // which we will recover from with an error. - let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { - associated_ty_id: *id, - substitution: subst.clone(), - })) - .intern(Interner); - return db.layout_of_ty(ty, trait_env); + + TyKind::Pat(_, _) | TyKind::UnsafeBinder(_) => { + return Err(LayoutError::NotImplemented); + } + + TyKind::Error(_) => return Err(LayoutError::HasErrorType), + TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) => { + return Err(LayoutError::HasPlaceholder); } - TyKind::Alias(_) - | TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder), }; Ok(Arc::new(result)) } pub(crate) fn layout_of_ty_cycle_result( _: &dyn HirDatabase, - _: Ty, + _: crate::Ty, + _: Arc, +) -> Result, LayoutError> { + Err(LayoutError::RecursiveTypeWithoutIndirection) +} + +pub(crate) fn layout_of_ty_ns_cycle_result<'db>( + _: &dyn HirDatabase, + _: Ty<'db>, _: Arc, ) -> Result, LayoutError> { Err(LayoutError::RecursiveTypeWithoutIndirection) } -fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { - match pointee.kind(Interner) { - &TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), ref subst) => { - let data = i.fields(db); +fn struct_tail_erasing_lifetimes<'a>(db: &'a dyn HirDatabase, pointee: Ty<'a>) -> Ty<'a> { + match pointee.kind() { + TyKind::Adt(def, args) => { + let struct_id = match def.inner().id { + AdtId::StructId(id) => id, + _ => return pointee, + }; + let data = struct_id.fields(db); let mut it = data.fields().iter().rev(); match it.next() { Some((f, _)) => { - let last_field_ty = field_ty(db, i.into(), f, subst); + let last_field_ty = field_ty(db, struct_id.into(), f, &args); struct_tail_erasing_lifetimes(db, last_field_ty) } None => pointee, } } - TyKind::Tuple(_, subst) => { - if let Some(last_field_ty) = - subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) - { - struct_tail_erasing_lifetimes(db, last_field_ty.clone()) + TyKind::Tuple(tys) => { + if let Some(last_field_ty) = tys.iter().last() { + struct_tail_erasing_lifetimes(db, last_field_ty) } else { pointee } @@ -398,13 +440,13 @@ fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { } } -fn field_ty( - db: &dyn HirDatabase, +fn field_ty<'a>( + db: &'a dyn HirDatabase, def: hir_def::VariantId, fd: LocalFieldId, - subst: &Substitution, -) -> Ty { - db.field_types(def)[fd].clone().substitute(Interner, subst) + args: &GenericArgs<'a>, +) -> Ty<'a> { + db.field_types_ns(def)[fd].instantiate(DbInterner::new_with(db, None, None), args) } fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 3f310c26ec14a..2fa01b6b41abc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -4,10 +4,10 @@ use std::{cmp, ops::Bound}; use hir_def::{ AdtId, VariantId, - layout::{Integer, ReprOptions, TargetDataLayout}, signatures::{StructFlags, VariantFields}, }; use intern::sym; +use rustc_abi::{Integer, ReprOptions, TargetDataLayout}; use rustc_index::IndexVec; use smallvec::SmallVec; use triomphe::Arc; @@ -15,16 +15,25 @@ use triomphe::Arc; use crate::{ Substitution, TraitEnvironment, db::HirDatabase, - layout::{Layout, LayoutError, field_ty}, + layout::{Layout, LayoutCx, LayoutError, field_ty}, + next_solver::{DbInterner, GenericArgs, mapping::ChalkToNextSolver}, }; -use super::LayoutCx; - pub fn layout_of_adt_query( db: &dyn HirDatabase, def: AdtId, subst: Substitution, trait_env: Arc, +) -> Result, LayoutError> { + let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); + db.layout_of_adt_ns(def, subst.to_nextsolver(interner), trait_env) +} + +pub fn layout_of_adt_ns_query<'db>( + db: &'db dyn HirDatabase, + def: AdtId, + args: GenericArgs<'db>, + trait_env: Arc, ) -> Result, LayoutError> { let krate = trait_env.krate; let Ok(target) = db.target_data_layout(krate) else { @@ -35,7 +44,7 @@ pub fn layout_of_adt_query( let handle_variant = |def: VariantId, var: &VariantFields| { var.fields() .iter() - .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone())) + .map(|(fd, _)| db.layout_of_ty_ns(field_ty(db, def, fd, &args), trait_env.clone())) .collect::, _>>() }; let (variants, repr, is_special_no_niche) = match def { @@ -96,6 +105,24 @@ pub fn layout_of_adt_query( Ok(Arc::new(result)) } +pub(crate) fn layout_of_adt_cycle_result( + _: &dyn HirDatabase, + _: AdtId, + _: Substitution, + _: Arc, +) -> Result, LayoutError> { + Err(LayoutError::RecursiveTypeWithoutIndirection) +} + +pub(crate) fn layout_of_adt_ns_cycle_result<'db>( + _: &'db dyn HirDatabase, + _def: AdtId, + _args: GenericArgs<'db>, + _trait_env: Arc, +) -> Result, LayoutError> { + Err(LayoutError::RecursiveTypeWithoutIndirection) +} + fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, Bound) { let attrs = db.attrs(def.into()); let get = |name| { @@ -120,15 +147,6 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, (get(sym::rustc_layout_scalar_valid_range_start), get(sym::rustc_layout_scalar_valid_range_end)) } -pub(crate) fn layout_of_adt_cycle_result( - _: &dyn HirDatabase, - _: AdtId, - _: Substitution, - _: Arc, -) -> Result, LayoutError> { - Err(LayoutError::RecursiveTypeWithoutIndirection) -} - /// Finds the appropriate Integer type and signedness for the given /// signed discriminant range and `#[repr]` attribute. /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index b3bc226ec93c7..93f2e123dca58 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -11,6 +11,7 @@ use crate::{ Interner, Substitution, db::HirDatabase, layout::{Layout, LayoutError}, + setup_tracing, test_db::TestDB, }; @@ -29,6 +30,7 @@ fn eval_goal( #[rust_analyzer::rust_fixture] ra_fixture: &str, minicore: &str, ) -> Result, LayoutError> { + let _tracing = setup_tracing(); let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\n{ra_fixture}", @@ -97,6 +99,7 @@ fn eval_expr( #[rust_analyzer::rust_fixture] ra_fixture: &str, minicore: &str, ) -> Result, LayoutError> { + let _tracing = setup_tracing(); let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\nfn main(){{let goal = {{{ra_fixture}}};}}", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index e787fd9b1e584..2b0dc931eaf4a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -21,6 +21,24 @@ extern crate rustc_pattern_analysis; #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_ast_ir; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_ast_ir as rustc_ast_ir; + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_type_ir; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_type_ir as rustc_type_ir; + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_next_trait_solver; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; + mod builder; mod chalk_db; mod chalk_ext; @@ -29,13 +47,16 @@ mod infer; mod inhabitedness; mod interner; mod lower; +mod lower_nextsolver; mod mapping; +pub mod next_solver; mod target_feature; mod tls; mod utils; pub mod autoderef; pub mod consteval; +pub mod consteval_nextsolver; pub mod db; pub mod diagnostics; pub mod display; @@ -57,7 +78,7 @@ mod variance; use std::hash::Hash; use chalk_ir::{ - NoSolution, + NoSolution, VariableKinds, fold::{Shift, TypeFoldable}, interner::HasInterner, }; @@ -121,9 +142,9 @@ pub type ClosureId = chalk_ir::ClosureId; pub type OpaqueTyId = chalk_ir::OpaqueTyId; pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; -pub type VariableKind = chalk_ir::VariableKind; -pub type VariableKinds = chalk_ir::VariableKinds; pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds; + +pub(crate) type VariableKind = chalk_ir::VariableKind; /// Represents generic parameters and an item bound by them. When the item has parent, the binders /// also contain the generic parameters for its parent. See chalk's documentation for details. /// @@ -145,52 +166,45 @@ pub type GenericArgData = chalk_ir::GenericArgData; pub type Ty = chalk_ir::Ty; pub type TyKind = chalk_ir::TyKind; pub type TypeFlags = chalk_ir::TypeFlags; -pub type DynTy = chalk_ir::DynTy; +pub(crate) type DynTy = chalk_ir::DynTy; pub type FnPointer = chalk_ir::FnPointer; -// pub type FnSubst = chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor -pub use chalk_ir::FnSubst; -pub type ProjectionTy = chalk_ir::ProjectionTy; +pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor + pub type AliasTy = chalk_ir::AliasTy; -pub type OpaqueTy = chalk_ir::OpaqueTy; -pub type InferenceVar = chalk_ir::InferenceVar; -pub type Lifetime = chalk_ir::Lifetime; -pub type LifetimeData = chalk_ir::LifetimeData; -pub type LifetimeOutlives = chalk_ir::LifetimeOutlives; +pub type ProjectionTy = chalk_ir::ProjectionTy; +pub(crate) type OpaqueTy = chalk_ir::OpaqueTy; +pub(crate) type InferenceVar = chalk_ir::InferenceVar; + +pub(crate) type Lifetime = chalk_ir::Lifetime; +pub(crate) type LifetimeData = chalk_ir::LifetimeData; +pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives; -pub type Const = chalk_ir::Const; -pub type ConstData = chalk_ir::ConstData; pub type ConstValue = chalk_ir::ConstValue; -pub type ConcreteConst = chalk_ir::ConcreteConst; -pub type ChalkTraitId = chalk_ir::TraitId; +pub type Const = chalk_ir::Const; +pub(crate) type ConstData = chalk_ir::ConstData; +pub(crate) type ConcreteConst = chalk_ir::ConcreteConst; + pub type TraitRef = chalk_ir::TraitRef; pub type QuantifiedWhereClause = Binders; -pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses; pub type Canonical = chalk_ir::Canonical; -pub type FnSig = chalk_ir::FnSig; +pub(crate) type ChalkTraitId = chalk_ir::TraitId; +pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses; + +pub(crate) type FnSig = chalk_ir::FnSig; pub type InEnvironment = chalk_ir::InEnvironment; -pub type Environment = chalk_ir::Environment; -pub type DomainGoal = chalk_ir::DomainGoal; -pub type Goal = chalk_ir::Goal; pub type AliasEq = chalk_ir::AliasEq; -pub type Solution = chalk_solve::Solution; -pub type Constraint = chalk_ir::Constraint; -pub type Constraints = chalk_ir::Constraints; -pub type ConstrainedSubst = chalk_ir::ConstrainedSubst; -pub type Guidance = chalk_solve::Guidance; pub type WhereClause = chalk_ir::WhereClause; -pub type CanonicalVarKind = chalk_ir::CanonicalVarKind; -pub type GoalData = chalk_ir::GoalData; -pub type Goals = chalk_ir::Goals; -pub type ProgramClauseData = chalk_ir::ProgramClauseData; -pub type ProgramClause = chalk_ir::ProgramClause; -pub type ProgramClauses = chalk_ir::ProgramClauses; -pub type TyData = chalk_ir::TyData; -pub type Variances = chalk_ir::Variances; +pub(crate) type DomainGoal = chalk_ir::DomainGoal; +pub(crate) type Goal = chalk_ir::Goal; + +pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind; +pub(crate) type GoalData = chalk_ir::GoalData; +pub(crate) type ProgramClause = chalk_ir::ProgramClause; /// A constant can have reference to other things. Memory map job is holding /// the necessary bits of memory of the const eval session to keep the constant @@ -311,30 +325,11 @@ where Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) } -pub(crate) fn make_type_and_const_binders>( - which_is_const: impl Iterator>, - value: T, -) -> Binders { - Binders::new( - VariableKinds::from_iter( - Interner, - which_is_const.map(|x| { - if let Some(ty) = x { - chalk_ir::VariableKind::Const(ty) - } else { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - }), - ), - value, - ) -} - pub(crate) fn make_single_type_binders>( value: T, ) -> Binders { Binders::new( - VariableKinds::from_iter( + chalk_ir::VariableKinds::from_iter( Interner, std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)), ), @@ -353,7 +348,7 @@ pub(crate) fn make_binders>( pub(crate) fn variable_kinds_from_iter( db: &dyn HirDatabase, iter: impl Iterator, -) -> VariableKinds { +) -> VariableKinds { VariableKinds::from_iter( Interner, iter.map(|x| match x { @@ -918,7 +913,7 @@ pub fn callable_sig_from_fn_trait( let obligation = InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() }; let canonical = table.canonicalize(obligation.clone()); - if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { + if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() { table.register_obligation(obligation.goal); let return_ty = table.normalize_projection_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { @@ -929,7 +924,7 @@ pub fn callable_sig_from_fn_trait( environment: trait_env.clone(), }; let canonical = table.canonicalize(obligation.clone()); - if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { + if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() { let ret_ty = table.resolve_completely(return_ty); let args_ty = table.resolve_completely(args_ty); let params = args_ty @@ -985,7 +980,7 @@ impl TypeVisitor for PlaceholderCollector<'_> { outer_binder: DebruijnIndex, ) -> std::ops::ControlFlow { let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER; - let TyData { kind, flags } = ty.data(Interner); + let chalk_ir::TyData { kind, flags } = ty.data(Interner); if let TyKind::Placeholder(idx) = kind { self.collect(*idx); @@ -1045,3 +1040,25 @@ pub(crate) enum DeclOrigin { pub(crate) struct DeclContext { pub(crate) origin: DeclOrigin, } + +pub fn setup_tracing() -> Option { + use std::env; + use std::sync::LazyLock; + use tracing_subscriber::{Registry, layer::SubscriberExt}; + use tracing_tree::HierarchicalLayer; + + static ENABLE: LazyLock = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok()); + if !*ENABLE { + return None; + } + + let filter: tracing_subscriber::filter::Targets = + env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); + let layer = HierarchicalLayer::default() + .with_indent_lines(true) + .with_ansi(false) + .with_indent_amount(2) + .with_writer(std::io::stderr); + let subscriber = Registry::default().with(filter).with(layer); + Some(tracing::subscriber::set_default(subscriber)) +} 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 afee9606bd5f8..7b6b3c3f8181a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -46,9 +46,9 @@ use stdx::{impl_from, never}; use triomphe::{Arc, ThinArc}; use crate::{ - AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, - FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, - LifetimeOutlives, PolyFnSig, ProgramClause, QuantifiedWhereClause, QuantifiedWhereClauses, + AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi, + FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, + LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, all_super_traits, consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, @@ -81,7 +81,7 @@ impl ImplTraitLoweringState { } } -pub(crate) struct PathDiagnosticCallbackData(TypeRefId); +pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); #[derive(Debug, Clone)] pub enum LifetimeElisionKind { @@ -889,7 +889,7 @@ fn named_associated_type_shorthand_candidates( pub(crate) type Diagnostics = Option>; -fn create_diagnostics(diagnostics: Vec) -> Diagnostics { +pub(crate) fn create_diagnostics(diagnostics: Vec) -> Diagnostics { (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) } @@ -1105,8 +1105,9 @@ pub(crate) fn trait_environment_query( traits_in_scope .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); } - let program_clause: chalk_ir::ProgramClause = pred.cast(Interner); - clauses.push(program_clause.into_from_env_clause(Interner)); + let program_clause: Binders = + pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner)); + clauses.push(program_clause); } } } @@ -1119,7 +1120,10 @@ pub(crate) fn trait_environment_query( let substs = TyBuilder::placeholder_subst(db, trait_id); let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; let pred = WhereClause::Implemented(trait_ref); - clauses.push(pred.cast::(Interner).into_from_env_clause(Interner)); + clauses.push(Binders::empty( + Interner, + pred.cast::(Interner).into_from_env_goal(Interner), + )); } let subst = generics.placeholder_subst(db); @@ -1128,15 +1132,30 @@ pub(crate) fn trait_environment_query( if let Some(implicitly_sized_clauses) = implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) { - clauses.extend( - implicitly_sized_clauses.map(|pred| { - pred.cast::(Interner).into_from_env_clause(Interner) - }), - ); + clauses.extend(implicitly_sized_clauses.map(|pred| { + Binders::empty( + Interner, + pred.into_from_env_goal(Interner).cast::(Interner), + ) + })); }; } - let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); + let clauses = chalk_ir::ProgramClauses::from_iter( + Interner, + clauses.into_iter().map(|g| { + chalk_ir::ProgramClause::new( + Interner, + chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication { + consequence: g, + conditions: chalk_ir::Goals::empty(Interner), + constraints: chalk_ir::Constraints::empty(Interner), + priority: chalk_ir::ClausePriority::High, + })), + ) + }), + ); + let env = chalk_ir::Environment { clauses }; TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) } @@ -1177,7 +1196,7 @@ pub(crate) fn generic_predicates_without_parent_with_diagnostics_query( } /// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent +/// with a given filter fn generic_predicates_filtered_by( db: &dyn HirDatabase, def: GenericDefId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs new file mode 100644 index 0000000000000..24bda43ca634f --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -0,0 +1,1609 @@ +//! Methods for lowering the HIR to types. There are two main cases here: +//! +//! - Lowering a type reference like `&usize` or `Option` to a +//! type: The entry point for this is `TyLoweringContext::lower_ty`. +//! - Building the type for an item: This happens through the `ty` query. +//! +//! This usually involves resolving names, collecting generic arguments etc. +#![allow(unused)] +// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir +pub(crate) mod path; + +use std::{ + cell::OnceCell, + iter, mem, + ops::{self, Not as _}, +}; + +use base_db::Crate; +use either::Either; +use hir_def::{ + AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId, + GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TypeAliasId, + TypeOrConstParamId, VariantId, + expr_store::{ + ExpressionStore, + path::{GenericArg, Path}, + }, + hir::generics::{TypeOrConstParamData, WherePredicate}, + lang_item::LangItem, + resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, + signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, + type_ref::{ + ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, + TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, + }, +}; +use hir_expand::name::Name; +use intern::sym; +use la_arena::{Arena, ArenaMap, Idx}; +use path::{PathDiagnosticCallback, PathLoweringContext, builtin}; +use rustc_ast_ir::Mutability; +use rustc_hash::FxHashSet; +use rustc_pattern_analysis::Captures; +use rustc_type_ir::{ + AliasTyKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, + ExistentialTraitRef, FnSig, OutlivesPredicate, + TyKind::{self}, + TypeVisitableExt, + inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, +}; +use salsa::plumbing::AsId; +use stdx::never; +use triomphe::Arc; + +use crate::{ + FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic, + TyLoweringDiagnosticKind, + consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic}, + db::HirDatabase, + generics::{Generics, generics, trait_self_param_idx}, + lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics}, + next_solver::{ + AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, + BoundVarKind, BoundVarKinds, Clause, Const, DbInterner, EarlyBinder, EarlyParamRegion, + ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, + TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind, mapping::ChalkToNextSolver, + }, +}; + +#[derive(PartialEq, Eq, Debug, Hash)] +pub struct ImplTraits<'db> { + pub(crate) impl_traits: Arena>, +} + +#[derive(PartialEq, Eq, Debug, Hash)] +pub(crate) struct ImplTrait<'db> { + pub(crate) predicates: Vec>, +} + +pub(crate) type ImplTraitIdx<'db> = Idx>; + +#[derive(Debug, Default)] +struct ImplTraitLoweringState<'db> { + /// When turning `impl Trait` into opaque types, we have to collect the + /// bounds at the same time to get the IDs correct (without becoming too + /// complicated). + mode: ImplTraitLoweringMode, + // This is structured as a struct with fields and not as an enum because it helps with the borrow checker. + opaque_type_data: Arena>, + param_and_variable_counter: u16, +} +impl<'db> ImplTraitLoweringState<'db> { + fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> { + Self { mode, opaque_type_data: Arena::new(), param_and_variable_counter: 0 } + } +} + +#[derive(Debug, Clone)] +pub(crate) enum LifetimeElisionKind<'db> { + /// Create a new anonymous lifetime parameter and reference it. + /// + /// If `report_in_path`, report an error when encountering lifetime elision in a path: + /// ```compile_fail + /// struct Foo<'a> { x: &'a () } + /// async fn foo(x: Foo) {} + /// ``` + /// + /// Note: the error should not trigger when the elided lifetime is in a pattern or + /// expression-position path: + /// ``` + /// struct Foo<'a> { x: &'a () } + /// async fn foo(Foo { x: _ }: Foo<'_>) {} + /// ``` + AnonymousCreateParameter { report_in_path: bool }, + + /// Replace all anonymous lifetimes by provided lifetime. + Elided(Region<'db>), + + /// Give a hard error when either `&` or `'_` is written. Used to + /// rule out things like `where T: Foo<'_>`. Does not imply an + /// error on default object bounds (e.g., `Box`). + AnonymousReportError, + + /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, + /// otherwise give a warning that the previous behavior of introducing a new early-bound + /// lifetime is a bug and will be removed (if `only_lint` is enabled). + StaticIfNoLifetimeInScope { only_lint: bool }, + + /// Signal we cannot find which should be the anonymous lifetime. + ElisionFailure, + + /// Infer all elided lifetimes. + Infer, +} + +impl<'db> LifetimeElisionKind<'db> { + #[inline] + pub(crate) fn for_const( + interner: DbInterner<'db>, + const_parent: ItemContainerId, + ) -> LifetimeElisionKind<'db> { + match const_parent { + ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => { + LifetimeElisionKind::Elided(Region::new_static(interner)) + } + ItemContainerId::ImplId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true } + } + ItemContainerId::TraitId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false } + } + } + } + + #[inline] + pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> { + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() } + } + + #[inline] + pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> { + // FIXME: We should use the elided lifetime here, or `ElisionFailure`. + LifetimeElisionKind::Elided(Region::error(interner)) + } +} + +#[derive(Debug)] +pub(crate) struct TyLoweringContext<'db, 'a> { + pub db: &'db dyn HirDatabase, + interner: DbInterner<'db>, + resolver: &'a Resolver<'db>, + store: &'a ExpressionStore, + def: GenericDefId, + generics: OnceCell, + in_binders: DebruijnIndex, + impl_trait_mode: ImplTraitLoweringState<'db>, + /// Tracks types with explicit `?Sized` bounds. + pub(crate) unsized_types: FxHashSet>, + pub(crate) diagnostics: Vec, + lifetime_elision: LifetimeElisionKind<'db>, +} + +impl<'db, 'a> TyLoweringContext<'db, 'a> { + pub(crate) fn new( + db: &'db dyn HirDatabase, + resolver: &'a Resolver<'db>, + store: &'a ExpressionStore, + def: GenericDefId, + lifetime_elision: LifetimeElisionKind<'db>, + ) -> Self { + let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); + let in_binders = DebruijnIndex::ZERO; + Self { + db, + interner: DbInterner::new_with(db, Some(resolver.krate()), None), + resolver, + def, + generics: Default::default(), + store, + in_binders, + impl_trait_mode, + unsized_types: FxHashSet::default(), + diagnostics: Vec::new(), + lifetime_elision, + } + } + + pub(crate) fn with_debruijn( + &mut self, + debruijn: DebruijnIndex, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, + ) -> T { + let old_debruijn = mem::replace(&mut self.in_binders, debruijn); + let result = f(self); + self.in_binders = old_debruijn; + result + } + + pub(crate) fn with_shifted_in( + &mut self, + debruijn: DebruijnIndex, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, + ) -> T { + self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f) + } + + pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { + Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } + } + + pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self { + self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode); + self + } + + pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { + self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +pub(crate) enum ImplTraitLoweringMode { + /// `impl Trait` gets lowered into an opaque type that doesn't unify with + /// anything except itself. This is used in places where values flow 'out', + /// i.e. for arguments of the function we're currently checking, and return + /// types of functions we're calling. + Opaque, + /// `impl Trait` is disallowed and will be an error. + #[default] + Disallowed, +} + +impl<'db, 'a> TyLoweringContext<'db, 'a> { + pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { + self.lower_ty_ext(type_ref).0 + } + + pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty<'db>) -> Const<'db> { + let const_ref = &self.store[const_ref.expr]; + match const_ref { + hir_def::hir::Expr::Path(path) => { + path_to_const(self.db, self.resolver, path, || self.generics(), const_type) + .unwrap_or_else(|| unknown_const(const_type)) + } + hir_def::hir::Expr::Literal(literal) => intern_const_ref( + self.db, + &match *literal { + hir_def::hir::Literal::Float(_, _) + | hir_def::hir::Literal::String(_) + | hir_def::hir::Literal::ByteString(_) + | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown, + hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c), + hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b), + hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val), + hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val), + }, + const_type, + self.resolver.krate(), + ), + _ => unknown_const(const_type), + } + } + + pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> { + path_to_const(self.db, self.resolver, path, || self.generics(), const_type) + .unwrap_or_else(|| unknown_const(const_type)) + } + + fn generics(&self) -> &Generics { + self.generics.get_or_init(|| generics(self.db, self.def)) + } + + #[tracing::instrument(skip(self), ret)] + pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { + let interner = self.interner; + let mut res = None; + let type_ref = &self.store[type_ref_id]; + tracing::debug!(?type_ref); + let ty = match type_ref { + TypeRef::Never => Ty::new(interner, TyKind::Never), + TypeRef::Tuple(inner) => { + let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr)); + Ty::new_tup_from_iter(interner, inner_tys) + } + TypeRef::Path(path) => { + let (ty, res_) = + self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id)); + res = res_; + ty + } + &TypeRef::TypeParam(type_param_id) => { + res = Some(TypeNs::GenericParam(type_param_id)); + + let generics = self.generics(); + let (idx, data) = + generics.type_or_const_param(type_param_id.into()).expect("matching generics"); + let type_data = match data { + TypeOrConstParamData::TypeParamData(ty) => ty, + _ => unreachable!(), + }; + Ty::new_param( + self.interner, + idx as u32, + type_data + .name + .as_ref() + .map_or_else(|| sym::MISSING_NAME.clone(), |d| d.symbol().clone()), + ) + } + &TypeRef::RawPtr(inner, mutability) => { + let inner_ty = self.lower_ty(inner); + Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability))) + } + TypeRef::Array(array) => { + let inner_ty = self.lower_ty(array.ty); + let const_len = self.lower_const(&array.len, Ty::new_usize(interner)); + Ty::new_array_with_const_len(interner, inner_ty, const_len) + } + &TypeRef::Slice(inner) => { + let inner_ty = self.lower_ty(inner); + Ty::new_slice(interner, inner_ty) + } + TypeRef::Reference(ref_) => { + let inner_ty = self.lower_ty(ref_.ty); + // FIXME: It should infer the eldided lifetimes instead of stubbing with error + let lifetime = ref_ + .lifetime + .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr)); + Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability)) + } + TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed), + TypeRef::Fn(fn_) => { + let substs = self.with_shifted_in( + DebruijnIndex::from_u32(1), + |ctx: &mut TyLoweringContext<'_, '_>| { + Tys::new_from_iter( + interner, + fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)), + ) + }, + ); + Ty::new_fn_ptr( + interner, + Binder::dummy(FnSig { + abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), + safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, + c_variadic: fn_.is_varargs, + inputs_and_output: substs, + }), + ) + } + TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), + TypeRef::ImplTrait(bounds) => { + match self.impl_trait_mode.mode { + ImplTraitLoweringMode::Opaque => { + let origin = match self.resolver.generic_def() { + Some(GenericDefId::FunctionId(it)) => Either::Left(it), + Some(GenericDefId::TypeAliasId(it)) => Either::Right(it), + _ => panic!( + "opaque impl trait lowering must be in function or type alias" + ), + }; + + // this dance is to make sure the data is in the right + // place even if we encounter more opaque types while + // lowering the bounds + let idx = self + .impl_trait_mode + .opaque_type_data + .alloc(ImplTrait { predicates: Vec::default() }); + + // FIXME(next-solver): this from_raw/into_raw dance isn't nice, but it's minimal + let impl_trait_id = origin.either( + |f| ImplTraitId::ReturnTypeImplTrait(f, Idx::from_raw(idx.into_raw())), + |a| ImplTraitId::TypeAliasImplTrait(a, Idx::from_raw(idx.into_raw())), + ); + let opaque_ty_id: SolverDefId = + self.db.intern_impl_trait_id(impl_trait_id).into(); + + // We don't want to lower the bounds inside the binders + // we're currently in, because they don't end up inside + // those binders. E.g. when we have `impl Trait>`, the `impl OtherTrait` can't refer + // to the self parameter from `impl Trait`, and the + // bounds aren't actually stored nested within each + // other, but separately. So if the `T` refers to a type + // parameter of the outer function, it's just one binder + // away instead of two. + let actual_opaque_type_data = self + .with_debruijn(DebruijnIndex::ZERO, |ctx| { + ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate()) + }); + self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; + + let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id); + Ty::new_alias( + self.interner, + AliasTyKind::Opaque, + AliasTy::new_from_args(self.interner, opaque_ty_id, args), + ) + } + ImplTraitLoweringMode::Disallowed => { + // FIXME: report error + Ty::new_error(self.interner, ErrorGuaranteed) + } + } + } + TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed), + }; + (ty, res) + } + + /// This is only for `generic_predicates_for_param`, where we can't just + /// lower the self types of the predicates since that could lead to cycles. + /// So we just check here if the `type_ref` resolves to a generic param, and which. + fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option { + let type_ref = &self.store[type_ref]; + let path = match type_ref { + TypeRef::Path(path) => path, + &TypeRef::TypeParam(idx) => return Some(idx.into()), + _ => return None, + }; + if path.type_anchor().is_some() { + return None; + } + if path.segments().len() > 1 { + return None; + } + let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) { + Some((it, None, _)) => it, + _ => return None, + }; + match resolution { + TypeNs::GenericParam(param_id) => Some(param_id.into()), + _ => None, + } + } + + #[inline] + fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static, 'db> { + PathDiagnosticCallback { + data: Either::Left(PathDiagnosticCallbackData(type_ref)), + callback: |data, this, diag| { + let type_ref = data.as_ref().left().unwrap().0; + this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag)) + }, + } + } + + #[inline] + fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> { + PathLoweringContext::new( + self, + Self::on_path_diagnostic_callback(path_id.type_ref()), + &self.store[path_id], + ) + } + + pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option) { + // Resolve the path (in type namespace) + if let Some(type_ref) = path.type_anchor() { + let (ty, res) = self.lower_ty_ext(type_ref); + let mut ctx = self.at_path(path_id); + return ctx.lower_ty_relative_path(ty, res); + } + + let mut ctx = self.at_path(path_id); + let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() { + Some(it) => it, + None => return (Ty::new_error(self.interner, ErrorGuaranteed), None), + }; + + if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { + // trait object type without dyn + let bound = TypeBound::Path(path_id, TraitBoundModifier::None); + let ty = self.lower_dyn_trait(&[bound]); + return (ty, None); + } + + ctx.lower_partly_resolved_path(resolution, false) + } + + fn lower_trait_ref_from_path( + &mut self, + path_id: PathId, + explicit_self_ty: Ty<'db>, + ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> { + let mut ctx = self.at_path(path_id); + let resolved = match ctx.resolve_path_in_type_ns_fully()? { + // FIXME(trait_alias): We need to handle trait alias here. + TypeNs::TraitId(tr) => tr, + _ => return None, + }; + Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty), ctx)) + } + + fn lower_trait_ref( + &mut self, + trait_ref: &HirTraitRef, + explicit_self_ty: Ty<'db>, + ) -> Option> { + self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0) + } + + pub(crate) fn lower_where_predicate<'b>( + &'b mut self, + where_predicate: &'b WherePredicate, + ignore_bindings: bool, + generics: &Generics, + predicate_filter: PredicateFilter, + ) -> impl Iterator> + use<'a, 'b, 'db> { + match where_predicate { + WherePredicate::ForLifetime { target, bound, .. } + | WherePredicate::TypeBound { target, bound } => { + if let PredicateFilter::SelfTrait = predicate_filter { + let target_type = &self.store[*target]; + let self_type = 'is_self: { + if let TypeRef::Path(path) = target_type + && path.is_self_type() + { + break 'is_self true; + } + if let TypeRef::TypeParam(param) = target_type + && generics[param.local_id()].is_trait_self() + { + break 'is_self true; + } + false + }; + if !self_type { + return Either::Left(Either::Left(iter::empty())); + } + } + let self_ty = self.lower_ty(*target); + Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings))) + } + &WherePredicate::Lifetime { bound, target } => { + Either::Right(iter::once(Clause(Predicate::new( + self.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate( + self.lower_lifetime(bound), + self.lower_lifetime(target), + )), + )), + )))) + } + } + .into_iter() + } + + pub(crate) fn lower_type_bound<'b>( + &'b mut self, + bound: &'b TypeBound, + self_ty: Ty<'db>, + ignore_bindings: bool, + ) -> impl Iterator> + use<'b, 'a, 'db> { + let interner = self.interner; + let mut assoc_bounds = None; + let mut clause = None; + match bound { + &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + // FIXME Don't silently drop the hrtb lifetimes here + if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { + // 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| SolverDefId::TraitId(it) == trait_ref.def_id) { + // Ignore this bound + } else if pointee_sized + .is_some_and(|it| SolverDefId::TraitId(it) == trait_ref.def_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); + } + clause = Some(Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + ))); + } + } + } + &TypeBound::Path(path, TraitBoundModifier::Maybe) => { + let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate()); + // Don't lower associated type bindings as the only possible relaxed trait bound + // `?Sized` has no of them. + // If we got another trait here ignore the bound completely. + let trait_id = + self.lower_trait_ref_from_path(path, self_ty).map(|(trait_ref, _)| { + match trait_ref.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + } + }); + if trait_id == sized_trait { + self.unsized_types.insert(self_ty); + } + } + &TypeBound::Lifetime(l) => { + let lifetime = self.lower_lifetime(l); + clause = Some(Clause(Predicate::new( + self.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate( + self_ty, lifetime, + )), + )), + ))); + } + TypeBound::Use(_) | TypeBound::Error => {} + } + clause.into_iter().chain(assoc_bounds.into_iter().flatten()) + } + + fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { + let interner = self.interner; + // FIXME: we should never create non-existential predicates in the first place + // For now, use an error type so we don't run into dummy binder issues + let self_ty = Ty::new_error(interner, ErrorGuaranteed); + // INVARIANT: The principal trait bound, if present, must come first. Others may be in any + // order but should be in the same order for the same set but possibly different order of + // bounds in the input. + // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. + // These invariants are utilized by `TyExt::dyn_trait()` and chalk. + let mut lifetime = None; + let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { + let mut lowered_bounds: Vec< + rustc_type_ir::Binder, ExistentialPredicate>>, + > = Vec::new(); + for b in bounds { + let db = ctx.db; + ctx.lower_type_bound(b, self_ty, false).for_each(|b| { + if let Some(bound) = b + .kind() + .map_bound(|c| match c { + rustc_type_ir::ClauseKind::Trait(t) => { + let id = t.def_id(); + let id = match id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let is_auto = + db.trait_signature(id).flags.contains(TraitFlags::AUTO); + if is_auto { + Some(ExistentialPredicate::AutoTrait(t.def_id())) + } else { + Some(ExistentialPredicate::Trait( + ExistentialTraitRef::new_from_args( + interner, + t.def_id(), + GenericArgs::new_from_iter( + interner, + t.trait_ref.args.iter().skip(1), + ), + ), + )) + } + } + rustc_type_ir::ClauseKind::Projection(p) => { + Some(ExistentialPredicate::Projection( + ExistentialProjection::new_from_args( + interner, + p.def_id(), + GenericArgs::new_from_iter( + interner, + p.projection_term.args.iter().skip(1), + ), + p.term, + ), + )) + } + rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => { + lifetime = Some(outlives_predicate.1); + None + } + rustc_type_ir::ClauseKind::RegionOutlives(_) + | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) + | rustc_type_ir::ClauseKind::WellFormed(_) + | rustc_type_ir::ClauseKind::ConstEvaluatable(_) + | rustc_type_ir::ClauseKind::HostEffect(_) + | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), + }) + .transpose() + { + lowered_bounds.push(bound); + } + }) + } + + let mut multiple_regular_traits = false; + let mut multiple_same_projection = false; + lowered_bounds.sort_unstable_by(|lhs, rhs| { + use std::cmp::Ordering; + match ((*lhs).skip_binder(), (*rhs).skip_binder()) { + (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => { + multiple_regular_traits = true; + // Order doesn't matter - we error + Ordering::Equal + } + ( + ExistentialPredicate::AutoTrait(lhs_id), + ExistentialPredicate::AutoTrait(rhs_id), + ) => { + let lhs_id = match lhs_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let rhs_id = match rhs_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + lhs_id.cmp(&rhs_id) + } + (ExistentialPredicate::Trait(_), _) => Ordering::Less, + (_, ExistentialPredicate::Trait(_)) => Ordering::Greater, + (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less, + (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater, + ( + ExistentialPredicate::Projection(lhs), + ExistentialPredicate::Projection(rhs), + ) => { + let lhs_id = match lhs.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), + }; + let rhs_id = match rhs.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), + }; + // We only compare the `associated_ty_id`s. We shouldn't have + // multiple bounds for an associated type in the correct Rust code, + // and if we do, we error out. + if lhs_id == rhs_id { + multiple_same_projection = true; + } + lhs_id.as_id().index().cmp(&rhs_id.as_id().index()) + } + } + }); + + if multiple_regular_traits || multiple_same_projection { + return None; + } + + if !lowered_bounds.first().map_or(false, |b| { + matches!( + b.as_ref().skip_binder(), + ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_) + ) + }) { + return None; + } + + // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the + // bounds. We shouldn't have repeated elements besides auto traits at this point. + lowered_bounds.dedup(); + + Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds)) + }); + + if let Some(bounds) = bounds { + let region = match lifetime { + Some(it) => match it.kind() { + rustc_type_ir::RegionKind::ReBound(db, var) => Region::new_bound( + self.interner, + db.shifted_out_to_binder(DebruijnIndex::from_u32(2)), + var, + ), + _ => it, + }, + None => Region::new_static(self.interner), + }; + Ty::new_dynamic(self.interner, bounds, region, rustc_type_ir::DynKind::Dyn) + } else { + // FIXME: report error + // (additional non-auto traits, associated type rebound, or no resolved trait) + Ty::new_error(self.interner, ErrorGuaranteed) + } + } + + fn lower_impl_trait( + &mut self, + def_id: SolverDefId, + bounds: &[TypeBound], + krate: Crate, + ) -> ImplTrait<'db> { + let interner = self.interner; + cov_mark::hit!(lower_rpit); + let args = GenericArgs::identity_for_item(interner, def_id); + let self_ty = Ty::new_alias( + self.interner, + rustc_type_ir::AliasTyKind::Opaque, + AliasTy::new_from_args(interner, def_id, args), + ); + let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { + let mut predicates = Vec::new(); + for b in bounds { + predicates.extend(ctx.lower_type_bound(b, self_ty, false)); + } + + if !ctx.unsized_types.contains(&self_ty) { + let sized_trait = LangItem::Sized.resolve_trait(self.db, krate); + let sized_clause = sized_trait.map(|trait_id| { + let trait_ref = TraitRef::new_from_args( + interner, + trait_id.into(), + GenericArgs::new_from_iter(interner, [self_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) + }); + predicates.extend(sized_clause); + } + predicates.shrink_to_fit(); + predicates + }); + ImplTrait { predicates } + } + + pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Region<'db> { + match self.resolver.resolve_lifetime(&self.store[lifetime]) { + Some(resolution) => match resolution { + LifetimeNs::Static => Region::new_static(self.interner), + LifetimeNs::LifetimeParam(id) => { + let idx = match self.generics().lifetime_idx(id) { + None => return Region::error(self.interner), + Some(idx) => idx, + }; + Region::new_early_param(self.interner, EarlyParamRegion { index: idx as u32 }) + } + }, + None => Region::error(self.interner), + } + } +} + +pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability { + match m { + hir_def::type_ref::Mutability::Shared => Mutability::Not, + hir_def::type_ref::Mutability::Mut => Mutability::Mut, + } +} + +fn unknown_const(_ty: Ty<'_>) -> Const<'_> { + Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed)) +} + +pub(crate) fn impl_trait_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> Option>> { + db.impl_trait_with_diagnostics_ns(impl_id).map(|it| it.0) +} + +pub(crate) fn impl_trait_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> { + let impl_data = db.impl_signature(impl_id); + let resolver = impl_id.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let self_ty = db.impl_self_ty_ns(impl_id).skip_binder(); + let target_trait = impl_data.target_trait.as_ref()?; + let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?); + Some((trait_ref, create_diagnostics(ctx.diagnostics))) +} + +pub(crate) fn return_type_impl_traits<'db>( + db: &'db dyn HirDatabase, + def: hir_def::FunctionId, +) -> Option>>> { + // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe + let data = db.function_signature(def); + let resolver = def.resolver(db); + let mut ctx_ret = + TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(ret_type) = data.ret_type { + let _ret = ctx_ret.lower_ty(ret_type); + } + let return_type_impl_traits = + ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; + if return_type_impl_traits.impl_traits.is_empty() { + None + } else { + Some(Arc::new(EarlyBinder::bind(return_type_impl_traits))) + } +} + +pub(crate) fn type_alias_impl_traits<'db>( + db: &'db dyn HirDatabase, + def: hir_def::TypeAliasId, +) -> Option>>> { + let data = db.type_alias_signature(def); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(type_ref) = data.ty { + let _ty = ctx.lower_ty(type_ref); + } + let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; + if type_alias_impl_traits.impl_traits.is_empty() { + None + } else { + Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits))) + } +} + +/// Build the declared type of an item. This depends on the namespace; e.g. for +/// `struct Foo(usize)`, we have two types: The type of the struct itself, and +/// the constructor function `(usize) -> Foo` which lives in the values +/// namespace. +pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + match def { + TyDefId::BuiltinType(it) => EarlyBinder::bind(builtin(interner, it)), + TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( + interner, + AdtDef::new(it, interner), + GenericArgs::identity_for_item(interner, it.into()), + )), + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics_ns(it).0, + } +} + +pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + t: TypeAliasId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + let type_alias_data = db.type_alias_signature(t); + let mut diags = None; + let resolver = t.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { + EarlyBinder::bind(Ty::new_foreign(interner, t.into())) + } else { + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + t.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + let res = EarlyBinder::bind( + type_alias_data + .ty + .map(|type_ref| ctx.lower_ty(type_ref)) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)), + ); + diags = create_diagnostics(ctx.diagnostics); + res + }; + (inner, diags) +} + +pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, + _adt: TypeAliasId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) +} + +pub(crate) fn impl_self_ty_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> EarlyBinder<'db, Ty<'db>> { + db.impl_self_ty_with_diagnostics_ns(impl_id).0 +} + +pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + let resolver = impl_id.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + + let impl_data = db.impl_signature(impl_id); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let ty = ctx.lower_ty(impl_data.self_ty); + assert!(!ty.has_escaping_bound_vars()); + (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics)) +} + +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _impl_id: ImplId, +) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) { + (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) +} + +pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { + db.const_param_ty_with_diagnostics_ns(def).0 +} + +// returns None if def is a type arg +pub(crate) fn const_param_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + def: ConstParamId, +) -> (Ty<'db>, Diagnostics) { + let (parent_data, store) = db.generic_params_and_store(def.parent()); + let data = &parent_data[def.local_id()]; + let resolver = def.parent().resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &store, + def.parent(), + LifetimeElisionKind::AnonymousReportError, + ); + let ty = match data { + TypeOrConstParamData::TypeParamData(_) => { + never!(); + Ty::new_error(interner, ErrorGuaranteed) + } + TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), + }; + (ty, create_diagnostics(ctx.diagnostics)) +} + +pub(crate) fn field_types_query<'db>( + db: &'db dyn HirDatabase, + variant_id: VariantId, +) -> Arc>>> { + db.field_types_with_diagnostics_ns(variant_id).0 +} + +/// Build the type of all specific fields of a struct or enum variant. +pub(crate) fn field_types_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + variant_id: VariantId, +) -> (Arc>>>, Diagnostics) { + let var_data = variant_id.fields(db); + let fields = var_data.fields(); + if fields.is_empty() { + return (Arc::new(ArenaMap::default()), None); + } + + let (resolver, def): (_, GenericDefId) = match variant_id { + VariantId::StructId(it) => (it.resolver(db), it.into()), + VariantId::UnionId(it) => (it.resolver(db), it.into()), + VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()), + }; + let mut res = ArenaMap::default(); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &var_data.store, + def, + LifetimeElisionKind::AnonymousReportError, + ); + for (field_id, field_data) in var_data.fields().iter() { + res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref))); + } + (Arc::new(res), create_diagnostics(ctx.diagnostics)) +} + +/// This query exists only to be used when resolving short-hand associated types +/// like `T::Item`. +/// +/// See the analogous query in rustc and its comment: +/// +/// This is a query mostly to handle cycles somewhat gracefully; e.g. the +/// following bounds are disallowed: `T: Foo, U: Foo`, but +/// these are fine: `T: Foo, U: Foo<()>`. +#[tracing::instrument(skip(db), ret)] +pub(crate) fn generic_predicates_for_param_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + param_id: TypeOrConstParamId, + assoc_name: Option, +) -> GenericPredicates<'db> { + let generics = generics(db, def); + let interner = DbInterner::new_with(db, None, None); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + + // we have to filter out all other predicates *first*, before attempting to lower them + let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred { + WherePredicate::ForLifetime { target, bound, .. } + | WherePredicate::TypeBound { target, bound, .. } => { + let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; + if invalid_target { + // 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, &generics, PredicateFilter::All) + .for_each(drop); + } + return false; + } + + match bound { + &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { + // Only lower the bound if the trait could possibly define the associated + // type we're looking for. + let path = &ctx.store[path]; + + let Some(assoc_name) = &assoc_name else { return true }; + let Some(TypeNs::TraitId(tr)) = + resolver.resolve_path_in_type_ns_fully(db, path) + else { + return false; + }; + + rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| { + let tr = match tr { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + tr.trait_items(db).items.iter().any(|(name, item)| { + matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name + }) + }) + } + TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, + } + } + WherePredicate::Lifetime { .. } => false, + }; + let mut predicates = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + if predicate(pred, &mut ctx) { + predicates.extend(ctx.lower_where_predicate( + pred, + true, + maybe_parent_generics, + PredicateFilter::All, + )); + } + } + } + + let args = GenericArgs::identity_for_item(interner, def.into()); + if !args.is_empty() { + let explicitly_unsized_tys = ctx.unsized_types; + if let Some(implicitly_sized_predicates) = + implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver) + { + predicates.extend(implicitly_sized_predicates); + }; + } + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) +} + +pub(crate) fn generic_predicates_for_param_cycle_result( + _db: &dyn HirDatabase, + _def: GenericDefId, + _param_id: TypeOrConstParamId, + _assoc_name: Option, +) -> GenericPredicates<'_> { + GenericPredicates(None) +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericPredicates<'db>(Option]>>); + +impl<'db> ops::Deref for GenericPredicates<'db> { + type Target = [Clause<'db>]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + +#[derive(Copy, Clone, Debug)] +pub(crate) enum PredicateFilter { + SelfTrait, + All, +} + +/// Resolve the where clause(s) of an item with generics. +#[tracing::instrument(skip(db))] +pub(crate) fn generic_predicates_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates<'db> { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0 +} + +pub(crate) fn generic_predicates_without_parent_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates<'db> { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0 +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> (GenericPredicates<'db>, Diagnostics) { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def) +} + +/// Resolve the where clause(s) of an item with generics, +/// with a given filter +#[tracing::instrument(skip(db, filter), ret)] +pub(crate) fn generic_predicates_filtered_by<'db, F>( + db: &'db dyn HirDatabase, + def: GenericDefId, + predicate_filter: PredicateFilter, + filter: F, +) -> (GenericPredicates<'db>, Diagnostics) +where + F: Fn(GenericDefId) -> bool, +{ + let generics = generics(db, def); + let resolver = def.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + + let mut predicates = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + tracing::debug!(?pred); + if filter(maybe_parent_generics.def()) { + // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake! + // If we use the parent generics + predicates.extend(ctx.lower_where_predicate( + pred, + false, + maybe_parent_generics, + predicate_filter, + )); + } + } + } + + let explicitly_unsized_tys = ctx.unsized_types; + + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + if let Some(sized_trait) = sized_trait { + let (mut generics, mut def_id) = + (crate::next_solver::generics::generics(db, def.into()), def); + loop { + if filter(def_id) { + let self_idx = trait_self_param_idx(db, def_id); + for (idx, p) in generics.own_params.iter().enumerate() { + if let Some(self_idx) = self_idx + && p.index() as usize == self_idx + { + continue; + } + let GenericParamDefKind::Type = p.kind else { + continue; + }; + let idx = idx as u32 + generics.parent_count as u32; + let param_ty = Ty::new_param(interner, idx, p.name.clone()); + if explicitly_unsized_tys.contains(¶m_ty) { + continue; + } + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_iter(interner, [param_ty.into()]), + ); + let clause = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + predicates.push(clause); + } + } + + if let Some(g) = generics.parent { + generics = crate::next_solver::generics::generics(db, g.into()); + def_id = g; + } else { + break; + } + } + } + + ( + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), + create_diagnostics(ctx.diagnostics), + ) +} + +/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. +/// Exception is Self of a trait def. +fn implicitly_sized_clauses<'a, 'subst, 'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + explicitly_unsized_tys: &'a FxHashSet>, + args: &'subst GenericArgs<'db>, + resolver: &Resolver<'db>, +) -> Option> + Captures<'a> + Captures<'subst>> { + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?; + + let trait_self_idx = trait_self_param_idx(db, def); + + Some( + args.iter() + .enumerate() + .filter_map( + move |(idx, generic_arg)| { + if Some(idx) == trait_self_idx { None } else { Some(generic_arg) } + }, + ) + .filter_map(|generic_arg| generic_arg.as_type()) + .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty)) + .map(move |self_ty| { + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_iter(interner, [self_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) + }), + ) +} + +pub(crate) fn make_binders<'db, T: rustc_type_ir::TypeVisitable>>( + interner: DbInterner<'db>, + generics: &Generics, + value: T, +) -> Binder<'db, T> { + Binder::bind_with_vars( + value, + BoundVarKinds::new_from_iter( + interner, + generics.iter_id().map(|x| match x { + hir_def::GenericParamId::ConstParamId(_) => BoundVarKind::Const, + hir_def::GenericParamId::TypeParamId(_) => BoundVarKind::Ty(BoundTyKind::Anon), + hir_def::GenericParamId::LifetimeParamId(_) => { + BoundVarKind::Region(BoundRegionKind::Anon) + } + }), + ), + ) +} + +/// Checks if the provided generic arg matches its expected kind, then lower them via +/// provided closures. Use unknown if there was kind mismatch. +/// +pub(crate) fn lower_generic_arg<'a, 'db, T>( + db: &'db dyn HirDatabase, + kind_id: GenericParamId, + arg: &'a GenericArg, + this: &mut T, + store: &ExpressionStore, + for_type: impl FnOnce(&mut T, TypeRefId) -> Ty<'db> + 'a, + for_const: impl FnOnce(&mut T, &ConstRef, Ty<'db>) -> Const<'db> + 'a, + for_const_ty_path_fallback: impl FnOnce(&mut T, &Path, Ty<'db>) -> Const<'db> + 'a, + for_lifetime: impl FnOnce(&mut T, &LifetimeRefId) -> Region<'db> + 'a, +) -> crate::next_solver::GenericArg<'db> { + let interner = DbInterner::new_with(db, None, None); + let kind = match kind_id { + GenericParamId::TypeParamId(_) => ParamKind::Type, + GenericParamId::ConstParamId(id) => { + let ty = db.const_param_ty(id); + ParamKind::Const(ty) + } + GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, + }; + match (arg, kind) { + (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).into(), + (GenericArg::Const(c), ParamKind::Const(c_ty)) => { + for_const(this, c, c_ty.to_nextsolver(interner)).into() + } + (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { + for_lifetime(this, lifetime_ref).into() + } + (GenericArg::Const(_), ParamKind::Type) => Ty::new_error(interner, ErrorGuaranteed).into(), + (GenericArg::Lifetime(_), ParamKind::Type) => { + Ty::new_error(interner, ErrorGuaranteed).into() + } + (GenericArg::Type(t), ParamKind::Const(c_ty)) => match &store[*t] { + TypeRef::Path(p) => { + for_const_ty_path_fallback(this, p, c_ty.to_nextsolver(interner)).into() + } + _ => unknown_const_as_generic(c_ty.to_nextsolver(interner)), + }, + (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => { + unknown_const(c_ty.to_nextsolver(interner)).into() + } + (GenericArg::Type(_), ParamKind::Lifetime) => Region::error(interner).into(), + (GenericArg::Const(_), ParamKind::Lifetime) => Region::error(interner).into(), + } +} + +/// Build the signature of a callable item (function, struct or enum variant). +pub(crate) fn callable_item_signature_query<'db>( + db: &'db dyn HirDatabase, + def: CallableDefId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + match def { + CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), + CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), + CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), + } +} + +fn fn_sig_for_fn<'db>( + db: &'db dyn HirDatabase, + def: FunctionId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let data = db.function_signature(def); + let resolver = def.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx_params = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_params(&data), + ); + let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); + + let ret = match data.ret_type { + Some(ret_type) => { + let mut ctx_ret = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_ret(interner), + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + ctx_ret.lower_ty(ret_type) + } + None => Ty::new_tup(interner, &[]), + }; + + let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); + // If/when we track late bound vars, we need to switch this to not be `dummy` + EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig { + abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), + c_variadic: data.is_varargs(), + safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, + inputs_and_output, + })) +} + +fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + let args = GenericArgs::identity_for_item(interner, adt.into()); + let ty = Ty::new_adt(interner, AdtDef::new(adt, interner), args); + EarlyBinder::bind(ty) +} + +fn fn_sig_for_struct_constructor<'db>( + db: &'db dyn HirDatabase, + def: StructId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let field_tys = db.field_types_ns(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let ret = type_for_adt(db, def.into()).skip_binder(); + + let inputs_and_output = + Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); + EarlyBinder::bind(Binder::dummy(FnSig { + abi: FnAbi::RustCall, + c_variadic: false, + safety: Safety::Safe, + inputs_and_output, + })) +} + +fn fn_sig_for_enum_variant_constructor<'db>( + db: &'db dyn HirDatabase, + def: EnumVariantId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let field_tys = db.field_types_ns(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let parent = def.lookup(db).parent; + let ret = type_for_adt(db, parent.into()).skip_binder(); + + let inputs_and_output = + Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); + EarlyBinder::bind(Binder::dummy(FnSig { + abi: FnAbi::RustCall, + c_variadic: false, + safety: Safety::Safe, + inputs_and_output, + })) +} + +pub(crate) fn associated_type_by_name_including_super_traits<'db>( + db: &'db dyn HirDatabase, + trait_ref: TraitRef<'db>, + name: &Name, +) -> Option<(TraitRef<'db>, TypeAliasId)> { + let interner = DbInterner::new_with(db, None, None); + rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { + let trait_id = match t.as_ref().skip_binder().def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; + Some((t.skip_binder(), assoc_type)) + }) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs new file mode 100644 index 0000000000000..b95bb1130fa20 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -0,0 +1,1459 @@ +//! A wrapper around [`TyLoweringContext`] specifically for lowering paths. + +use std::ops::Deref; + +use either::Either; +use hir_def::{ + AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, + builtin_type::BuiltinType, + expr_store::{ + ExpressionStore, HygieneId, + path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments}, + }, + hir::generics::{ + GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, + }, + resolver::{ResolveValueResult, TypeNs, ValueNs}, + signatures::TraitFlags, + type_ref::{TypeRef, TypeRefId}, +}; +use intern::sym; +use rustc_hash::FxHashSet; +use rustc_type_ir::{ + AliasTerm, AliasTy, AliasTyKind, TypeVisitableExt, + inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _}, +}; +use smallvec::{SmallVec, smallvec}; +use stdx::never; + +use crate::{ + GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource, + PathLoweringDiagnostic, TyDefId, ValueTyDefId, + consteval_nextsolver::{unknown_const, unknown_const_as_generic}, + db::HirDatabase, + generics::{Generics, generics}, + lower::PathDiagnosticCallbackData, + lower_nextsolver::{LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by}, + next_solver::{ + AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate, + Region, SolverDefId, TraitRef, Ty, + mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, + }, + primitive, +}; + +use super::{ + ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits, + const_param_ty_query, ty_query, +}; + +type CallbackData<'a> = + Either>; + +// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box` +// because of the allocation, so we create a lifetime-less callback, tailored for our needs. +pub(crate) struct PathDiagnosticCallback<'a, 'db> { + pub(crate) data: CallbackData<'a>, + pub(crate) callback: + fn(&CallbackData<'_>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic), +} + +pub(crate) struct PathLoweringContext<'a, 'b, 'db> { + ctx: &'a mut TyLoweringContext<'db, 'b>, + on_diagnostic: PathDiagnosticCallback<'a, 'db>, + path: &'a Path, + segments: PathSegments<'a>, + current_segment_idx: usize, + /// Contains the previous segment if `current_segment_idx == segments.len()` + current_or_prev_segment: PathSegment<'a>, +} + +impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { + #[inline] + pub(crate) fn new( + ctx: &'a mut TyLoweringContext<'db, 'b>, + on_diagnostic: PathDiagnosticCallback<'a, 'db>, + path: &'a Path, + ) -> Self { + let segments = path.segments(); + let first_segment = segments.first().unwrap_or(PathSegment::MISSING); + Self { + ctx, + on_diagnostic, + path, + segments, + current_segment_idx: 0, + current_or_prev_segment: first_segment, + } + } + + #[inline] + #[cold] + fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) { + (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag); + } + + #[inline] + pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> { + self.ctx + } + + #[inline] + fn current_segment_u32(&self) -> u32 { + self.current_segment_idx as u32 + } + + #[inline] + fn skip_resolved_segment(&mut self) { + if !matches!(self.path, Path::LangItem(..)) { + // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it + // point at -1, but I don't feel this is clearer. + self.current_segment_idx += 1; + } + self.update_current_segment(); + } + + #[inline] + fn update_current_segment(&mut self) { + self.current_or_prev_segment = + self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment); + } + + #[inline] + pub(crate) fn ignore_last_segment(&mut self) { + self.segments = self.segments.strip_last(); + } + + #[inline] + pub(crate) fn set_current_segment(&mut self, segment: usize) { + self.current_segment_idx = segment; + self.current_or_prev_segment = self + .segments + .get(segment) + .expect("invalid segment passed to PathLoweringContext::set_current_segment()"); + } + + #[inline] + fn with_lifetime_elision( + &mut self, + lifetime_elision: LifetimeElisionKind<'db>, + f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T, + ) -> T { + let old_lifetime_elision = + std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision); + let result = f(self); + self.ctx.lifetime_elision = old_lifetime_elision; + result + } + + pub(crate) fn lower_ty_relative_path( + &mut self, + ty: Ty<'db>, + // We need the original resolution to lower `Self::AssocTy` correctly + res: Option, + ) -> (Ty<'db>, Option) { + let remaining_segments = self.segments.len() - self.current_segment_idx; + match remaining_segments { + 0 => (ty, res), + 1 => { + // resolve unselected assoc types + (self.select_associated_type(res), None) + } + _ => { + // FIXME report error (ambiguous associated type) + (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None) + } + } + } + + fn prohibit_parenthesized_generic_args(&mut self) -> bool { + if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings { + match generic_args.parenthesized { + GenericArgsParentheses::No => {} + GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => { + let segment = self.current_segment_u32(); + self.on_diagnostic( + PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, + ); + return true; + } + } + } + false + } + + // When calling this, the current segment is the resolved segment (we don't advance it yet). + pub(crate) fn lower_partly_resolved_path( + &mut self, + resolution: TypeNs, + infer_args: bool, + ) -> (Ty<'db>, Option) { + let remaining_segments = self.segments.skip(self.current_segment_idx + 1); + tracing::debug!(?remaining_segments); + let rem_seg_len = remaining_segments.len(); + tracing::debug!(?rem_seg_len); + + let ty = match resolution { + TypeNs::TraitId(trait_) => { + let ty = match remaining_segments.len() { + 1 => { + let trait_ref = self.lower_trait_ref_from_resolved_path( + trait_, + Ty::new_error(self.ctx.interner, ErrorGuaranteed), + ); + tracing::debug!(?trait_ref); + self.skip_resolved_segment(); + let segment = self.current_or_prev_segment; + let trait_id = match trait_ref.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let found = + trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name); + + tracing::debug!(?found); + match found { + Some(associated_ty) => { + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`trait_ref.substitution`). + let substitution = self.substs_from_path_segment( + associated_ty.into(), + false, + None, + true, + ); + let args = crate::next_solver::GenericArgs::new_from_iter( + self.ctx.interner, + trait_ref + .args + .iter() + .chain(substitution.iter().skip(trait_ref.args.len())), + ); + Ty::new_alias( + self.ctx.interner, + AliasTyKind::Projection, + AliasTy::new_from_args( + self.ctx.interner, + associated_ty.into(), + args, + ), + ) + } + None => { + // FIXME: report error (associated type not found) + Ty::new_error(self.ctx.interner, ErrorGuaranteed) + } + } + } + 0 => { + // Trait object type without dyn; this should be handled in upstream. See + // `lower_path()`. + stdx::never!("unexpected fully resolved trait path"); + Ty::new_error(self.ctx.interner, ErrorGuaranteed) + } + _ => { + // FIXME report error (ambiguous associated type) + Ty::new_error(self.ctx.interner, ErrorGuaranteed) + } + }; + return (ty, None); + } + TypeNs::TraitAliasId(_) => { + // FIXME(trait_alias): Implement trait alias. + return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None); + } + TypeNs::GenericParam(param_id) => { + let generics = self.ctx.generics(); + let idx = generics.type_or_const_param_idx(param_id.into()); + match idx { + None => { + never!("no matching generics"); + Ty::new_error(self.ctx.interner, ErrorGuaranteed) + } + Some(idx) => { + let (pidx, param) = generics.iter().nth(idx).unwrap(); + assert_eq!(pidx, param_id.into()); + let p = match param { + GenericParamDataRef::TypeParamData(p) => p, + _ => unreachable!(), + }; + Ty::new_param( + self.ctx.interner, + idx as u32, + p.name + .as_ref() + .map_or_else(|| sym::MISSING_NAME.clone(), |p| p.symbol().clone()), + ) + } + } + } + TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty_ns(impl_id).skip_binder(), + TypeNs::AdtSelfType(adt) => { + let args = crate::next_solver::GenericArgs::identity_for_item( + self.ctx.interner, + adt.into(), + ); + Ty::new_adt(self.ctx.interner, AdtDef::new(adt, self.ctx.interner), args) + } + + TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args), + TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args), + TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args), + // FIXME: report error + TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => { + return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None); + } + }; + + tracing::debug!(?ty); + + self.skip_resolved_segment(); + self.lower_ty_relative_path(ty, Some(resolution)) + } + + fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) { + let mut prohibit_generics_on_resolved = |reason| { + if self.current_or_prev_segment.args_and_bindings.is_some() { + let segment = self.current_segment_u32(); + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment, + reason, + }); + } + }; + + match resolution { + TypeNs::SelfType(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) + } + TypeNs::GenericParam(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam) + } + TypeNs::AdtSelfType(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) + } + TypeNs::BuiltinType(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy) + } + TypeNs::ModuleId(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module) + } + TypeNs::AdtId(_) + | TypeNs::EnumVariantId(_) + | TypeNs::TypeAliasId(_) + | TypeNs::TraitId(_) + | TypeNs::TraitAliasId(_) => {} + } + } + + pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option { + let (res, unresolved) = self.resolve_path_in_type_ns()?; + if unresolved.is_some() { + return None; + } + Some(res) + } + + #[tracing::instrument(skip(self), ret)] + pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option)> { + let (resolution, remaining_index, _, prefix_info) = + self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?; + + let segments = self.segments; + if segments.is_empty() || matches!(self.path, Path::LangItem(..)) { + // `segments.is_empty()` can occur with `self`. + return Some((resolution, remaining_index)); + } + + let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index { + None if prefix_info.enum_variant => { + (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2)) + } + None => (segments.strip_last(), segments.len() - 1, None), + Some(i) => (segments.take(i - 1), i - 1, None), + }; + + self.current_segment_idx = resolved_segment_idx; + self.current_or_prev_segment = + segments.get(resolved_segment_idx).expect("should have resolved segment"); + + if matches!(self.path, Path::BarePath(..)) { + // Bare paths cannot have generics, so skip them as an optimization. + return Some((resolution, remaining_index)); + } + + for (i, mod_segment) in module_segments.iter().enumerate() { + if mod_segment.args_and_bindings.is_some() { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: i as u32, + reason: GenericArgsProhibitedReason::Module, + }); + } + } + + if let Some(enum_segment) = enum_segment + && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }); + } + + self.handle_type_ns_resolution(&resolution); + + Some((resolution, remaining_index)) + } + + pub(crate) fn resolve_path_in_value_ns( + &mut self, + hygiene_id: HygieneId, + ) -> Option { + let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info( + self.ctx.db, + self.path, + hygiene_id, + )?; + + let segments = self.segments; + if segments.is_empty() || matches!(self.path, Path::LangItem(..)) { + // `segments.is_empty()` can occur with `self`. + return Some(res); + } + + let (mod_segments, enum_segment, resolved_segment_idx) = match res { + ResolveValueResult::Partial(_, unresolved_segment, _) => { + (segments.take(unresolved_segment - 1), None, unresolved_segment - 1) + } + ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _) + if prefix_info.enum_variant => + { + (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1) + } + ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1), + }; + + self.current_segment_idx = resolved_segment_idx; + self.current_or_prev_segment = + segments.get(resolved_segment_idx).expect("should have resolved segment"); + + for (i, mod_segment) in mod_segments.iter().enumerate() { + if mod_segment.args_and_bindings.is_some() { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: i as u32, + reason: GenericArgsProhibitedReason::Module, + }); + } + } + + if let Some(enum_segment) = enum_segment + && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }); + } + + match &res { + ResolveValueResult::ValueNs(resolution, _) => { + let resolved_segment_idx = self.current_segment_u32(); + let resolved_segment = self.current_or_prev_segment; + + let mut prohibit_generics_on_resolved = |reason| { + if resolved_segment.args_and_bindings.is_some() { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: resolved_segment_idx, + reason, + }); + } + }; + + match resolution { + ValueNs::ImplSelf(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) + } + // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not + // E0109 (generic arguments provided for a type that doesn't accept them) for + // consts and statics, presumably as a defense against future in which consts + // and statics can be generic, or just because it was easier for rustc implementors. + // That means we'll show the wrong error code. Because of us it's easier to do it + // this way :) + ValueNs::GenericParam(_) | ValueNs::ConstId(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const) + } + ValueNs::StaticId(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static) + } + ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {} + ValueNs::LocalBinding(_) => {} + } + } + ResolveValueResult::Partial(resolution, _, _) => { + self.handle_type_ns_resolution(resolution); + } + }; + Some(res) + } + + #[tracing::instrument(skip(self), ret)] + fn select_associated_type(&mut self, res: Option) -> Ty<'db> { + let interner = self.ctx.interner; + let Some(res) = res else { + return Ty::new_error(self.ctx.interner, ErrorGuaranteed); + }; + let segment = self.current_or_prev_segment; + let assoc_name = segment.name; + let db = self.ctx.db; + let def = self.ctx.def; + let mut search = |t: TraitRef<'db>| { + let trait_id = match t.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let mut checked_traits = FxHashSet::default(); + let mut check_trait = |trait_id: TraitId| { + let name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_id, ?name); + if !checked_traits.insert(trait_id) { + return None; + } + let data = trait_id.trait_items(db); + + tracing::debug!(?data.items); + for (name, assoc_id) in &data.items { + if let &AssocItemId::TypeAliasId(alias) = assoc_id { + if name != assoc_name { + continue; + } + + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`t.substitution`). + let substs = self.substs_from_path_segment(alias.into(), false, None, true); + + let substs = crate::next_solver::GenericArgs::new_from_iter( + interner, + t.args.iter().chain(substs.iter().skip(t.args.len())), + ); + + return Some(Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy::new(interner, alias.into(), substs), + )); + } + } + None + }; + let mut stack: SmallVec<[_; 4]> = smallvec![trait_id]; + while let Some(trait_def_id) = stack.pop() { + if let Some(alias) = check_trait(trait_def_id) { + return alias; + } + for pred in generic_predicates_filtered_by( + db, + GenericDefId::TraitId(trait_def_id), + PredicateFilter::SelfTrait, + |pred| pred == GenericDefId::TraitId(trait_def_id), + ) + .0 + .deref() + { + tracing::debug!(?pred); + let trait_id = match pred.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(), + _ => continue, + }; + let trait_id = match trait_id { + SolverDefId::TraitId(trait_id) => trait_id, + _ => continue, + }; + stack.push(trait_id); + } + tracing::debug!(?stack); + } + + Ty::new_error(interner, ErrorGuaranteed) + }; + + match res { + TypeNs::SelfType(impl_id) => { + let trait_ref = db.impl_trait_ns(impl_id); + let Some(trait_ref) = trait_ref else { + return Ty::new_error(interner, ErrorGuaranteed); + }; + + // we're _in_ the impl -- the binders get added back later. Correct, + // but it would be nice to make this more explicit + search(trait_ref.skip_binder()) + } + TypeNs::GenericParam(param_id) => { + // Handle `Self::Type` referring to own associated type in trait definitions + // This *must* be done first to avoid cycles with + // `generic_predicates_for_param`, but not sure that it's sufficient, + // see FIXME in `search`. + if let GenericDefId::TraitId(trait_id) = param_id.parent() { + let trait_name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_name); + let trait_generics = generics(db, trait_id.into()); + tracing::debug!(?trait_generics); + if trait_generics[param_id.local_id()].is_trait_self() { + let args = crate::next_solver::GenericArgs::identity_for_item( + interner, + trait_id.into(), + ); + let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); + tracing::debug!(?args, ?trait_ref); + return search(trait_ref); + } + } + + let predicates = db.generic_predicates_for_param_ns( + def, + param_id.into(), + Some(segment.name.clone()), + ); + predicates + .iter() + .find_map(|pred| match (*pred).kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), + _ => None, + }) + .map(|trait_predicate| { + let trait_ref = trait_predicate.trait_ref; + assert!( + !trait_ref.has_escaping_bound_vars(), + "FIXME unexpected higher-ranked trait bound" + ); + search(trait_ref) + }) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) + } + _ => Ty::new_error(interner, ErrorGuaranteed), + } + } + + fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> { + let generic_def = match typeable { + TyDefId::BuiltinType(builtinty) => return builtin(self.ctx.interner, builtinty), + TyDefId::AdtId(it) => it.into(), + TyDefId::TypeAliasId(it) => it.into(), + }; + let args = self.substs_from_path_segment(generic_def, infer_args, None, false); + let ty = ty_query(self.ctx.db, typeable); + ty.instantiate(self.ctx.interner, args) + } + + /// Collect generic arguments from a path into a `Substs`. See also + /// `create_substs_for_ast_path` and `def_to_ty` in rustc. + pub(crate) fn substs_from_path( + &mut self, + // Note that we don't call `db.value_type(resolved)` here, + // `ValueTyDefId` is just a convenient way to pass generics and + // special-case enum variants + resolved: ValueTyDefId, + infer_args: bool, + lowering_assoc_type_generics: bool, + ) -> crate::next_solver::GenericArgs<'db> { + let interner = self.ctx.interner; + let prev_current_segment_idx = self.current_segment_idx; + let prev_current_segment = self.current_or_prev_segment; + + let generic_def = match resolved { + ValueTyDefId::FunctionId(it) => it.into(), + ValueTyDefId::StructId(it) => it.into(), + ValueTyDefId::UnionId(it) => it.into(), + ValueTyDefId::ConstId(it) => it.into(), + ValueTyDefId::StaticId(_) => { + return crate::next_solver::GenericArgs::new_from_iter(interner, []); + } + ValueTyDefId::EnumVariantId(var) => { + // the generic args for an enum variant may be either specified + // on the segment referring to the enum, or on the segment + // referring to the variant. So `Option::::None` and + // `Option::None::` are both allowed (though the former is + // FIXME: This isn't strictly correct, enum variants may be used not through the enum + // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result + // available here. The worst that can happen is that we will show some confusing diagnostics to the user, + // if generics exist on the module and they don't match with the variant. + // preferred). See also `def_ids_for_path_segments` in rustc. + // + // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2. + // This simplifies the code a bit. + let penultimate_idx = self.current_segment_idx.wrapping_sub(1); + let penultimate = self.segments.get(penultimate_idx); + if let Some(penultimate) = penultimate + && self.current_or_prev_segment.args_and_bindings.is_none() + && penultimate.args_and_bindings.is_some() + { + self.current_segment_idx = penultimate_idx; + self.current_or_prev_segment = penultimate; + } + var.lookup(self.ctx.db).parent.into() + } + }; + let result = self.substs_from_path_segment( + generic_def, + infer_args, + None, + lowering_assoc_type_generics, + ); + self.current_segment_idx = prev_current_segment_idx; + self.current_or_prev_segment = prev_current_segment; + result + } + + pub(crate) fn substs_from_path_segment( + &mut self, + def: GenericDefId, + infer_args: bool, + explicit_self_ty: Option>, + lowering_assoc_type_generics: bool, + ) -> crate::next_solver::GenericArgs<'db> { + let mut lifetime_elision = self.ctx.lifetime_elision.clone(); + + if let Some(args) = self.current_or_prev_segment.args_and_bindings + && args.parenthesized != GenericArgsParentheses::No + { + let prohibit_parens = match def { + GenericDefId::TraitId(trait_) => { + // RTN is prohibited anyways if we got here. + let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; + let is_fn_trait = self + .ctx + .db + .trait_signature(trait_) + .flags + .contains(TraitFlags::RUSTC_PAREN_SUGAR); + is_rtn || !is_fn_trait + } + _ => true, + }; + + if prohibit_parens { + let segment = self.current_segment_u32(); + self.on_diagnostic( + PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, + ); + + return unknown_subst(self.ctx.interner, def); + } + + // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. + lifetime_elision = + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; + } + + self.substs_from_args_and_bindings( + self.current_or_prev_segment.args_and_bindings, + def, + infer_args, + explicit_self_ty, + PathGenericsSource::Segment(self.current_segment_u32()), + lowering_assoc_type_generics, + lifetime_elision, + ) + } + + pub(super) fn substs_from_args_and_bindings( + &mut self, + args_and_bindings: Option<&GenericArgs>, + def: GenericDefId, + infer_args: bool, + explicit_self_ty: Option>, + generics_source: PathGenericsSource, + lowering_assoc_type_generics: bool, + lifetime_elision: LifetimeElisionKind<'db>, + ) -> crate::next_solver::GenericArgs<'db> { + struct LowererCtx<'a, 'b, 'c, 'db> { + ctx: &'a mut PathLoweringContext<'b, 'c, 'db>, + generics_source: PathGenericsSource, + } + + impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> { + fn report_len_mismatch( + &mut self, + def: GenericDefId, + provided_count: u32, + expected_count: u32, + kind: IncorrectGenericsLenKind, + ) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen { + generics_source: self.generics_source, + provided_count, + expected_count, + kind, + def, + }); + } + + fn report_arg_mismatch( + &mut self, + param_id: GenericParamId, + arg_idx: u32, + has_self_arg: bool, + ) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder { + generics_source: self.generics_source, + param_id, + arg_idx, + has_self_arg, + }); + } + + fn provided_kind( + &mut self, + param_id: GenericParamId, + param: GenericParamDataRef<'_>, + arg: &GenericArg, + ) -> crate::next_solver::GenericArg<'db> { + match (param, arg) { + (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { + self.ctx.ctx.lower_lifetime(*lifetime).into() + } + (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { + self.ctx.ctx.lower_ty(*type_ref).into() + } + (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { + let GenericParamId::ConstParamId(const_id) = param_id else { + unreachable!("non-const param ID for const param"); + }; + self.ctx + .ctx + .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id)) + .into() + } + _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), + } + } + + fn provided_type_like_const( + &mut self, + const_ty: Ty<'db>, + arg: TypeLikeConst<'_>, + ) -> crate::next_solver::Const<'db> { + match arg { + TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty), + TypeLikeConst::Infer => unknown_const(const_ty), + } + } + + fn inferred_kind( + &mut self, + def: GenericDefId, + param_id: GenericParamId, + param: GenericParamDataRef<'_>, + infer_args: bool, + preceding_args: &[crate::next_solver::GenericArg<'db>], + ) -> crate::next_solver::GenericArg<'db> { + let default = || { + self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| { + convert_binder_to_early_binder( + self.ctx.ctx.interner, + default.to_nextsolver(self.ctx.ctx.interner), + ) + .instantiate(self.ctx.ctx.interner, preceding_args) + }) + }; + match param { + GenericParamDataRef::LifetimeParamData(_) => { + Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) + .into() + } + GenericParamDataRef::TypeParamData(param) => { + if !infer_args + && param.default.is_some() + && let Some(default) = default() + { + return default; + } + Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() + } + GenericParamDataRef::ConstParamData(param) => { + if !infer_args + && param.default.is_some() + && let Some(default) = default() + { + return default; + } + let GenericParamId::ConstParamId(const_id) = param_id else { + unreachable!("non-const param ID for const param"); + }; + unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) + } + } + } + + fn parent_arg( + &mut self, + param_id: GenericParamId, + ) -> crate::next_solver::GenericArg<'db> { + match param_id { + GenericParamId::TypeParamId(_) => { + Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() + } + GenericParamId::ConstParamId(const_id) => { + unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) + } + GenericParamId::LifetimeParamId(_) => { + Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) + .into() + } + } + } + + fn report_elided_lifetimes_in_path( + &mut self, + def: GenericDefId, + expected_count: u32, + hard_error: bool, + ) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath { + generics_source: self.generics_source, + def, + expected_count, + hard_error, + }); + } + + fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure { + generics_source: self.generics_source, + def, + expected_count, + }); + } + + fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime { + generics_source: self.generics_source, + def, + expected_count, + }); + } + } + + substs_from_args_and_bindings( + self.ctx.db, + self.ctx.store, + args_and_bindings, + def, + infer_args, + lifetime_elision, + lowering_assoc_type_generics, + explicit_self_ty, + &mut LowererCtx { ctx: self, generics_source }, + ) + } + + pub(crate) fn lower_trait_ref_from_resolved_path( + &mut self, + resolved: TraitId, + explicit_self_ty: Ty<'db>, + ) -> TraitRef<'db> { + let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty); + TraitRef::new_from_args(self.ctx.interner, resolved.into(), args) + } + + fn trait_ref_substs_from_path( + &mut self, + resolved: TraitId, + explicit_self_ty: Ty<'db>, + ) -> crate::next_solver::GenericArgs<'db> { + self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty), false) + } + + pub(super) fn assoc_type_bindings_from_type_bound<'c>( + mut self, + trait_ref: TraitRef<'db>, + ) -> Option> + use<'a, 'b, 'c, 'db>> { + let interner = self.ctx.interner; + self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { + args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| { + let found = associated_type_by_name_including_super_traits( + self.ctx.db, + trait_ref, + &binding.name, + ); + let (super_trait_ref, associated_ty) = match found { + None => return SmallVec::new(), + Some(t) => t, + }; + let args = + self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| { + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`super_trait_ref.substitution`). + this.substs_from_args_and_bindings( + binding.args.as_ref(), + associated_ty.into(), + false, // this is not relevant + Some(super_trait_ref.self_ty()), + PathGenericsSource::AssocType { + segment: this.current_segment_u32(), + assoc_type: binding_idx as u32, + }, + false, + this.ctx.lifetime_elision.clone(), + ) + }); + let args = crate::next_solver::GenericArgs::new_from_iter( + interner, + super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())), + ); + let projection_term = + AliasTerm::new_from_args(interner, associated_ty.into(), args); + let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( + binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), + ); + if let Some(type_ref) = binding.type_ref { + match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) { + (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (), + (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => { + let ty = self.ctx.lower_ty(type_ref); + let pred = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Projection(ProjectionPredicate { + projection_term, + term: ty.into(), + }), + )), + )); + predicates.push(pred); + } + } + } + for bound in binding.bounds.iter() { + predicates.extend(self.ctx.lower_type_bound( + bound, + Ty::new_alias( + self.ctx.interner, + AliasTyKind::Projection, + AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args), + ), + false, + )); + } + predicates + }) + }) + } +} + +/// A const that were parsed like a type. +pub(crate) enum TypeLikeConst<'a> { + Infer, + Path(&'a Path), +} + +pub(crate) trait GenericArgsLowerer<'db> { + fn report_elided_lifetimes_in_path( + &mut self, + def: GenericDefId, + expected_count: u32, + hard_error: bool, + ); + + fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32); + + fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32); + + fn report_len_mismatch( + &mut self, + def: GenericDefId, + provided_count: u32, + expected_count: u32, + kind: IncorrectGenericsLenKind, + ); + + fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool); + + fn provided_kind( + &mut self, + param_id: GenericParamId, + param: GenericParamDataRef<'_>, + arg: &GenericArg, + ) -> crate::next_solver::GenericArg<'db>; + + fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>) + -> Const<'db>; + + fn inferred_kind( + &mut self, + def: GenericDefId, + param_id: GenericParamId, + param: GenericParamDataRef<'_>, + infer_args: bool, + preceding_args: &[crate::next_solver::GenericArg<'db>], + ) -> crate::next_solver::GenericArg<'db>; + + fn parent_arg(&mut self, param_id: GenericParamId) -> crate::next_solver::GenericArg<'db>; +} + +/// Returns true if there was an error. +fn check_generic_args_len<'db>( + args_and_bindings: Option<&GenericArgs>, + def: GenericDefId, + def_generics: &Generics, + infer_args: bool, + lifetime_elision: &LifetimeElisionKind<'db>, + lowering_assoc_type_generics: bool, + ctx: &mut impl GenericArgsLowerer<'db>, +) -> bool { + let mut had_error = false; + + let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize); + if let Some(args_and_bindings) = args_and_bindings { + let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..]; + for arg in args_no_self { + match arg { + GenericArg::Lifetime(_) => provided_lifetimes_count += 1, + GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1, + } + } + } + + let lifetime_args_len = def_generics.len_lifetimes_self(); + if provided_lifetimes_count == 0 && lifetime_args_len > 0 && !lowering_assoc_type_generics { + // In generic associated types, we never allow inferring the lifetimes. + match lifetime_elision { + &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => { + ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path); + had_error |= report_in_path; + } + LifetimeElisionKind::AnonymousReportError => { + ctx.report_missing_lifetime(def, lifetime_args_len as u32); + had_error = true + } + LifetimeElisionKind::ElisionFailure => { + ctx.report_elision_failure(def, lifetime_args_len as u32); + had_error = true; + } + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { + // FIXME: Check there are other lifetimes in scope, and error/lint. + } + LifetimeElisionKind::Elided(_) => { + ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false); + } + LifetimeElisionKind::Infer => { + // Allow eliding lifetimes. + } + } + } else if lifetime_args_len != provided_lifetimes_count { + ctx.report_len_mismatch( + def, + provided_lifetimes_count as u32, + lifetime_args_len as u32, + IncorrectGenericsLenKind::Lifetimes, + ); + had_error = true; + } + + let defaults_count = + def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count(); + let named_type_and_const_params_count = def_generics + .iter_self_type_or_consts() + .filter(|(_, param)| match param { + TypeOrConstParamData::TypeParamData(param) => { + param.provenance == TypeParamProvenance::TypeParamList + } + TypeOrConstParamData::ConstParamData(_) => true, + }) + .count(); + let expected_max = named_type_and_const_params_count; + let expected_min = + if infer_args { 0 } else { named_type_and_const_params_count - defaults_count }; + if provided_types_and_consts_count < expected_min + || expected_max < provided_types_and_consts_count + { + ctx.report_len_mismatch( + def, + provided_types_and_consts_count as u32, + named_type_and_const_params_count as u32, + IncorrectGenericsLenKind::TypesAndConsts, + ); + had_error = true; + } + + had_error +} + +pub(crate) fn substs_from_args_and_bindings<'db>( + db: &'db dyn HirDatabase, + store: &ExpressionStore, + args_and_bindings: Option<&GenericArgs>, + def: GenericDefId, + mut infer_args: bool, + lifetime_elision: LifetimeElisionKind<'db>, + lowering_assoc_type_generics: bool, + explicit_self_ty: Option>, + ctx: &mut impl GenericArgsLowerer<'db>, +) -> crate::next_solver::GenericArgs<'db> { + let interner = DbInterner::new_with(db, None, None); + + tracing::debug!(?args_and_bindings); + + // Order is + // - Parent parameters + // - Optional Self parameter + // - Lifetime parameters + // - Type or Const parameters + let def_generics = generics(db, def); + let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default(); + + // We do not allow inference if there are specified args, i.e. we do not allow partial inference. + let has_non_lifetime_args = + args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))); + infer_args &= !has_non_lifetime_args; + + let had_count_error = check_generic_args_len( + args_and_bindings, + def, + &def_generics, + infer_args, + &lifetime_elision, + lowering_assoc_type_generics, + ctx, + ); + + let mut substs = Vec::with_capacity(def_generics.len()); + + substs.extend(def_generics.iter_parent_id().map(|id| ctx.parent_arg(id))); + + let mut args = args_slice.iter().enumerate().peekable(); + let mut params = def_generics.iter_self().peekable(); + + // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. + // If we later encounter a lifetime, we know that the arguments were provided in the + // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be + // inferred, so we can use it for diagnostics later. + let mut force_infer_lt = None; + + let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type); + // First, handle `Self` parameter. Consume it from the args if provided, otherwise from `explicit_self_ty`, + // and lastly infer it. + if let Some(&( + self_param_id, + self_param @ GenericParamDataRef::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }), + )) = params.peek() + { + let self_ty = if has_self_arg { + let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type"); + ctx.provided_kind(self_param_id, self_param, self_ty) + } else { + explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| { + ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs) + }) + }; + params.next(); + substs.push(self_ty); + } + + loop { + // We're going to iterate through the generic arguments that the user + // provided, matching them with the generic parameters we expect. + // Mismatches can occur as a result of elided lifetimes, or for malformed + // input. We try to handle both sensibly. + match (args.peek(), params.peek()) { + (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) { + (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param)) + if type_param.provenance == TypeParamProvenance::ArgumentImplTrait => + { + // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here + // we will handle it as if it was specified, instead of inferring it. + substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs)); + params.next(); + } + (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_)) + | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_)) + | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => { + substs.push(ctx.provided_kind(param_id, param, arg)); + args.next(); + params.next(); + } + ( + GenericArg::Type(_) | GenericArg::Const(_), + GenericParamDataRef::LifetimeParamData(_), + ) => { + // We expected a lifetime argument, but got a type or const + // argument. That means we're inferring the lifetime. + substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs)); + params.next(); + force_infer_lt = Some((arg_idx as u32, param_id)); + } + (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => { + if let Some(konst) = type_looks_like_const(store, *type_ref) { + let GenericParamId::ConstParamId(param_id) = param_id else { + panic!("unmatching param kinds"); + }; + let const_ty = const_param_ty_query(db, param_id); + substs.push(ctx.provided_type_like_const(const_ty, konst).into()); + args.next(); + params.next(); + } else { + // See the `_ => { ... }` branch. + if !had_count_error { + ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg); + } + while args.next().is_some() {} + } + } + _ => { + // We expected one kind of parameter, but the user provided + // another. This is an error. However, if we already know that + // the arguments don't match up with the parameters, we won't issue + // an additional error, as the user already knows what's wrong. + if !had_count_error { + ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg); + } + + // We've reported the error, but we want to make sure that this + // problem doesn't bubble down and create additional, irrelevant + // errors. In this case, we're simply going to ignore the argument + // and any following arguments. The rest of the parameters will be + // inferred. + while args.next().is_some() {} + } + }, + + (Some(&(_, arg)), None) => { + // We should never be able to reach this point with well-formed input. + // There are two situations in which we can encounter this issue. + // + // 1. The number of arguments is incorrect. In this case, an error + // will already have been emitted, and we can ignore it. + // 2. We've inferred some lifetimes, which have been provided later (i.e. + // after a type or const). We want to throw an error in this case. + if !had_count_error { + assert!( + matches!(arg, GenericArg::Lifetime(_)), + "the only possible situation here is incorrect lifetime order" + ); + let (provided_arg_idx, param_id) = + force_infer_lt.expect("lifetimes ought to have been inferred"); + ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg); + } + + break; + } + + (None, Some(&(param_id, param))) => { + // If there are fewer arguments than parameters, it means we're inferring the remaining arguments. + let param = if let GenericParamId::LifetimeParamId(_) = param_id { + match &lifetime_elision { + LifetimeElisionKind::ElisionFailure + | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true } + | LifetimeElisionKind::AnonymousReportError => { + assert!(had_count_error); + ctx.inferred_kind(def, param_id, param, infer_args, &substs) + } + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { + Region::new_static(interner).into() + } + LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false } + | LifetimeElisionKind::Infer => { + // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here + // (but this will probably be done in hir-def lowering instead). + ctx.inferred_kind(def, param_id, param, infer_args, &substs) + } + } + } else { + ctx.inferred_kind(def, param_id, param, infer_args, &substs) + }; + substs.push(param); + params.next(); + } + + (None, None) => break, + } + } + + crate::next_solver::GenericArgs::new_from_iter(interner, substs) +} + +fn type_looks_like_const( + store: &ExpressionStore, + type_ref: TypeRefId, +) -> Option> { + // A path/`_` const will be parsed as a type, instead of a const, because when parsing/lowering + // in hir-def we don't yet know the expected argument kind. rustc does this a bit differently, + // when lowering to HIR it resolves the path, and if it doesn't resolve to the type namespace + // it is lowered as a const. Our behavior could deviate from rustc when the value is resolvable + // in both the type and value namespaces, but I believe we only allow more code. + let type_ref = &store[type_ref]; + match type_ref { + TypeRef::Path(path) => Some(TypeLikeConst::Path(path)), + TypeRef::Placeholder => Some(TypeLikeConst::Infer), + _ => None, + } +} + +fn unknown_subst<'db>( + interner: DbInterner<'db>, + def: impl Into, +) -> crate::next_solver::GenericArgs<'db> { + let params = generics(interner.db(), def.into()); + crate::next_solver::GenericArgs::new_from_iter( + interner, + params.iter_id().map(|id| match id { + GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(), + GenericParamId::ConstParamId(id) => { + unknown_const_as_generic(const_param_ty_query(interner.db(), id)) + } + GenericParamId::LifetimeParamId(_) => { + crate::next_solver::Region::error(interner).into() + } + }), + ) +} + +pub(crate) fn builtin<'db>(interner: DbInterner<'db>, builtin: BuiltinType) -> Ty<'db> { + match builtin { + BuiltinType::Char => Ty::new(interner, rustc_type_ir::TyKind::Char), + BuiltinType::Bool => Ty::new_bool(interner), + BuiltinType::Str => Ty::new(interner, rustc_type_ir::TyKind::Str), + BuiltinType::Int(t) => { + let int_ty = match primitive::int_ty_from_builtin(t) { + chalk_ir::IntTy::Isize => rustc_type_ir::IntTy::Isize, + chalk_ir::IntTy::I8 => rustc_type_ir::IntTy::I8, + chalk_ir::IntTy::I16 => rustc_type_ir::IntTy::I16, + chalk_ir::IntTy::I32 => rustc_type_ir::IntTy::I32, + chalk_ir::IntTy::I64 => rustc_type_ir::IntTy::I64, + chalk_ir::IntTy::I128 => rustc_type_ir::IntTy::I128, + }; + Ty::new_int(interner, int_ty) + } + BuiltinType::Uint(t) => { + let uint_ty = match primitive::uint_ty_from_builtin(t) { + chalk_ir::UintTy::Usize => rustc_type_ir::UintTy::Usize, + chalk_ir::UintTy::U8 => rustc_type_ir::UintTy::U8, + chalk_ir::UintTy::U16 => rustc_type_ir::UintTy::U16, + chalk_ir::UintTy::U32 => rustc_type_ir::UintTy::U32, + chalk_ir::UintTy::U64 => rustc_type_ir::UintTy::U64, + chalk_ir::UintTy::U128 => rustc_type_ir::UintTy::U128, + }; + Ty::new_uint(interner, uint_ty) + } + BuiltinType::Float(t) => { + let float_ty = match primitive::float_ty_from_builtin(t) { + chalk_ir::FloatTy::F16 => rustc_type_ir::FloatTy::F16, + chalk_ir::FloatTy::F32 => rustc_type_ir::FloatTy::F32, + chalk_ir::FloatTy::F64 => rustc_type_ir::FloatTy::F64, + chalk_ir::FloatTy::F128 => rustc_type_ir::FloatTy::F128, + }; + Ty::new_float(interner, float_ty) + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index b22781e947013..49438151bbff5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -16,22 +16,24 @@ use hir_def::{ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; use crate::{ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, - Goal, Guidance, InEnvironment, Interner, Mutability, Scalar, Solution, Substitution, - TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, - VariableKind, WhereClause, + Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause, autoderef::{self, AutoderefKind}, db::HirDatabase, error_lifetime, from_chalk_trait_id, from_foreign_def_id, infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, lang_items::is_box, + next_solver::SolverDefId, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, + traits::NextTraitSolveResult, utils::all_super_traits, }; @@ -43,6 +45,7 @@ pub enum TyFingerprint { Slice, Array, Never, + Ref(Mutability), RawPtr(Mutability), Scalar(Scalar), // These can have user-defined impls: @@ -88,7 +91,7 @@ impl TyFingerprint { TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, - TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty), + TyKind::Ref(mutability, _, _) => TyFingerprint::Ref(*mutability), TyKind::Tuple(_, subst) => { let first_ty = subst.interned().first().map(|arg| arg.assert_ty_ref(Interner)); match first_ty { @@ -113,6 +116,94 @@ impl TyFingerprint { }; Some(fp) } + + /// Creates a TyFingerprint for looking up a trait impl. + pub fn for_trait_impl_ns<'db>(ty: &crate::next_solver::Ty<'db>) -> Option { + use rustc_type_ir::TyKind; + let fp = match (*ty).kind() { + TyKind::Str => TyFingerprint::Str, + TyKind::Never => TyFingerprint::Never, + TyKind::Slice(..) => TyFingerprint::Slice, + TyKind::Array(..) => TyFingerprint::Array, + TyKind::Int(int) => TyFingerprint::Scalar(Scalar::Int(match int { + rustc_type_ir::IntTy::Isize => IntTy::Isize, + rustc_type_ir::IntTy::I8 => IntTy::I8, + rustc_type_ir::IntTy::I16 => IntTy::I16, + rustc_type_ir::IntTy::I32 => IntTy::I32, + rustc_type_ir::IntTy::I64 => IntTy::I64, + rustc_type_ir::IntTy::I128 => IntTy::I128, + })), + TyKind::Uint(uint) => TyFingerprint::Scalar(Scalar::Uint(match uint { + rustc_type_ir::UintTy::Usize => UintTy::Usize, + rustc_type_ir::UintTy::U8 => UintTy::U8, + rustc_type_ir::UintTy::U16 => UintTy::U16, + rustc_type_ir::UintTy::U32 => UintTy::U32, + rustc_type_ir::UintTy::U64 => UintTy::U64, + rustc_type_ir::UintTy::U128 => UintTy::U128, + })), + TyKind::Float(float) => TyFingerprint::Scalar(Scalar::Float(match float { + rustc_type_ir::FloatTy::F16 => FloatTy::F16, + rustc_type_ir::FloatTy::F32 => FloatTy::F32, + rustc_type_ir::FloatTy::F64 => FloatTy::F64, + rustc_type_ir::FloatTy::F128 => FloatTy::F128, + })), + TyKind::Bool => TyFingerprint::Scalar(Scalar::Bool), + TyKind::Char => TyFingerprint::Scalar(Scalar::Char), + TyKind::Adt(def, _) => TyFingerprint::Adt(def.inner().id), + TyKind::RawPtr(.., mutability) => match mutability { + rustc_ast_ir::Mutability::Mut => TyFingerprint::RawPtr(Mutability::Mut), + rustc_ast_ir::Mutability::Not => TyFingerprint::RawPtr(Mutability::Not), + }, + TyKind::Foreign(def) => { + let SolverDefId::ForeignId(def) = def else { unreachable!() }; + TyFingerprint::ForeignType(crate::to_foreign_def_id(def)) + } + TyKind::Dynamic(bounds, _, _) => { + let trait_ref = bounds + .as_slice() + .iter() + .map(|b| (*b).skip_binder()) + .filter_map(|b| match b { + rustc_type_ir::ExistentialPredicate::Trait(t) => Some(t.def_id), + _ => None, + }) + .next()?; + let trait_id = match trait_ref { + SolverDefId::TraitId(id) => id, + _ => panic!("Bad GenericDefId in trait ref"), + }; + TyFingerprint::Dyn(trait_id) + } + TyKind::Ref(_, _, mutability) => match mutability { + rustc_ast_ir::Mutability::Mut => TyFingerprint::Ref(Mutability::Mut), + rustc_ast_ir::Mutability::Not => TyFingerprint::Ref(Mutability::Not), + }, + TyKind::Tuple(tys) => { + let first_ty = tys.as_slice().iter().next(); + match first_ty { + Some(ty) => return TyFingerprint::for_trait_impl_ns(ty), + None => TyFingerprint::Unit, + } + } + TyKind::FnDef(_, _) + | TyKind::Closure(_, _) + | TyKind::Coroutine(..) + | TyKind::CoroutineWitness(..) + | TyKind::Pat(..) + | TyKind::CoroutineClosure(..) => TyFingerprint::Unnameable, + TyKind::FnPtr(sig, _) => { + TyFingerprint::Function(sig.inputs().skip_binder().len() as u32) + } + TyKind::Alias(..) + | TyKind::Placeholder(_) + | TyKind::Bound(..) + | TyKind::Infer(_) + | TyKind::Error(_) + | TyKind::Param(..) + | TyKind::UnsafeBinder(..) => return None, + }; + Some(fp) + } } pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ @@ -807,10 +898,13 @@ fn find_matching_impl( let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs) .into_iter() - .map(|b| b.cast(Interner)); - let goal = crate::Goal::all(Interner, wcs); - table.try_obligation(goal.clone())?; - table.register_obligation(goal); + .map(|b| -> Goal { b.cast(Interner) }); + for goal in wcs { + if table.try_obligation(goal.clone()).no_solution() { + return None; + } + table.register_obligation(goal); + } Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) }) }) @@ -1313,7 +1407,7 @@ fn iterate_trait_method_candidates( }; if !known_implemented { let goal = generic_implements_goal(db, &table.trait_env, t, &canonical_self_ty); - if db.trait_solve(krate, block, goal.cast(Interner)).is_none() { + if db.trait_solve(krate, block, goal.cast(Interner)).no_solution() { continue 'traits; } } @@ -1496,9 +1590,9 @@ pub(crate) fn resolve_indexing_op( let deref_chain = autoderef_method_receiver(&mut table, ty); for (ty, adj) in deref_chain { let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty); - if db + if !db .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner)) - .is_some() + .no_solution() { return Some(adj); } @@ -1692,7 +1786,7 @@ fn is_valid_impl_fn_candidate( ); match solution { - Some(Solution::Unique(canonical_subst)) => { + NextTraitSolveResult::Certain(canonical_subst) => { canonicalized.apply_solution( table, Canonical { @@ -1701,16 +1795,13 @@ fn is_valid_impl_fn_candidate( }, ); } - Some(Solution::Ambig(Guidance::Definite(substs))) => { - canonicalized.apply_solution(table, substs); - } - Some(_) => (), - None => return IsValidCandidate::No, + NextTraitSolveResult::Uncertain(..) => {} + NextTraitSolveResult::NoSolution => return IsValidCandidate::No, } } for goal in goals { - if table.try_obligation(goal).is_none() { + if table.try_obligation(goal).no_solution() { return IsValidCandidate::No; } } @@ -1726,9 +1817,7 @@ pub fn implements_trait( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env, trait_, ty); - let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); - - solution.is_some() + !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution() } pub fn implements_trait_unique( @@ -1738,9 +1827,7 @@ pub fn implements_trait_unique( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env, trait_, ty); - let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner)); - - matches!(solution, Some(crate::Solution::Unique(_))) + db.trait_solve(env.krate, env.block, goal.cast(Interner)).certain() } /// This creates Substs for a trait with the given Self type and type variables 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 c1f86960e154c..eb5af58f2ea18 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 @@ -5,7 +5,9 @@ use syntax::{TextRange, TextSize}; use test_fixture::WithFixture; use crate::display::DisplayTarget; -use crate::{Interner, Substitution, db::HirDatabase, mir::MirLowerError, test_db::TestDB}; +use crate::{ + Interner, Substitution, db::HirDatabase, mir::MirLowerError, setup_tracing, test_db::TestDB, +}; use super::{MirEvalError, interpret_mir}; @@ -49,6 +51,7 @@ fn check_pass_and_stdio( expected_stdout: &str, expected_stderr: &str, ) { + let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let x = eval_main(&db, file_id); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index eb80e8706fa0c..0bb8e6fe79d65 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -2163,7 +2163,9 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result = rustc_type_ir::Binder, T>; +pub type EarlyBinder<'db, T> = rustc_type_ir::EarlyBinder, T>; +pub type Canonical<'db, T> = rustc_type_ir::Canonical, T>; +pub type CanonicalVarValues<'db> = rustc_type_ir::CanonicalVarValues>; +pub type CanonicalVarKind<'db> = rustc_type_ir::CanonicalVarKind>; +pub type CanonicalQueryInput<'db, V> = rustc_type_ir::CanonicalQueryInput, V>; +pub type AliasTy<'db> = rustc_type_ir::AliasTy>; +pub type PolyFnSig<'db> = Binder<'db, rustc_type_ir::FnSig>>; +pub type TypingMode<'db> = rustc_type_ir::TypingMode>; + +pub type FxIndexMap = + indexmap::IndexMap>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs new file mode 100644 index 0000000000000..80d1ea4aa4d00 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs @@ -0,0 +1,68 @@ +//! ABI-related things in the next-trait-solver. +use rustc_type_ir::{error::TypeError, relate::Relate}; + +use crate::FnAbi; + +use super::interner::DbInterner; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Safety { + Unsafe, + Safe, +} + +impl<'db> Relate> for Safety { + fn relate>>( + _relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + if a != b { + Err(TypeError::SafetyMismatch(rustc_type_ir::error::ExpectedFound::new(a, b))) + } else { + Ok(a) + } + } +} + +impl<'db> rustc_type_ir::inherent::Safety> for Safety { + fn safe() -> Self { + Self::Safe + } + + fn is_safe(self) -> bool { + matches!(self, Safety::Safe) + } + + fn prefix_str(self) -> &'static str { + match self { + Self::Unsafe => "unsafe ", + Self::Safe => "", + } + } +} + +impl<'db> Relate> for FnAbi { + fn relate>>( + _relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + if a == b { + Ok(a) + } else { + Err(TypeError::AbiMismatch(rustc_type_ir::error::ExpectedFound::new(a, b))) + } + } +} + +impl<'db> rustc_type_ir::inherent::Abi> for FnAbi { + fn rust() -> Self { + FnAbi::Rust + } + + fn is_rust(self) -> bool { + // TODO: rustc does not consider `RustCall` to be true here, but Chalk does + matches!(self, FnAbi::Rust | FnAbi::RustCall) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs new file mode 100644 index 0000000000000..5698ff290f748 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -0,0 +1,404 @@ +//! Things related to consts in the next-trait-solver. + +use std::hash::Hash; + +use intern::{Interned, Symbol}; +use rustc_ast_ir::try_visit; +use rustc_ast_ir::visit::VisitorResult; +use rustc_type_ir::{ + BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, WithCachedTypeInfo, + inherent::{IntoKind, PlaceholderLike}, + relate::Relate, +}; + +use crate::{ConstScalar, MemoryMap, interner::InternedWrapperNoDebug}; + +use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty}; + +pub type ConstKind<'db> = rustc_type_ir::ConstKind>; +pub type UnevaluatedConst<'db> = rustc_type_ir::UnevaluatedConst>; + +#[salsa::interned(constructor = new_, debug)] +pub struct Const<'db> { + #[returns(ref)] + kind_: InternedWrapperNoDebug>>, +} + +impl<'db> Const<'db> { + pub fn new(interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self { + let flags = FlagComputation::for_const_kind(&kind); + let cached = WithCachedTypeInfo { + internee: kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; + Const::new_(interner.db(), InternedWrapperNoDebug(cached)) + } + + pub fn inner(&self) -> &WithCachedTypeInfo> { + salsa::with_attached_database(|db| { + let inner = &self.kind_(db).0; + // SAFETY: The caller already has access to a `Const<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + + pub fn error(interner: DbInterner<'db>) -> Self { + Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) + } + + pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self { + Const::new(interner, rustc_type_ir::ConstKind::Param(param)) + } + + pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst) -> Self { + Const::new(interner, ConstKind::Placeholder(placeholder)) + } + + pub fn is_ct_infer(&self) -> bool { + matches!(&self.inner().internee, ConstKind::Infer(_)) + } + + pub fn is_trivially_wf(self) -> bool { + match self.kind() { + ConstKind::Param(_) | ConstKind::Placeholder(_) | ConstKind::Bound(..) => true, + ConstKind::Infer(_) + | ConstKind::Unevaluated(..) + | ConstKind::Value(_) + | ConstKind::Error(_) + | ConstKind::Expr(_) => false, + } + } +} + +impl<'db> std::fmt::Debug for InternedWrapperNoDebug>> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.internee.fmt(f) + } +} + +pub type PlaceholderConst = Placeholder; + +#[derive(Copy, Clone, Hash, Eq, PartialEq)] +pub struct ParamConst { + pub index: u32, +} + +impl std::fmt::Debug for ParamConst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#{}", self.index) + } +} + +/// A type-level constant value. +/// +/// Represents a typed, fully evaluated constant. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct ValueConst<'db> { + pub(crate) ty: Ty<'db>, + pub(crate) value: Valtree<'db>, +} + +impl<'db> ValueConst<'db> { + pub fn new(ty: Ty<'db>, bytes: ConstBytes) -> Self { + let value = Valtree::new(bytes); + ValueConst { ty, value } + } +} + +impl<'db> rustc_type_ir::inherent::ValueConst> for ValueConst<'db> { + fn ty(self) -> Ty<'db> { + self.ty + } + + fn valtree(self) -> Valtree<'db> { + self.value + } +} + +impl<'db> rustc_type_ir::TypeVisitable> for ValueConst<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + self.ty.visit_with(visitor) + } +} + +impl<'db> rustc_type_ir::TypeFoldable> for ValueConst<'db> { + fn fold_with>>(self, folder: &mut F) -> Self { + ValueConst { ty: self.ty.fold_with(folder), value: self.value } + } + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(ValueConst { ty: self.ty.try_fold_with(folder)?, value: self.value }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstBytes(pub Box<[u8]>, pub MemoryMap); + +impl Hash for ConstBytes { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +#[salsa::interned(constructor = new_, debug)] +pub struct Valtree<'db> { + #[returns(ref)] + bytes_: ConstBytes, +} + +impl<'db> Valtree<'db> { + pub fn new(bytes: ConstBytes) -> Self { + salsa::with_attached_database(|db| unsafe { + // SAFETY: ¯\_(ツ)_/¯ + std::mem::transmute(Valtree::new_(db, bytes)) + }) + .unwrap() + } + + pub fn inner(&self) -> &ConstBytes { + salsa::with_attached_database(|db| { + let inner = self.bytes_(db); + // SAFETY: The caller already has access to a `Valtree<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ExprConst; + +impl rustc_type_ir::inherent::ParamLike for ParamConst { + fn index(self) -> u32 { + self.index + } +} + +impl<'db> IntoKind for Const<'db> { + type Kind = ConstKind<'db>; + + fn kind(self) -> Self::Kind { + self.inner().internee + } +} + +impl<'db> TypeVisitable> for Const<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_const(*self) + } +} + +impl<'db> TypeSuperVisitable> for Const<'db> { + fn super_visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + match self.kind() { + ConstKind::Unevaluated(uv) => uv.visit_with(visitor), + ConstKind::Value(v) => v.visit_with(visitor), + ConstKind::Expr(e) => e.visit_with(visitor), + ConstKind::Error(e) => e.visit_with(visitor), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) => V::Result::output(), + } + } +} + +impl<'db> TypeFoldable> for Const<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + folder.try_fold_const(self) + } + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_const(self) + } +} + +impl<'db> TypeSuperFoldable> for Const<'db> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let kind = match self.kind() { + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), + ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), + ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return Ok(self), + }; + if kind != self.kind() { Ok(Const::new(folder.cx(), kind)) } else { Ok(self) } + } + fn super_fold_with>>( + self, + folder: &mut F, + ) -> Self { + let kind = match self.kind() { + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)), + ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)), + ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return self, + }; + if kind != self.kind() { Const::new(folder.cx(), kind) } else { self } + } +} + +impl<'db> Relate> for Const<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + relation.consts(a, b) + } +} + +impl<'db> Flags for Const<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + self.inner().flags + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.inner().outer_exclusive_binder + } +} + +impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { + fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferConst) -> Self { + Const::new(interner, ConstKind::Infer(var)) + } + + fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::ConstVid) -> Self { + Const::new(interner, ConstKind::Infer(rustc_type_ir::InferConst::Var(var))) + } + + fn new_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: BoundVar, + ) -> Self { + Const::new(interner, ConstKind::Bound(debruijn, var)) + } + + fn new_anon_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: rustc_type_ir::BoundVar, + ) -> Self { + Const::new(interner, ConstKind::Bound(debruijn, var)) + } + + fn new_unevaluated( + interner: DbInterner<'db>, + uv: rustc_type_ir::UnevaluatedConst>, + ) -> Self { + Const::new(interner, ConstKind::Unevaluated(uv)) + } + + fn new_expr(interner: DbInterner<'db>, expr: ExprConst) -> Self { + Const::new(interner, ConstKind::Expr(expr)) + } + + fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self { + Const::new(interner, ConstKind::Error(guar)) + } + + fn new_placeholder( + interner: DbInterner<'db>, + param: as rustc_type_ir::Interner>::PlaceholderConst, + ) -> Self { + Const::new(interner, ConstKind::Placeholder(param)) + } +} + +impl<'db> PlaceholderLike> for PlaceholderConst { + type Bound = rustc_type_ir::BoundVar; + + fn universe(self) -> rustc_type_ir::UniverseIndex { + self.universe + } + + fn var(self) -> rustc_type_ir::BoundVar { + self.bound + } + + fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self { + Placeholder { universe: ui, bound: self.bound } + } + + fn new(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { + Placeholder { universe: ui, bound: var } + } + fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { + Placeholder { universe: ui, bound: var } + } +} + +impl<'db> TypeVisitable> for ExprConst { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + // Ensure we get back to this when we fill in the fields + let ExprConst = &self; + V::Result::output() + } +} + +impl<'db> TypeFoldable> for ExprConst { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(ExprConst) + } + fn fold_with>>(self, folder: &mut F) -> Self { + ExprConst + } +} + +impl<'db> Relate> for ExprConst { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + // Ensure we get back to this when we fill in the fields + let ExprConst = b; + Ok(a) + } +} + +impl<'db> rustc_type_ir::inherent::ExprConst> for ExprConst { + fn args(self) -> as rustc_type_ir::Interner>::GenericArgs { + // Ensure we get back to this when we fill in the fields + let ExprConst = self; + GenericArgs::default() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs new file mode 100644 index 0000000000000..cfbc10e740e4b --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -0,0 +1,96 @@ +//! Definition of `SolverDefId` + +use hir_def::{ + AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, StaticId, StructId, + TraitAliasId, TraitId, TypeAliasId, UnionId, +}; +use rustc_type_ir::inherent; +use stdx::impl_from; + +use crate::db::{InternedClosureId, InternedCoroutineId, InternedOpaqueTyId}; + +use super::DbInterner; + +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +pub enum Ctor { + Struct(StructId), + Enum(EnumVariantId), +} + +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +pub enum SolverDefId { + AdtId(AdtId), + ConstId(ConstId), + FunctionId(FunctionId), + ImplId(ImplId), + StaticId(StaticId), + TraitAliasId(TraitAliasId), + TraitId(TraitId), + TypeAliasId(TypeAliasId), + ForeignId(TypeAliasId), + InternedClosureId(InternedClosureId), + InternedCoroutineId(InternedCoroutineId), + InternedOpaqueTyId(InternedOpaqueTyId), + Ctor(Ctor), +} + +impl_from!( + AdtId(StructId, EnumId, UnionId), + ConstId, + FunctionId, + ImplId, + StaticId, + TraitAliasId, + TraitId, + TypeAliasId, + InternedClosureId, + InternedCoroutineId, + InternedOpaqueTyId + for SolverDefId +); + +impl From for SolverDefId { + fn from(value: GenericDefId) -> Self { + match value { + GenericDefId::AdtId(adt_id) => SolverDefId::AdtId(adt_id), + GenericDefId::ConstId(const_id) => SolverDefId::ConstId(const_id), + GenericDefId::FunctionId(function_id) => SolverDefId::FunctionId(function_id), + GenericDefId::ImplId(impl_id) => SolverDefId::ImplId(impl_id), + GenericDefId::StaticId(static_id) => SolverDefId::StaticId(static_id), + GenericDefId::TraitAliasId(trait_alias_id) => SolverDefId::TraitAliasId(trait_alias_id), + GenericDefId::TraitId(trait_id) => SolverDefId::TraitId(trait_id), + GenericDefId::TypeAliasId(type_alias_id) => SolverDefId::TypeAliasId(type_alias_id), + } + } +} + +impl TryFrom for GenericDefId { + type Error = SolverDefId; + + fn try_from(value: SolverDefId) -> Result { + Ok(match value { + SolverDefId::AdtId(adt_id) => GenericDefId::AdtId(adt_id), + SolverDefId::ConstId(const_id) => GenericDefId::ConstId(const_id), + SolverDefId::FunctionId(function_id) => GenericDefId::FunctionId(function_id), + SolverDefId::ImplId(impl_id) => GenericDefId::ImplId(impl_id), + SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id), + SolverDefId::TraitAliasId(trait_alias_id) => GenericDefId::TraitAliasId(trait_alias_id), + SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id), + SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id), + SolverDefId::ForeignId(_) => return Err(value), + SolverDefId::InternedClosureId(_) => return Err(value), + SolverDefId::InternedCoroutineId(_) => return Err(value), + SolverDefId::InternedOpaqueTyId(_) => return Err(value), + SolverDefId::Ctor(_) => return Err(value), + }) + } +} + +impl<'db> inherent::DefId> for SolverDefId { + fn as_local(self) -> Option { + Some(self) + } + fn is_local(self) -> bool { + true + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs new file mode 100644 index 0000000000000..3cc1e64b6add0 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs @@ -0,0 +1,129 @@ +//! Fold impls for the next-trait-solver. + +use rustc_type_ir::{ + BoundVar, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, + inherent::{IntoKind, Region as _}, +}; + +use super::{ + Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, Ty, TyKind, +}; + +/// A delegate used when instantiating bound vars. +/// +/// Any implementation must make sure that each bound variable always +/// gets mapped to the same result. `BoundVarReplacer` caches by using +/// a `DelayedMap` which does not cache the first few types it encounters. +pub trait BoundVarReplacerDelegate<'db> { + fn replace_region(&mut self, br: BoundRegion) -> Region<'db>; + fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db>; + fn replace_const(&mut self, bv: BoundVar) -> Const<'db>; +} + +/// A simple delegate taking 3 mutable functions. The used functions must +/// always return the same result for each bound variable, no matter how +/// frequently they are called. +pub struct FnMutDelegate<'db, 'a> { + pub regions: &'a mut (dyn FnMut(BoundRegion) -> Region<'db> + 'a), + pub types: &'a mut (dyn FnMut(BoundTy) -> Ty<'db> + 'a), + pub consts: &'a mut (dyn FnMut(BoundVar) -> Const<'db> + 'a), +} + +impl<'db, 'a> BoundVarReplacerDelegate<'db> for FnMutDelegate<'db, 'a> { + fn replace_region(&mut self, br: BoundRegion) -> Region<'db> { + (self.regions)(br) + } + fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { + (self.types)(bt) + } + fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { + (self.consts)(bv) + } +} + +/// Replaces the escaping bound vars (late bound regions or bound types) in a type. +pub(crate) struct BoundVarReplacer<'db, D> { + interner: DbInterner<'db>, + /// As with `RegionFolder`, represents the index of a binder *just outside* + /// the ones we have visited. + current_index: DebruijnIndex, + + delegate: D, +} + +impl<'db, D: BoundVarReplacerDelegate<'db>> BoundVarReplacer<'db, D> { + pub fn new(tcx: DbInterner<'db>, delegate: D) -> Self { + BoundVarReplacer { interner: tcx, current_index: DebruijnIndex::ZERO, delegate } + } +} + +impl<'db, D> TypeFolder> for BoundVarReplacer<'db, D> +where + D: BoundVarReplacerDelegate<'db>, +{ + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_binder>>( + &mut self, + t: Binder<'db, T>, + ) -> Binder<'db, T> { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + match t.kind() { + TyKind::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + let ty = self.delegate.replace_ty(bound_ty); + debug_assert!(!ty.has_vars_bound_above(DebruijnIndex::ZERO)); + rustc_type_ir::shift_vars(self.interner, ty, self.current_index.as_u32()) + } + _ => { + if !t.has_vars_bound_at_or_above(self.current_index) { + t + } else { + t.super_fold_with(self) + } + } + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + match r.kind() { + RegionKind::ReBound(debruijn, br) if debruijn == self.current_index => { + let region = self.delegate.replace_region(br); + if let RegionKind::ReBound(debruijn1, br) = region.kind() { + // If the callback returns a bound region, + // that region should always use the INNERMOST + // debruijn index. Then we adjust it to the + // correct depth. + assert_eq!(debruijn1, DebruijnIndex::ZERO); + Region::new_bound(self.interner, debruijn, br) + } else { + region + } + } + _ => r, + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + match ct.kind() { + ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + let ct = self.delegate.replace_const(bound_const); + debug_assert!(!ct.has_vars_bound_above(DebruijnIndex::ZERO)); + rustc_type_ir::shift_vars(self.interner, ct, self.current_index.as_u32()) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs new file mode 100644 index 0000000000000..007a674ad399a --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -0,0 +1,229 @@ +//! Fulfill loop for next-solver. + +use std::marker::PhantomData; +use std::mem; +use std::ops::ControlFlow; +use std::vec::ExtractIf; + +use rustc_next_trait_solver::delegate::SolverDelegate; +use rustc_next_trait_solver::solve::{ + GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt, +}; +use rustc_type_ir::Interner; +use rustc_type_ir::inherent::Span as _; +use rustc_type_ir::solve::{Certainty, NoSolution}; + +use crate::next_solver::infer::InferCtxt; +use crate::next_solver::infer::traits::{PredicateObligation, PredicateObligations}; +use crate::next_solver::{DbInterner, SolverContext, Span, TypingMode}; + +type PendingObligations<'db> = + Vec<(PredicateObligation<'db>, Option>>)>; + +/// A trait engine using the new trait solver. +/// +/// This is mostly identical to how `evaluate_all` works inside of the +/// solver, except that the requirements are slightly different. +/// +/// Unlike `evaluate_all` it is possible to add new obligations later on +/// and we also have to track diagnostics information by using `Obligation` +/// instead of `Goal`. +/// +/// It is also likely that we want to use slightly different datastructures +/// here as this will have to deal with far more root goals than `evaluate_all`. +pub struct FulfillmentCtxt<'db> { + obligations: ObligationStorage<'db>, + + /// The snapshot in which this context was created. Using the context + /// outside of this snapshot leads to subtle bugs if the snapshot + /// gets rolled back. Because of this we explicitly check that we only + /// use the context in exactly this snapshot. + usable_in_snapshot: usize, +} + +#[derive(Default, Debug)] +struct ObligationStorage<'db> { + /// Obligations which resulted in an overflow in fulfillment itself. + /// + /// We cannot eagerly return these as error so we instead store them here + /// to avoid recomputing them each time `select_where_possible` is called. + /// This also allows us to return the correct `FulfillmentError` for them. + overflowed: Vec>, + pending: PendingObligations<'db>, +} + +impl<'db> ObligationStorage<'db> { + fn register( + &mut self, + obligation: PredicateObligation<'db>, + stalled_on: Option>>, + ) { + self.pending.push((obligation, stalled_on)); + } + + fn has_pending_obligations(&self) -> bool { + !self.pending.is_empty() || !self.overflowed.is_empty() + } + + fn clone_pending(&self) -> PredicateObligations<'db> { + let mut obligations: PredicateObligations<'db> = + self.pending.iter().map(|(o, _)| o.clone()).collect(); + obligations.extend(self.overflowed.iter().cloned()); + obligations + } + + fn drain_pending( + &mut self, + cond: impl Fn(&PredicateObligation<'db>) -> bool, + ) -> PendingObligations<'db> { + let (not_stalled, pending) = + mem::take(&mut self.pending).into_iter().partition(|(o, _)| cond(o)); + self.pending = pending; + not_stalled + } + + fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'db>) { + infcx.probe(|_| { + // IMPORTANT: we must not use solve any inference variables in the obligations + // as this is all happening inside of a probe. We use a probe to make sure + // we get all obligations involved in the overflow. We pretty much check: if + // we were to do another step of `select_where_possible`, which goals would + // change. + // FIXME: is merged, this can be removed. + self.overflowed.extend( + self.pending + .extract_if(.., |(o, stalled_on)| { + let goal = o.as_goal(); + let result = <&SolverContext<'db>>::from(infcx).evaluate_root_goal( + goal, + Span::dummy(), + stalled_on.take(), + ); + matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) + }) + .map(|(o, _)| o), + ); + }) + } +} + +impl<'db> FulfillmentCtxt<'db> { + pub fn new(infcx: &InferCtxt<'db>) -> FulfillmentCtxt<'db> { + FulfillmentCtxt { + obligations: Default::default(), + usable_in_snapshot: infcx.num_open_snapshots(), + } + } +} + +impl<'db> FulfillmentCtxt<'db> { + #[tracing::instrument(level = "trace", skip(self, infcx))] + pub(crate) fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'db>, + obligation: PredicateObligation<'db>, + ) { + assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + self.obligations.register(obligation, None); + } + + pub(crate) fn collect_remaining_errors( + &mut self, + infcx: &InferCtxt<'db>, + ) -> Vec> { + self.obligations + .pending + .drain(..) + .map(|(obligation, _)| NextSolverError::Ambiguity(obligation)) + .chain(self.obligations.overflowed.drain(..).map(NextSolverError::Overflow)) + .collect() + } + + pub(crate) fn select_where_possible( + &mut self, + infcx: &InferCtxt<'db>, + ) -> Vec> { + assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + let mut errors = Vec::new(); + loop { + let mut any_changed = false; + for (mut obligation, stalled_on) in self.obligations.drain_pending(|_| true) { + if obligation.recursion_depth >= infcx.interner.recursion_limit() { + self.obligations.on_fulfillment_overflow(infcx); + // Only return true errors that we have accumulated while processing. + return errors; + } + + let goal = obligation.as_goal(); + let delegate = <&SolverContext<'db>>::from(infcx); + if let Some(certainty) = delegate.compute_goal_fast_path(goal, Span::dummy()) { + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.obligations.register(obligation, None); + } + } + continue; + } + + let result = delegate.evaluate_root_goal(goal, Span::dummy(), stalled_on); + let GoalEvaluation { certainty, has_changed, stalled_on } = match result { + Ok(result) => result, + Err(NoSolution) => { + errors.push(NextSolverError::TrueError(obligation)); + continue; + } + }; + + if has_changed == HasChanged::Yes { + // We increment the recursion depth here to track the number of times + // this goal has resulted in inference progress. This doesn't precisely + // model the way that we track recursion depth in the old solver due + // to the fact that we only process root obligations, but it is a good + // approximation and should only result in fulfillment overflow in + // pathological cases. + obligation.recursion_depth += 1; + any_changed = true; + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on), + } + } + + if !any_changed { + break; + } + } + + errors + } + + pub(crate) fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'db>, + ) -> Vec> { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + + self.collect_remaining_errors(infcx) + } + + fn has_pending_obligations(&self) -> bool { + self.obligations.has_pending_obligations() + } + + fn pending_obligations(&self) -> PredicateObligations<'db> { + self.obligations.clone_pending() + } +} + +#[derive(Debug)] +pub enum NextSolverError<'db> { + TrueError(PredicateObligation<'db>), + Ambiguity(PredicateObligation<'db>), + Overflow(PredicateObligation<'db>), +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs new file mode 100644 index 0000000000000..85a79923a7295 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -0,0 +1,525 @@ +//! Things related to generic args in the next-trait-solver. + +use intern::{Interned, Symbol}; +use rustc_type_ir::{ + ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, + GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable, + Variance, + inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _}, + relate::{Relate, VarianceDiagInfo}, +}; +use smallvec::SmallVec; + +use crate::db::HirDatabase; + +use super::{ + Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys, + generics::{GenericParamDef, GenericParamDefKind, Generics}, + interned_vec_db, +}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum GenericArg<'db> { + Ty(Ty<'db>), + Lifetime(Region<'db>), + Const(Const<'db>), +} + +impl<'db> std::fmt::Debug for GenericArg<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ty(t) => std::fmt::Debug::fmt(t, f), + Self::Lifetime(r) => std::fmt::Debug::fmt(r, f), + Self::Const(c) => std::fmt::Debug::fmt(c, f), + } + } +} + +impl<'db> From> for GenericArg<'db> { + fn from(value: Term<'db>) -> Self { + match value { + Term::Ty(ty) => GenericArg::Ty(ty), + Term::Const(c) => GenericArg::Const(c), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum Term<'db> { + Ty(Ty<'db>), + Const(Const<'db>), +} + +impl<'db> std::fmt::Debug for Term<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ty(t) => std::fmt::Debug::fmt(t, f), + Self::Const(c) => std::fmt::Debug::fmt(c, f), + } + } +} + +impl<'db> Term<'db> { + pub fn expect_type(&self) -> Ty<'db> { + self.as_type().expect("expected a type, but found a const") + } + + pub fn is_trivially_wf(&self, tcx: DbInterner<'db>) -> bool { + match self.kind() { + TermKind::Ty(ty) => ty.is_trivially_wf(tcx), + TermKind::Const(ct) => ct.is_trivially_wf(), + } + } +} + +impl<'db> From> for GenericArg<'db> { + fn from(value: Ty<'db>) -> Self { + Self::Ty(value) + } +} + +impl<'db> From> for GenericArg<'db> { + fn from(value: Region<'db>) -> Self { + Self::Lifetime(value) + } +} + +impl<'db> From> for GenericArg<'db> { + fn from(value: Const<'db>) -> Self { + Self::Const(value) + } +} + +impl<'db> IntoKind for GenericArg<'db> { + type Kind = GenericArgKind>; + + fn kind(self) -> Self::Kind { + match self { + GenericArg::Ty(ty) => GenericArgKind::Type(ty), + GenericArg::Lifetime(region) => GenericArgKind::Lifetime(region), + GenericArg::Const(c) => GenericArgKind::Const(c), + } + } +} + +impl<'db> TypeVisitable> for GenericArg<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + match self { + GenericArg::Lifetime(lt) => lt.visit_with(visitor), + GenericArg::Ty(ty) => ty.visit_with(visitor), + GenericArg::Const(ct) => ct.visit_with(visitor), + } + } +} + +impl<'db> TypeFoldable> for GenericArg<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + match self.kind() { + GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into), + GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into), + GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), + } + } + fn fold_with>>(self, folder: &mut F) -> Self { + match self.kind() { + GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(), + GenericArgKind::Type(ty) => ty.fold_with(folder).into(), + GenericArgKind::Const(ct) => ct.fold_with(folder).into(), + } + } +} + +impl<'db> Relate> for GenericArg<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + match (a.kind(), b.kind()) { + (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { + Ok(relation.relate(a_lt, b_lt)?.into()) + } + (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { + Ok(relation.relate(a_ty, b_ty)?.into()) + } + (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { + Ok(relation.relate(a_ct, b_ct)?.into()) + } + (GenericArgKind::Lifetime(unpacked), x) => { + unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } + (GenericArgKind::Type(unpacked), x) => { + unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } + (GenericArgKind::Const(unpacked), x) => { + unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } + } + } +} + +interned_vec_db!(GenericArgs, GenericArg); + +impl<'db> rustc_type_ir::inherent::GenericArg> for GenericArg<'db> {} + +impl<'db> GenericArgs<'db> { + /// Creates an `GenericArgs` for generic parameter definitions, + /// by calling closures to obtain each kind. + /// The closures get to observe the `GenericArgs` as they're + /// being built, which can be used to correctly + /// replace defaults of generic parameters. + pub fn for_item( + interner: DbInterner<'db>, + def_id: SolverDefId, + mut mk_kind: F, + ) -> GenericArgs<'db> + where + F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let defs = interner.generics_of(def_id); + let count = defs.count(); + let mut args = SmallVec::with_capacity(count); + Self::fill_item(&mut args, interner, defs, &mut mk_kind); + interner.mk_args(&args) + } + + fn fill_item( + args: &mut SmallVec<[GenericArg<'db>; 8]>, + interner: DbInterner<'_>, + defs: Generics, + mk_kind: &mut F, + ) where + F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let self_len = defs.own_params.len() as u32; + if let Some(def_id) = defs.parent { + let parent_defs = interner.generics_of(def_id.into()); + Self::fill_item(args, interner, parent_defs, mk_kind); + } + Self::fill_single(args, &defs, mk_kind); + } + + fn fill_single(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F) + where + F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let start_len = args.len(); + args.reserve(defs.own_params.len()); + for param in &defs.own_params { + let kind = mk_kind(¶m.name, args.len() as u32, param.kind, args); + args.push(kind); + } + } +} + +impl<'db> rustc_type_ir::relate::Relate> for GenericArgs<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + let interner = relation.cx(); + CollectAndApply::collect_and_apply( + std::iter::zip(a.iter(), b.iter()).map(|(a, b)| { + relation.relate_with_variance( + Variance::Invariant, + VarianceDiagInfo::default(), + a, + b, + ) + }), + |g| GenericArgs::new_from_iter(interner, g.iter().cloned()), + ) + } +} + +impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs<'db> { + fn as_closure(self) -> ClosureArgs> { + ClosureArgs { args: self } + } + fn as_coroutine(self) -> CoroutineArgs> { + CoroutineArgs { args: self } + } + fn as_coroutine_closure(self) -> CoroutineClosureArgs> { + CoroutineClosureArgs { args: self } + } + fn rebase_onto( + self, + interner: DbInterner<'db>, + source_def_id: as rustc_type_ir::Interner>::DefId, + target: as rustc_type_ir::Interner>::GenericArgs, + ) -> as rustc_type_ir::Interner>::GenericArgs { + let defs = interner.generics_of(source_def_id); + interner.mk_args_from_iter(target.iter().chain(self.iter().skip(defs.count()))) + } + + fn identity_for_item( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + ) -> as rustc_type_ir::Interner>::GenericArgs { + Self::for_item(interner, def_id, |name, index, kind, _| mk_param(index, name, kind)) + } + + fn extend_with_error( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + original_args: &[ as rustc_type_ir::Interner>::GenericArg], + ) -> as rustc_type_ir::Interner>::GenericArgs { + Self::for_item(interner, def_id, |name, index, kind, _| { + if let Some(arg) = original_args.get(index as usize) { + *arg + } else { + error_for_param_kind(kind, interner) + } + }) + } + fn type_at(self, i: usize) -> as rustc_type_ir::Interner>::Ty { + self.inner() + .get(i) + .and_then(|g| g.as_type()) + .unwrap_or_else(|| Ty::new_error(DbInterner::conjure(), ErrorGuaranteed)) + } + + fn region_at(self, i: usize) -> as rustc_type_ir::Interner>::Region { + self.inner() + .get(i) + .and_then(|g| g.as_region()) + .unwrap_or_else(|| Region::error(DbInterner::conjure())) + } + + fn const_at(self, i: usize) -> as rustc_type_ir::Interner>::Const { + self.inner() + .get(i) + .and_then(|g| g.as_const()) + .unwrap_or_else(|| Const::error(DbInterner::conjure())) + } + + fn split_closure_args(self) -> rustc_type_ir::ClosureArgsParts> { + // FIXME: should use `ClosureSubst` when possible + match self.inner().as_slice() { + [parent_args @ .., sig_ty] => { + let interner = DbInterner::conjure(); + // This is stupid, but the next solver expects the first input to actually be a tuple + let sig_ty = match sig_ty.expect_ty().kind() { + TyKind::FnPtr(sig_tys, header) => Ty::new( + interner, + TyKind::FnPtr( + sig_tys.map_bound(|s| { + let inputs = Ty::new_tup_from_iter(interner, s.inputs().iter()); + let output = s.output(); + FnSigTys { + inputs_and_output: Tys::new_from_iter( + interner, + [inputs, output], + ), + } + }), + header, + ), + ), + _ => unreachable!("sig_ty should be last"), + }; + rustc_type_ir::ClosureArgsParts { + parent_args: GenericArgs::new_from_iter(interner, parent_args.iter().cloned()), + closure_sig_as_fn_ptr_ty: sig_ty, + closure_kind_ty: Ty::new(interner, TyKind::Int(IntTy::I8)), + tupled_upvars_ty: Ty::new_unit(interner), + } + } + _ => { + unreachable!("unexpected closure sig"); + } + } + } + + fn split_coroutine_closure_args( + self, + ) -> rustc_type_ir::CoroutineClosureArgsParts> { + match self.inner().as_slice() { + [ + parent_args @ .., + closure_kind_ty, + signature_parts_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty, + ] => rustc_type_ir::CoroutineClosureArgsParts { + parent_args: GenericArgs::new_from_iter( + DbInterner::conjure(), + parent_args.iter().cloned(), + ), + closure_kind_ty: closure_kind_ty.expect_ty(), + signature_parts_ty: signature_parts_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), + coroutine_witness_ty: coroutine_witness_ty.expect_ty(), + }, + _ => panic!("GenericArgs were likely not for a CoroutineClosure."), + } + } + + fn split_coroutine_args(self) -> rustc_type_ir::CoroutineArgsParts> { + let interner = DbInterner::conjure(); + match self.inner().as_slice() { + [parent_args @ .., resume_ty, yield_ty, return_ty] => { + rustc_type_ir::CoroutineArgsParts { + parent_args: GenericArgs::new_from_iter(interner, parent_args.iter().cloned()), + kind_ty: Ty::new_unit(interner), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + witness: Ty::new_unit(interner), + tupled_upvars_ty: Ty::new_unit(interner), + } + } + _ => panic!("GenericArgs were likely not for a Coroutine."), + } + } +} + +pub fn mk_param<'db>(index: u32, name: &Symbol, kind: GenericParamDefKind) -> GenericArg<'db> { + let name = name.clone(); + match kind { + GenericParamDefKind::Lifetime => { + Region::new_early_param(DbInterner::conjure(), EarlyParamRegion { index }).into() + } + GenericParamDefKind::Type => Ty::new_param(DbInterner::conjure(), index, name).into(), + GenericParamDefKind::Const => { + Const::new_param(DbInterner::conjure(), ParamConst { index }).into() + } + } +} + +pub fn error_for_param_kind<'db>( + kind: GenericParamDefKind, + interner: DbInterner<'db>, +) -> GenericArg<'db> { + match kind { + GenericParamDefKind::Lifetime => Region::error(interner).into(), + GenericParamDefKind::Type => Ty::new_error(interner, ErrorGuaranteed).into(), + GenericParamDefKind::Const => Const::error(interner).into(), + } +} + +impl<'db> IntoKind for Term<'db> { + type Kind = TermKind>; + + fn kind(self) -> Self::Kind { + match self { + Term::Ty(ty) => TermKind::Ty(ty), + Term::Const(c) => TermKind::Const(c), + } + } +} + +impl<'db> From> for Term<'db> { + fn from(value: Ty<'db>) -> Self { + Self::Ty(value) + } +} + +impl<'db> From> for Term<'db> { + fn from(value: Const<'db>) -> Self { + Self::Const(value) + } +} + +impl<'db> TypeVisitable> for Term<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + match self { + Term::Ty(ty) => ty.visit_with(visitor), + Term::Const(ct) => ct.visit_with(visitor), + } + } +} + +impl<'db> TypeFoldable> for Term<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + match self.kind() { + TermKind::Ty(ty) => ty.try_fold_with(folder).map(Into::into), + TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), + } + } + fn fold_with>>(self, folder: &mut F) -> Self { + match self.kind() { + TermKind::Ty(ty) => ty.fold_with(folder).into(), + TermKind::Const(ct) => ct.fold_with(folder).into(), + } + } +} + +impl<'db> Relate> for Term<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + match (a.kind(), b.kind()) { + (TermKind::Ty(a_ty), TermKind::Ty(b_ty)) => Ok(relation.relate(a_ty, b_ty)?.into()), + (TermKind::Const(a_ct), TermKind::Const(b_ct)) => { + Ok(relation.relate(a_ct, b_ct)?.into()) + } + (TermKind::Ty(unpacked), x) => { + unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } + (TermKind::Const(unpacked), x) => { + unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) + } + } + } +} + +impl<'db> rustc_type_ir::inherent::Term> for Term<'db> {} + +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum TermVid { + Ty(TyVid), + Const(ConstVid), +} + +impl From for TermVid { + fn from(value: TyVid) -> Self { + TermVid::Ty(value) + } +} + +impl From for TermVid { + fn from(value: ConstVid) -> Self { + TermVid::Const(value) + } +} + +impl<'db> DbInterner<'db> { + pub(super) fn mk_args(self, args: &[GenericArg<'db>]) -> GenericArgs<'db> { + GenericArgs::new_from_iter(self, args.iter().cloned()) + } + + pub(super) fn mk_args_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: rustc_type_ir::CollectAndApply, GenericArgs<'db>>, + { + T::collect_and_apply(iter, |xs| self.mk_args(xs)) + } + + pub(super) fn check_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) -> bool { + // TODO + true + } + + pub(super) fn debug_assert_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) { + // TODO + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs new file mode 100644 index 0000000000000..48f5e73f2562d --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -0,0 +1,147 @@ +//! Things related to generics in the next-trait-solver. + +use hir_def::{ + ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup, + TypeOrConstParamId, TypeParamId, + db::DefDatabase, + expr_store::ExpressionStore, + hir::generics::{ + GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId, + LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, TypeParamProvenance, + WherePredicate, + }, +}; +use hir_expand::name::Name; +use intern::Symbol; +use la_arena::Arena; +use rustc_type_ir::inherent::Ty as _; +use triomphe::Arc; + +use crate::{db::HirDatabase, generics::parent_generic_def, next_solver::Ty}; + +use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId}; + +use super::{DbInterner, GenericArg}; + +pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { + let mk_lt = |(index, (_, lt)): (usize, (_, &LifetimeParamData))| { + let name = lt.name.symbol().clone(); + let index = index as u32; + let kind = GenericParamDefKind::Lifetime; + GenericParamDef { name, index, kind } + }; + let mk_ty = |len_lt, (index, p): (usize, &TypeOrConstParamData)| { + let name = p + .name() + .map(|n| n.symbol().clone()) + .unwrap_or_else(|| Name::missing().symbol().clone()); + let index = (len_lt + index) as u32; + let kind = match p { + TypeOrConstParamData::TypeParamData(_) => GenericParamDefKind::Type, + TypeOrConstParamData::ConstParamData(_) => GenericParamDefKind::Const, + }; + GenericParamDef { name, index, kind } + }; + let own_params_for_generic_params = |params: &GenericParams| { + if params.trait_self_param().is_some() { + let len_lt = params.len_lifetimes() + 1; + params + .iter_type_or_consts() + .take(1) + .enumerate() + .map(|t| mk_ty(0, (t.0, t.1.1))) + .chain(params.iter_lt().enumerate().map(mk_lt)) + .chain( + params + .iter_type_or_consts() + .skip(1) + .enumerate() + .map(|t| mk_ty(len_lt, (t.0, t.1.1))), + ) + .collect() + } else { + let len_lt = params.len_lifetimes(); + params + .iter_lt() + .enumerate() + .map(mk_lt) + .chain( + params.iter_type_or_consts().enumerate().map(|t| mk_ty(len_lt, (t.0, t.1.1))), + ) + .collect() + } + }; + + let (parent, own_params) = match (def.try_into(), def) { + (Ok(def), _) => { + (parent_generic_def(db, def), own_params_for_generic_params(&db.generic_params(def))) + } + (_, SolverDefId::InternedOpaqueTyId(id)) => { + match db.lookup_intern_impl_trait_id(id) { + crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => { + // The opaque type itself does not have generics - only the parent function + (Some(GenericDefId::FunctionId(function_id)), vec![]) + } + crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => ( + None, + own_params_for_generic_params( + &db.generic_params(GenericDefId::TypeAliasId(type_alias_id)), + ), + ), + crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { + let param = TypeOrConstParamData::TypeParamData(TypeParamData { + name: None, + default: None, + provenance: TypeParamProvenance::TypeParamList, + }); + // Yes, there is a parent but we don't include it in the generics + (None, vec![mk_ty(0, (0, ¶m))]) + } + } + } + _ => panic!("No generics for {def:?}"), + }; + let parent_generics = parent.map(|def| Box::new(generics(db, def.into()))); + + Generics { + parent, + parent_count: parent_generics.map_or(0, |g| g.parent_count + g.own_params.len()), + own_params, + } +} + +#[derive(Debug)] +pub struct Generics { + pub parent: Option, + pub parent_count: usize, + pub own_params: Vec, +} + +#[derive(Debug)] +pub struct GenericParamDef { + pub(crate) name: Symbol, + //def_id: GenericDefId, + index: u32, + pub(crate) kind: GenericParamDefKind, +} + +impl GenericParamDef { + /// Returns the index of the param on the self generics only + /// (i.e. not including parent generics) + pub fn index(&self) -> u32 { + self.index + } +} + +#[derive(Copy, Clone, Debug)] +pub enum GenericParamDefKind { + Lifetime, + Type, + Const, +} + +impl<'db> rustc_type_ir::inherent::GenericsOf> for Generics { + fn count(&self) -> usize { + self.parent_count + self.own_params.len() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs new file mode 100644 index 0000000000000..d64c7ed626eb2 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs @@ -0,0 +1,333 @@ +//! A nice interface for working with the infcx. The basic idea is to +//! do `infcx.at(cause, param_env)`, which sets the "cause" of the +//! operation as well as the surrounding parameter environment. Then +//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a +//! subtype or equality relationship respectively. The first argument +//! is always the "expected" output from the POV of diagnostics. +//! +//! Examples: +//! ```ignore (fragment) +//! infcx.at(cause, param_env).sub(a, b) +//! // requires that `a <: b`, with `a` considered the "expected" type +//! +//! infcx.at(cause, param_env).sup(a, b) +//! // requires that `b <: a`, with `a` considered the "expected" type +//! +//! infcx.at(cause, param_env).eq(a, b) +//! // requires that `a == b`, with `a` considered the "expected" type +//! ``` +//! For finer-grained control, you can also do use `trace`: +//! ```ignore (fragment) +//! infcx.at(...).trace(a, b).sub(&c, &d) +//! ``` +//! This will set `a` and `b` as the "root" values for +//! error-reporting, but actually operate on `c` and `d`. This is +//! sometimes useful when the types of `c` and `d` are not traceable +//! things. (That system should probably be refactored.) + +use rustc_type_ir::{ + FnSig, GenericArgKind, TypingMode, Variance, + error::ExpectedFound, + inherent::{IntoKind, Span as _}, + relate::{Relate, TypeRelation, solver_relating::RelateExt}, +}; + +use crate::next_solver::{ + AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term, + TraitRef, Ty, +}; + +use super::{ + InferCtxt, InferOk, InferResult, TypeTrace, ValuePairs, + traits::{Obligation, ObligationCause}, +}; + +/// Whether we should define opaque types or just treat them opaquely. +/// +/// Currently only used to prevent predicate matching from matching anything +/// against opaque types. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum DefineOpaqueTypes { + Yes, + No, +} + +#[derive(Clone, Copy)] +pub struct At<'a, 'db> { + pub infcx: &'a InferCtxt<'db>, + pub cause: &'a ObligationCause, + pub param_env: ParamEnv<'db>, +} + +impl<'db> InferCtxt<'db> { + #[inline] + pub fn at<'a>(&'a self, cause: &'a ObligationCause, param_env: ParamEnv<'db>) -> At<'a, 'db> { + At { infcx: self, cause, param_env } + } + + /// Forks the inference context, creating a new inference context with the same inference + /// variables in the same state. This can be used to "branch off" many tests from the same + /// common state. + pub fn fork(&self) -> Self { + Self { + interner: self.interner, + typing_mode: self.typing_mode, + inner: self.inner.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), + universe: self.universe.clone(), + } + } + + /// Forks the inference context, creating a new inference context with the same inference + /// variables in the same state, except possibly changing the intercrate mode. This can be + /// used to "branch off" many tests from the same common state. Used in negative coherence. + pub fn fork_with_typing_mode(&self, typing_mode: TypingMode>) -> Self { + // Unlike `fork`, this invalidates all cache entries as they may depend on the + // typing mode. + + Self { + interner: self.interner, + typing_mode, + inner: self.inner.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), + universe: self.universe.clone(), + } + } +} + +pub trait ToTrace<'db>: Relate> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db>; +} + +impl<'a, 'db> At<'a, 'db> { + /// Makes `actual <: expected`. For example, if type-checking a + /// call like `foo(x)`, where `foo: fn(i32)`, you might have + /// `sup(i32, x)`, since the "expected" type is the type that + /// appears in the signature. + pub fn sup( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'db, ()> + where + T: ToTrace<'db>, + { + RelateExt::relate( + self.infcx, + self.param_env, + expected, + Variance::Contravariant, + actual, + Span::dummy(), + ) + .map(|goals| self.goals_to_obligations(goals)) + } + + /// Makes `expected <: actual`. + pub fn sub( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'db, ()> + where + T: ToTrace<'db>, + { + RelateExt::relate( + self.infcx, + self.param_env, + expected, + Variance::Covariant, + actual, + Span::dummy(), + ) + .map(|goals| self.goals_to_obligations(goals)) + } + + /// Makes `expected == actual`. + pub fn eq( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'db, ()> + where + T: ToTrace<'db>, + { + self.eq_trace( + define_opaque_types, + ToTrace::to_trace(self.cause, expected, actual), + expected, + actual, + ) + } + + /// Makes `expected == actual`. + pub fn eq_trace( + self, + define_opaque_types: DefineOpaqueTypes, + trace: TypeTrace<'db>, + expected: T, + actual: T, + ) -> InferResult<'db, ()> + where + T: Relate>, + { + RelateExt::relate( + self.infcx, + self.param_env, + expected, + Variance::Invariant, + actual, + Span::dummy(), + ) + .map(|goals| self.goals_to_obligations(goals)) + } + + pub fn relate( + self, + define_opaque_types: DefineOpaqueTypes, + expected: T, + variance: Variance, + actual: T, + ) -> InferResult<'db, ()> + where + T: ToTrace<'db>, + { + match variance { + Variance::Covariant => self.sub(define_opaque_types, expected, actual), + Variance::Invariant => self.eq(define_opaque_types, expected, actual), + Variance::Contravariant => self.sup(define_opaque_types, expected, actual), + + // We could make this make sense but it's not readily + // exposed and I don't feel like dealing with it. Note + // that bivariance in general does a bit more than just + // *nothing*, it checks that the types are the same + // "modulo variance" basically. + Variance::Bivariant => panic!("Bivariant given to `relate()`"), + } + } + + fn goals_to_obligations(&self, goals: Vec>>) -> InferOk<'db, ()> { + InferOk { + value: (), + obligations: goals + .into_iter() + .map(|goal| { + Obligation::new( + self.infcx.interner, + self.cause.clone(), + goal.param_env, + goal.predicate, + ) + }) + .collect(), + } + } +} + +impl<'db> ToTrace<'db> for Ty<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), + } + } +} + +impl<'db> ToTrace<'db> for Region<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) } + } +} + +impl<'db> ToTrace<'db> for Const<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), + } + } +} + +impl<'db> ToTrace<'db> for GenericArg<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: match (a.kind(), b.kind()) { + (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { + ValuePairs::Regions(ExpectedFound::new(a, b)) + } + (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { + ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())) + } + (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { + ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())) + } + _ => panic!("relating different kinds: {a:?} {b:?}"), + }, + } + } +} + +impl<'db> ToTrace<'db> for Term<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) } + } +} + +impl<'db> ToTrace<'db> for TraitRef<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) } + } +} + +impl<'db> ToTrace<'db> for AliasTy<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())), + } + } +} + +impl<'db> ToTrace<'db> for AliasTerm<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) } + } +} + +impl<'db> ToTrace<'db> for FnSig> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::PolySigs(ExpectedFound::new(Binder::dummy(a), Binder::dummy(b))), + } + } +} + +impl<'db> ToTrace<'db> for PolyFnSig<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) } + } +} + +impl<'db> ToTrace<'db> for PolyExistentialTraitRef<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)), + } + } +} + +impl<'db> ToTrace<'db> for PolyExistentialProjection<'db> { + fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)), + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs new file mode 100644 index 0000000000000..0448f03463e4b --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs @@ -0,0 +1,106 @@ +//! This module contains code to instantiate new values into a +//! `Canonical<'tcx, T>`. +//! +//! For an overview of what canonicalization is and how it fits into +//! rustc, check out the [chapter in the rustc dev guide][c]. +//! +//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html + +use crate::next_solver::{ + AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal, + ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind, + fold::FnMutDelegate, + infer::{ + DefineOpaqueTypes, InferCtxt, TypeTrace, + traits::{Obligation, PredicateObligations}, + }, +}; +use rustc_type_ir::{ + AliasRelationDirection, AliasTyKind, BoundVar, GenericArgKind, InferTy, TypeFoldable, Upcast, + Variance, + inherent::{IntoKind, SliceLike}, + relate::{ + Relate, TypeRelation, VarianceDiagInfo, + combine::{super_combine_consts, super_combine_tys}, + }, +}; + +pub trait CanonicalExt<'db, V> { + fn instantiate(&self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>) -> V + where + V: TypeFoldable>; + fn instantiate_projected( + &self, + tcx: DbInterner<'db>, + var_values: &CanonicalVarValues<'db>, + projection_fn: impl FnOnce(&V) -> T, + ) -> T + where + T: TypeFoldable>; +} + +/// FIXME(-Znext-solver): This or public because it is shared with the +/// new trait solver implementation. We should deduplicate canonicalization. +impl<'db, V> CanonicalExt<'db, V> for Canonical<'db, V> { + /// Instantiate the wrapped value, replacing each canonical value + /// with the value given in `var_values`. + fn instantiate(&self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>) -> V + where + V: TypeFoldable>, + { + self.instantiate_projected(tcx, var_values, |value| value.clone()) + } + + /// Allows one to apply a instantiation to some subset of + /// `self.value`. Invoke `projection_fn` with `self.value` to get + /// a value V that is expressed in terms of the same canonical + /// variables bound in `self` (usually this extracts from subset + /// of `self`). Apply the instantiation `var_values` to this value + /// V, replacing each of the canonical variables. + fn instantiate_projected( + &self, + tcx: DbInterner<'db>, + var_values: &CanonicalVarValues<'db>, + projection_fn: impl FnOnce(&V) -> T, + ) -> T + where + T: TypeFoldable>, + { + assert_eq!(self.variables.len(), var_values.len()); + let value = projection_fn(&self.value); + instantiate_value(tcx, var_values, value) + } +} + +/// Instantiate the values from `var_values` into `value`. `var_values` +/// must be values for the set of canonical variables that appear in +/// `value`. +pub(super) fn instantiate_value<'db, T>( + tcx: DbInterner<'db>, + var_values: &CanonicalVarValues<'db>, + value: T, +) -> T +where + T: TypeFoldable>, +{ + if var_values.var_values.is_empty() { + value + } else { + let delegate = FnMutDelegate { + regions: &mut |br: BoundRegion| match var_values[br.var].kind() { + GenericArgKind::Lifetime(l) => l, + r => panic!("{br:?} is a region but value is {r:?}"), + }, + types: &mut |bound_ty: BoundTy| match var_values[bound_ty.var].kind() { + GenericArgKind::Type(ty) => ty, + r => panic!("{bound_ty:?} is a type but value is {r:?}"), + }, + consts: &mut |bound_ct: BoundVar| match var_values[bound_ct].kind() { + GenericArgKind::Const(ct) => ct, + c => panic!("{bound_ct:?} is a const but value is {c:?}"), + }, + }; + + tcx.replace_escaping_bound_vars_uncached(value, delegate) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs new file mode 100644 index 0000000000000..4457e1340d584 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -0,0 +1,156 @@ +//! **Canonicalization** is the key to constructing a query in the +//! middle of type inference. Ordinarily, it is not possible to store +//! types from type inference in query keys, because they contain +//! references to inference variables whose lifetimes are too short +//! and so forth. Canonicalizing a value T1 using `canonicalize_query` +//! produces two things: +//! +//! - a value T2 where each unbound inference variable has been +//! replaced with a **canonical variable**; +//! - a map M (of type `CanonicalVarValues`) from those canonical +//! variables back to the original. +//! +//! We can then do queries using T2. These will give back constraints +//! on the canonical variables which can be translated, using the map +//! M, into constraints in our source context. This process of +//! translating the results back is done by the +//! `instantiate_query_result` method. +//! +//! For a more detailed look at what is happening here, check +//! out the [chapter in the rustc dev guide][c]. +//! +//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html + +use crate::next_solver::{ + AliasTy, Binder, Canonical, CanonicalVarValues, CanonicalVars, Const, DbInterner, GenericArg, + Goal, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind, + Region, Ty, TyKind, + infer::{ + DefineOpaqueTypes, InferCtxt, TypeTrace, + traits::{Obligation, PredicateObligations}, + }, +}; +use instantiate::CanonicalExt; +use rustc_index::IndexVec; +use rustc_type_ir::{ + AliasRelationDirection, AliasTyKind, CanonicalTyVarKind, CanonicalVarKind, InferTy, + TypeFoldable, UniverseIndex, Upcast, Variance, + inherent::{SliceLike, Ty as _}, + relate::{ + Relate, TypeRelation, VarianceDiagInfo, + combine::{super_combine_consts, super_combine_tys}, + }, +}; + +pub mod instantiate; + +impl<'db> InferCtxt<'db> { + /// Creates an instantiation S for the canonical value with fresh inference + /// variables and placeholders then applies it to the canonical value. + /// Returns both the instantiated result *and* the instantiation S. + /// + /// This can be invoked as part of constructing an + /// inference context at the start of a query (see + /// `InferCtxtBuilder::build_with_canonical`). It basically + /// brings the canonical value "into scope" within your new infcx. + /// + /// At the end of processing, the instantiation S (once + /// canonicalized) then represents the values that you computed + /// for each of the canonical inputs to your query. + pub fn instantiate_canonical( + &self, + canonical: &Canonical<'db, T>, + ) -> (T, CanonicalVarValues<'db>) + where + T: TypeFoldable>, + { + // For each universe that is referred to in the incoming + // query, create a universe in our local inference context. In + // practice, as of this writing, all queries have no universes + // in them, so this code has no effect, but it is looking + // forward to the day when we *do* want to carry universes + // through into queries. + // + // Instantiate the root-universe content into the current universe, + // and create fresh universes for the higher universes. + let universes: IndexVec = std::iter::once(self.universe()) + .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe())) + .collect(); + + let canonical_inference_vars = + self.instantiate_canonical_vars(canonical.variables, |ui| universes[ui]); + let result = canonical.instantiate(self.interner, &canonical_inference_vars); + (result, canonical_inference_vars) + } + + /// Given the "infos" about the canonical variables from some + /// canonical, creates fresh variables with the same + /// characteristics (see `instantiate_canonical_var` for + /// details). You can then use `instantiate` to instantiate the + /// canonical variable with these inference variables. + fn instantiate_canonical_vars( + &self, + variables: CanonicalVars<'db>, + universe_map: impl Fn(UniverseIndex) -> UniverseIndex, + ) -> CanonicalVarValues<'db> { + CanonicalVarValues { + var_values: self.interner.mk_args_from_iter( + variables.iter().map(|info| self.instantiate_canonical_var(info, &universe_map)), + ), + } + } + + /// Given the "info" about a canonical variable, creates a fresh + /// variable for it. If this is an existentially quantified + /// variable, then you'll get a new inference variable; if it is a + /// universally quantified variable, you get a placeholder. + /// + /// FIXME(-Znext-solver): This is public because it's used by the + /// new trait solver which has a different canonicalization routine. + /// We should somehow deduplicate all of this. + pub fn instantiate_canonical_var( + &self, + cv_info: CanonicalVarKind>, + universe_map: impl Fn(UniverseIndex) -> UniverseIndex, + ) -> GenericArg<'db> { + match cv_info { + CanonicalVarKind::Ty(ty_kind) => { + let ty = match ty_kind { + CanonicalTyVarKind::General(ui) => { + self.next_ty_var_in_universe(universe_map(ui)) + } + + CanonicalTyVarKind::Int => self.next_int_var(), + + CanonicalTyVarKind::Float => self.next_float_var(), + }; + ty.into() + } + + CanonicalVarKind::PlaceholderTy(PlaceholderTy { universe, bound }) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped = PlaceholderTy { universe: universe_mapped, bound }; + Ty::new_placeholder(self.interner, placeholder_mapped).into() + } + + CanonicalVarKind::Region(ui) => { + self.next_region_var_in_universe(universe_map(ui)).into() + } + + CanonicalVarKind::PlaceholderRegion(PlaceholderRegion { universe, bound }) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped: crate::next_solver::Placeholder< + crate::next_solver::BoundRegion, + > = PlaceholderRegion { universe: universe_mapped, bound }; + Region::new_placeholder(self.interner, placeholder_mapped).into() + } + + CanonicalVarKind::Const(ui) => self.next_const_var_in_universe(universe_map(ui)).into(), + CanonicalVarKind::PlaceholderConst(PlaceholderConst { universe, bound }) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped = PlaceholderConst { universe: universe_mapped, bound }; + Const::new_placeholder(self.interner, placeholder_mapped).into() + } + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs new file mode 100644 index 0000000000000..93fd6eeab34e4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs @@ -0,0 +1,316 @@ +//! Definition of `InferCtxtLike` from the librarified type layer. + +use rustc_type_ir::{ + ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntTy, IntVarValue, + IntVid, RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex, + inherent::{Const as _, IntoKind, Span as _, Ty as _}, + relate::combine::PredicateEmittingRelation, +}; + +use crate::next_solver::{ + Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, ParamEnv, + Region, SolverDefId, Span, Ty, TyKind, + infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries}, +}; + +use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult, traits::ObligationCause}; + +impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { + type Interner = DbInterner<'db>; + + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn next_trait_solver(&self) -> bool { + true + } + + fn typing_mode(&self) -> TypingMode> { + self.typing_mode() + } + + fn universe(&self) -> UniverseIndex { + self.universe() + } + + fn create_next_universe(&self) -> UniverseIndex { + self.create_next_universe() + } + + fn universe_of_ty(&self, vid: TyVid) -> Option { + self.probe_ty_var(vid).err() + } + + fn universe_of_lt(&self, lt: RegionVid) -> Option { + self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt).err() + } + + fn universe_of_ct(&self, ct: ConstVid) -> Option { + self.probe_const_var(ct).err() + } + + fn root_ty_var(&self, var: TyVid) -> TyVid { + self.root_var(var) + } + + fn root_const_var(&self, var: ConstVid) -> ConstVid { + self.root_const_var(var) + } + + fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'db> { + match self.probe_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.interner, self.root_var(vid)), + } + } + + fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'db> { + self.opportunistic_resolve_int_var(vid) + } + + fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'db> { + self.opportunistic_resolve_float_var(vid) + } + + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> Const<'db> { + match self.probe_const_var(vid) { + Ok(ct) => ct, + Err(_) => Const::new_var(self.interner, self.root_const_var(vid)), + } + } + + fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> Region<'db> { + self.inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.interner, vid) + } + + fn is_changed_arg(&self, arg: ::GenericArg) -> bool { + match arg.kind() { + GenericArgKind::Lifetime(_) => { + // Lifetimes should not change affect trait selection. + false + } + GenericArgKind::Type(ty) => { + if let TyKind::Infer(infer_ty) = ty.kind() { + match infer_ty { + InferTy::TyVar(vid) => { + !self.probe_ty_var(vid).is_err_and(|_| self.root_var(vid) == vid) + } + InferTy::IntVar(vid) => { + let mut inner = self.inner.borrow_mut(); + !matches!( + inner.int_unification_table().probe_value(vid), + IntVarValue::Unknown + if inner.int_unification_table().find(vid) == vid + ) + } + InferTy::FloatVar(vid) => { + let mut inner = self.inner.borrow_mut(); + !matches!( + inner.float_unification_table().probe_value(vid), + FloatVarValue::Unknown + if inner.float_unification_table().find(vid) == vid + ) + } + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => { + true + } + } + } else { + true + } + } + GenericArgKind::Const(ct) => { + if let ConstKind::Infer(infer_ct) = ct.kind() { + match infer_ct { + InferConst::Var(vid) => !self + .probe_const_var(vid) + .is_err_and(|_| self.root_const_var(vid) == vid), + InferConst::Fresh(_) => true, + } + } else { + true + } + } + } + } + + fn next_ty_infer(&self) -> Ty<'db> { + self.next_ty_var() + } + + fn next_region_infer(&self) -> ::Region { + self.next_region_var() + } + + fn next_const_infer(&self) -> Const<'db> { + self.next_const_var() + } + + fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { + self.fresh_args_for_item(def_id) + } + + fn instantiate_binder_with_infer> + Clone>( + &self, + value: Binder<'db, T>, + ) -> T { + self.instantiate_binder_with_fresh_vars(BoundRegionConversionTime::HigherRankedType, value) + } + + fn enter_forall> + Clone, U>( + &self, + value: Binder<'db, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.enter_forall(value, f) + } + + fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + self.inner.borrow_mut().type_variables().equate(a, b); + } + + fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) { + self.inner.borrow_mut().int_unification_table().union(a, b); + } + + fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) { + self.inner.borrow_mut().float_unification_table().union(a, b); + } + + fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) { + self.inner.borrow_mut().const_unification_table().union(a, b); + } + + fn instantiate_ty_var_raw>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: rustc_type_ir::TyVid, + instantiation_variance: rustc_type_ir::Variance, + source_ty: Ty<'db>, + ) -> RelateResult<'db, ()> { + self.instantiate_ty_var( + relation, + target_is_expected, + target_vid, + instantiation_variance, + source_ty, + ) + } + + fn instantiate_int_var_raw( + &self, + vid: rustc_type_ir::IntVid, + value: rustc_type_ir::IntVarValue, + ) { + self.inner.borrow_mut().int_unification_table().union_value(vid, value); + } + + fn instantiate_float_var_raw( + &self, + vid: rustc_type_ir::FloatVid, + value: rustc_type_ir::FloatVarValue, + ) { + self.inner.borrow_mut().float_unification_table().union_value(vid, value); + } + + fn instantiate_const_var_raw>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: rustc_type_ir::ConstVid, + source_ct: Const<'db>, + ) -> RelateResult<'db, ()> { + self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct) + } + + fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + self.set_tainted_by_errors(e) + } + + fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { + self.shallow_resolve(ty) + } + fn shallow_resolve_const(&self, ct: Const<'db>) -> Const<'db> { + self.shallow_resolve_const(ct) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.resolve_vars_if_possible(value) + } + + fn probe(&self, probe: impl FnOnce() -> T) -> T { + self.probe(|_| probe()) + } + + fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, span: Span) { + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(sub, sup); + } + + fn equate_regions(&self, a: Region<'db>, b: Region<'db>, span: Span) { + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(a, b); + } + + fn register_ty_outlives(&self, ty: Ty<'db>, r: Region<'db>, span: Span) { + //self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(Span::dummy())); + } + + type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; + + fn opaque_types_storage_num_entries(&self) -> OpaqueTypeStorageEntries { + self.inner.borrow_mut().opaque_types().num_entries() + } + fn clone_opaque_types_lookup_table(&self) -> Vec<(OpaqueTypeKey<'db>, Ty<'db>)> { + self.inner.borrow_mut().opaque_types().iter_lookup_table().map(|(k, h)| (k, h.ty)).collect() + } + fn clone_duplicate_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, Ty<'db>)> { + self.inner + .borrow_mut() + .opaque_types() + .iter_duplicate_entries() + .map(|(k, h)| (k, h.ty)) + .collect() + } + fn clone_opaque_types_added_since( + &self, + prev_entries: OpaqueTypeStorageEntries, + ) -> Vec<(OpaqueTypeKey<'db>, Ty<'db>)> { + self.inner + .borrow_mut() + .opaque_types() + .opaque_types_added_since(prev_entries) + .map(|(k, h)| (k, h.ty)) + .collect() + } + + fn register_hidden_type_in_storage( + &self, + opaque_type_key: OpaqueTypeKey<'db>, + hidden_ty: Ty<'db>, + _span: Span, + ) -> Option> { + self.register_hidden_type_in_storage(opaque_type_key, OpaqueHiddenType { ty: hidden_ty }) + } + fn add_duplicate_opaque_type( + &self, + opaque_type_key: OpaqueTypeKey<'db>, + hidden_ty: Ty<'db>, + _span: Span, + ) { + self.inner + .borrow_mut() + .opaque_types() + .add_duplicate(opaque_type_key, OpaqueHiddenType { ty: hidden_ty }) + } + + fn reset_opaque_types(&self) { + let _ = self.take_opaque_types(); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs new file mode 100644 index 0000000000000..19ae76f7e358f --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -0,0 +1,1066 @@ +//! Infer context the next-trait-solver. + +use std::cell::{Cell, RefCell}; +use std::fmt; +use std::sync::Arc; + +pub use BoundRegionConversionTime::*; +pub use at::DefineOpaqueTypes; +use ena::undo_log::UndoLogs; +use ena::unify as ut; +use intern::Symbol; +use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage}; +use region_constraints::{ + GenericKind, RegionConstraintCollector, RegionConstraintStorage, UndoLog, VarInfos, VerifyBound, +}; +pub use relate::StructurallyRelateAliases; +pub use relate::combine::PredicateEmittingRelation; +use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_pattern_analysis::Captures; +use rustc_type_ir::error::{ExpectedFound, TypeError}; +use rustc_type_ir::inherent::{ + Const as _, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Term as _, + Ty as _, +}; +use rustc_type_ir::{ + BoundVar, ClosureKind, ConstVid, FloatTy, FloatVarValue, FloatVid, GenericArgKind, InferConst, + InferTy, IntTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex, +}; +use rustc_type_ir::{TermKind, TypeVisitableExt}; +use rustc_type_ir::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use snapshot::undo_log::InferCtxtUndoLogs; +use tracing::{debug, instrument}; +use traits::{ObligationCause, PredicateObligations}; +use type_variable::TypeVariableOrigin; +use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; + +use crate::next_solver::fold::BoundVarReplacerDelegate; +use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries; +use crate::next_solver::{BoundRegion, BoundTy, BoundVarKind}; + +use super::generics::{GenericParamDef, GenericParamDefKind}; +use super::{ + AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, + DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, + PlaceholderRegion, PolyCoercePredicate, PolyExistentialProjection, PolyExistentialTraitRef, + PolyFnSig, PolyRegionOutlivesPredicate, PolySubtypePredicate, Predicate, Region, SolverDefId, + SubtypePredicate, Term, TraitPredicate, TraitRef, Ty, TyKind, TypingMode, +}; + +pub mod at; +pub mod canonical; +mod context; +mod opaque_types; +pub mod region_constraints; +pub mod relate; +pub mod resolve; +pub(crate) mod snapshot; +pub(crate) mod traits; +mod type_variable; +mod unify_key; + +/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper +/// around `PredicateObligations`, but it has one important property: +/// because `InferOk` is marked with `#[must_use]`, if you have a method +/// `InferCtxt::f` that returns `InferResult<()>` and you call it with +/// `infcx.f()?;` you'll get a warning about the obligations being discarded +/// without use, which is probably unintentional and has been a source of bugs +/// in the past. +#[must_use] +#[derive(Debug)] +pub struct InferOk<'db, T> { + pub value: T, + pub obligations: PredicateObligations<'db>, +} +pub type InferResult<'db, T> = Result, TypeError>>; + +pub(crate) type FixupResult = Result; // "fixup result" + +pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable< + ut::InPlace, &'a mut InferCtxtUndoLogs<'db>>, +>; + +/// This type contains all the things within `InferCtxt` that sit within a +/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot +/// operations are hot enough that we want only one call to `borrow_mut` per +/// call to `start_snapshot` and `rollback_to`. +#[derive(Clone)] +pub struct InferCtxtInner<'db> { + pub(crate) undo_log: InferCtxtUndoLogs<'db>, + + /// We instantiate `UnificationTable` with `bounds` because the types + /// that might instantiate a general type variable have an order, + /// represented by its upper and lower bounds. + pub(crate) type_variable_storage: type_variable::TypeVariableStorage<'db>, + + /// Map from const parameter variable to the kind of const it represents. + pub(crate) const_unification_storage: ut::UnificationTableStorage>, + + /// Map from integral variable to the kind of integer it represents. + pub(crate) int_unification_storage: ut::UnificationTableStorage, + + /// Map from floating variable to the kind of float it represents. + pub(crate) float_unification_storage: ut::UnificationTableStorage, + + /// Tracks the set of region variables and the constraints between them. + /// + /// This is initially `Some(_)` but when + /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` + /// -- further attempts to perform unification, etc., may fail if new + /// region constraints would've been added. + pub(crate) region_constraint_storage: Option>, + + /// A set of constraints that regionck must validate. + /// + /// Each constraint has the form `T:'a`, meaning "some type `T` must + /// outlive the lifetime 'a". These constraints derive from + /// instantiated type parameters. So if you had a struct defined + /// like the following: + /// ```ignore (illustrative) + /// struct Foo { ... } + /// ``` + /// In some expression `let x = Foo { ... }`, it will + /// instantiate the type parameter `T` with a fresh type `$0`. At + /// the same time, it will record a region obligation of + /// `$0: 'static`. This will get checked later by regionck. (We + /// can't generally check these things right away because we have + /// to wait until types are resolved.) + /// + /// These are stored in a map keyed to the id of the innermost + /// enclosing fn body / static initializer expression. This is + /// because the location where the obligation was incurred can be + /// relevant with respect to which sublifetime assumptions are in + /// place. The reason that we store under the fn-id, and not + /// something more fine-grained, is so that it is easier for + /// regionck to be sure that it has found *all* the region + /// obligations (otherwise, it's easy to fail to walk to a + /// particular node-id). + /// + /// Before running `resolve_regions_and_report_errors`, the creator + /// of the inference context is expected to invoke + /// [`InferCtxt::process_registered_region_obligations`] + /// for each body-id in this map, which will process the + /// obligations within. This is expected to be done 'late enough' + /// that all type inference variables have been bound and so forth. + pub(crate) region_obligations: Vec>, + + /// Caches for opaque type inference. + pub(crate) opaque_type_storage: OpaqueTypeStorage<'db>, +} + +impl<'db> InferCtxtInner<'db> { + fn new() -> InferCtxtInner<'db> { + InferCtxtInner { + undo_log: InferCtxtUndoLogs::default(), + + type_variable_storage: Default::default(), + const_unification_storage: Default::default(), + int_unification_storage: Default::default(), + float_unification_storage: Default::default(), + region_constraint_storage: Some(Default::default()), + region_obligations: vec![], + opaque_type_storage: Default::default(), + } + } + + #[inline] + pub fn region_obligations(&self) -> &[RegionObligation<'db>] { + &self.region_obligations + } + + #[inline] + fn try_type_variables_probe_ref( + &self, + vid: TyVid, + ) -> Option<&type_variable::TypeVariableValue<'db>> { + // Uses a read-only view of the unification table, this way we don't + // need an undo log. + self.type_variable_storage.eq_relations_ref().try_probe_value(vid) + } + + #[inline] + fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'db> { + self.type_variable_storage.with_log(&mut self.undo_log) + } + + #[inline] + pub(crate) fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'db> { + self.opaque_type_storage.with_log(&mut self.undo_log) + } + + #[inline] + fn int_unification_table(&mut self) -> UnificationTable<'_, 'db, IntVid> { + self.int_unification_storage.with_log(&mut self.undo_log) + } + + #[inline] + fn float_unification_table(&mut self) -> UnificationTable<'_, 'db, FloatVid> { + self.float_unification_storage.with_log(&mut self.undo_log) + } + + #[inline] + fn const_unification_table(&mut self) -> UnificationTable<'_, 'db, ConstVidKey<'db>> { + self.const_unification_storage.with_log(&mut self.undo_log) + } + + #[inline] + pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'db, '_> { + self.region_constraint_storage + .as_mut() + .expect("region constraints already solved") + .with_log(&mut self.undo_log) + } +} + +pub struct InferCtxt<'db> { + pub interner: DbInterner<'db>, + + /// The mode of this inference context, see the struct documentation + /// for more details. + typing_mode: TypingMode<'db>, + + pub inner: RefCell>, + + /// When an error occurs, we want to avoid reporting "derived" + /// errors that are due to this original failure. We have this + /// flag that one can set whenever one creates a type-error that + /// is due to an error in a prior pass. + /// + /// Don't read this flag directly, call `is_tainted_by_errors()` + /// and `set_tainted_by_errors()`. + tainted_by_errors: Cell>, + + /// What is the innermost universe we have created? Starts out as + /// `UniverseIndex::root()` but grows from there as we enter + /// universal quantifiers. + /// + /// N.B., at present, we exclude the universal quantifiers on the + /// item we are type-checking, and just consider those names as + /// part of the root universe. So this would only get incremented + /// when we enter into a higher-ranked (`for<..>`) type or trait + /// bound. + universe: Cell, +} + +/// See the `error_reporting` module for more details. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ValuePairs<'db> { + Regions(ExpectedFound>), + Terms(ExpectedFound>), + Aliases(ExpectedFound>), + TraitRefs(ExpectedFound>), + PolySigs(ExpectedFound>), + ExistentialTraitRef(ExpectedFound>), + ExistentialProjection(ExpectedFound>), +} + +impl<'db> ValuePairs<'db> { + pub fn ty(&self) -> Option<(Ty<'db>, Ty<'db>)> { + if let ValuePairs::Terms(ExpectedFound { expected, found }) = self + && let Some(expected) = expected.as_type() + && let Some(found) = found.as_type() + { + return Some((expected, found)); + } + None + } +} + +/// The trace designates the path through inference that we took to +/// encounter an error or subtyping constraint. +/// +/// See the `error_reporting` module for more details. +#[derive(Clone, Debug)] +pub struct TypeTrace<'db> { + pub cause: ObligationCause, + pub values: ValuePairs<'db>, +} + +/// Times when we replace bound regions with existentials: +#[derive(Clone, Copy, Debug)] +pub enum BoundRegionConversionTime { + /// when a fn is called + FnCall, + + /// when two higher-ranked types are compared + HigherRankedType, + + /// when projecting an associated type + AssocTypeProjection(SolverDefId), +} + +#[derive(Copy, Clone, Debug)] +pub struct FixupError { + unresolved: TyOrConstInferVar, +} + +impl fmt::Display for FixupError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use TyOrConstInferVar::*; + + match self.unresolved { + TyInt(_) => write!( + f, + "cannot determine the type of this integer; \ + add a suffix to specify the type explicitly" + ), + TyFloat(_) => write!( + f, + "cannot determine the type of this number; \ + add a suffix to specify the type explicitly" + ), + Ty(_) => write!(f, "unconstrained type"), + Const(_) => write!(f, "unconstrained const value"), + } + } +} + +/// See the `region_obligations` field for more information. +#[derive(Clone, Debug)] +pub struct RegionObligation<'db> { + pub sub_region: Region<'db>, + pub sup_type: Ty<'db>, +} + +/// Used to configure inference contexts before their creation. +pub struct InferCtxtBuilder<'db> { + interner: DbInterner<'db>, +} + +pub trait DbInternerInferExt<'db> { + fn infer_ctxt(self) -> InferCtxtBuilder<'db>; +} + +impl<'db> DbInternerInferExt<'db> for DbInterner<'db> { + fn infer_ctxt(self) -> InferCtxtBuilder<'db> { + InferCtxtBuilder { interner: self } + } +} + +impl<'db> InferCtxtBuilder<'db> { + /// Given a canonical value `C` as a starting point, create an + /// inference context that contains each of the bound values + /// within instantiated as a fresh variable. The `f` closure is + /// invoked with the new infcx, along with the instantiated value + /// `V` and a instantiation `S`. This instantiation `S` maps from + /// the bound values in `C` to their instantiated values in `V` + /// (in other words, `S(C) = V`). + pub fn build_with_canonical( + mut self, + input: &CanonicalQueryInput<'db, T>, + ) -> (InferCtxt<'db>, T, CanonicalVarValues<'db>) + where + T: TypeFoldable>, + { + let infcx = self.build(input.typing_mode); + let (value, args) = infcx.instantiate_canonical(&input.canonical); + (infcx, value, args) + } + + pub fn build(&mut self, typing_mode: TypingMode<'db>) -> InferCtxt<'db> { + let InferCtxtBuilder { interner } = *self; + InferCtxt { + interner, + typing_mode, + inner: RefCell::new(InferCtxtInner::new()), + tainted_by_errors: Cell::new(None), + universe: Cell::new(UniverseIndex::ROOT), + } + } +} + +impl<'db> InferOk<'db, ()> { + pub fn into_obligations(self) -> PredicateObligations<'db> { + self.obligations + } +} + +impl<'db> InferCtxt<'db> { + #[inline(always)] + pub fn typing_mode(&self) -> TypingMode<'db> { + self.typing_mode + } + + #[inline(always)] + pub fn typing_mode_unchecked(&self) -> TypingMode<'db> { + self.typing_mode + } + + pub fn unresolved_variables(&self) -> Vec> { + let mut inner = self.inner.borrow_mut(); + let mut vars: Vec> = inner + .type_variables() + .unresolved_variables() + .into_iter() + .map(|t| Ty::new_var(self.interner, t)) + .collect(); + vars.extend( + (0..inner.int_unification_table().len()) + .map(IntVid::from_usize) + .filter(|&vid| inner.int_unification_table().probe_value(vid).is_unknown()) + .map(|v| Ty::new_int_var(self.interner, v)), + ); + vars.extend( + (0..inner.float_unification_table().len()) + .map(FloatVid::from_usize) + .filter(|&vid| inner.float_unification_table().probe_value(vid).is_unknown()) + .map(|v| Ty::new_float_var(self.interner, v)), + ); + vars + } + + #[instrument(skip(self), level = "debug")] + pub fn sub_regions(&self, a: Region<'db>, b: Region<'db>) { + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(a, b); + } + + /// Processes a `Coerce` predicate from the fulfillment context. + /// This is NOT the preferred way to handle coercion, which is to + /// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`). + /// + /// This method here is actually a fallback that winds up being + /// invoked when `FnCtxt::coerce` encounters unresolved type variables + /// and records a coercion predicate. Presently, this method is equivalent + /// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up + /// actually requiring `a <: b`. This is of course a valid coercion, + /// but it's not as flexible as `FnCtxt::coerce` would be. + /// + /// (We may refactor this in the future, but there are a number of + /// practical obstacles. Among other things, `FnCtxt::coerce` presently + /// records adjustments that are required on the HIR in order to perform + /// the coercion, and we don't currently have a way to manage that.) + pub fn coerce_predicate( + &self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + predicate: PolyCoercePredicate<'db>, + ) -> Result, (TyVid, TyVid)> { + let subtype_predicate = predicate.map_bound(|p| SubtypePredicate { + a_is_expected: false, // when coercing from `a` to `b`, `b` is expected + a: p.a, + b: p.b, + }); + self.subtype_predicate(cause, param_env, subtype_predicate) + } + + pub fn subtype_predicate( + &self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + predicate: PolySubtypePredicate<'db>, + ) -> Result, (TyVid, TyVid)> { + // Check for two unresolved inference variables, in which case we can + // make no progress. This is partly a micro-optimization, but it's + // also an opportunity to "sub-unify" the variables. This isn't + // *necessary* to prevent cycles, because they would eventually be sub-unified + // anyhow during generalization, but it helps with diagnostics (we can detect + // earlier that they are sub-unified). + // + // Note that we can just skip the binders here because + // type variables can't (at present, at + // least) capture any of the things bound by this binder. + // + // Note that this sub here is not just for diagnostics - it has semantic + // effects as well. + let r_a = self.shallow_resolve(predicate.skip_binder().a); + let r_b = self.shallow_resolve(predicate.skip_binder().b); + match (r_a.kind(), r_b.kind()) { + (TyKind::Infer(InferTy::TyVar(a_vid)), TyKind::Infer(InferTy::TyVar(b_vid))) => { + return Err((a_vid, b_vid)); + } + _ => {} + } + + self.enter_forall(predicate, |SubtypePredicate { a_is_expected, a, b }| { + if a_is_expected { + Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) + } else { + Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) + } + }) + } + + pub fn region_outlives_predicate( + &self, + cause: &traits::ObligationCause, + predicate: PolyRegionOutlivesPredicate<'db>, + ) { + self.enter_forall(predicate, |OutlivesPredicate(r_a, r_b)| { + self.sub_regions(r_b, r_a); // `b : a` ==> `a <= b` + }) + } + + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + + pub fn next_ty_var(&self) -> Ty<'db> { + self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None }) + } + + pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> { + let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); + Ty::new_var(self.interner, vid) + } + + pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex) -> TyVid { + let origin = TypeVariableOrigin { param_def_id: None }; + self.inner.borrow_mut().type_variables().new_var(universe, origin) + } + + pub fn next_ty_var_in_universe(&self, universe: UniverseIndex) -> Ty<'db> { + let vid = self.next_ty_var_id_in_universe(universe); + Ty::new_var(self.interner, vid) + } + + pub fn next_const_var(&self) -> Const<'db> { + self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None }) + } + + pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> { + let vid = self + .inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) + .vid; + Const::new_var(self.interner, vid) + } + + pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> { + let origin = ConstVariableOrigin { param_def_id: None }; + let vid = self + .inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVariableValue::Unknown { origin, universe }) + .vid; + Const::new_var(self.interner, vid) + } + + pub fn next_int_var(&self) -> Ty<'db> { + let next_int_var_id = + self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown); + Ty::new_int_var(self.interner, next_int_var_id) + } + + pub fn next_float_var(&self) -> Ty<'db> { + let next_float_var_id = + self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown); + Ty::new_float_var(self.interner, next_float_var_id) + } + + /// Creates a fresh region variable with the next available index. + /// The variable will be created in the maximum universe created + /// thus far, allowing it to name any region created thus far. + pub fn next_region_var(&self) -> Region<'db> { + self.next_region_var_in_universe(self.universe()) + } + + /// Creates a fresh region variable with the next available index + /// in the given universe; typically, you can use + /// `next_region_var` and just use the maximal universe. + pub fn next_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { + let region_var = + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe); + Region::new_var(self.interner, region_var) + } + + pub fn next_term_var_of_kind(&self, term: Term<'db>) -> Term<'db> { + match term.kind() { + TermKind::Ty(_) => self.next_ty_var().into(), + TermKind::Const(_) => self.next_const_var().into(), + } + } + + /// Return the universe that the region `r` was created in. For + /// most regions (e.g., `'static`, named regions from the user, + /// etc) this is the root universe U0. For inference variables or + /// placeholders, however, it will return the universe which they + /// are associated. + pub fn universe_of_region(&self, r: Region<'db>) -> UniverseIndex { + self.inner.borrow_mut().unwrap_region_constraints().universe(r) + } + + /// Number of region variables created so far. + pub fn num_region_vars(&self) -> usize { + self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() + } + + /// Just a convenient wrapper of `next_region_var` for using during NLL. + #[instrument(skip(self), level = "debug")] + pub fn next_nll_region_var(&self) -> Region<'db> { + self.next_region_var() + } + + /// Just a convenient wrapper of `next_region_var` for using during NLL. + #[instrument(skip(self), level = "debug")] + pub fn next_nll_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { + self.next_region_var_in_universe(universe) + } + + fn var_for_def(&self, kind: GenericParamDefKind, name: &Symbol) -> GenericArg<'db> { + match kind { + GenericParamDefKind::Lifetime => { + // Create a region inference variable for the given + // region parameter definition. + self.next_region_var().into() + } + GenericParamDefKind::Type => { + // Create a type inference variable for the given + // type parameter definition. The generic parameters are + // for actual parameters that may be referred to by + // the default of this type parameter, if it exists. + // e.g., `struct Foo(...);` when + // used in a path such as `Foo::::new()` will + // use an inference variable for `C` with `[T, U]` + // as the generic parameters for the default, `(T, U)`. + let ty_var_id = self + .inner + .borrow_mut() + .type_variables() + .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }); + + Ty::new_var(self.interner, ty_var_id).into() + } + GenericParamDefKind::Const => { + let origin = ConstVariableOrigin { param_def_id: None }; + let const_var_id = self + .inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) + .vid; + Const::new_var(self.interner, const_var_id).into() + } + } + } + + /// Given a set of generics defined on a type or impl, returns the generic parameters mapping + /// each type/region parameter to a fresh inference variable. + pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { + GenericArgs::for_item(self.interner, def_id, |name, index, kind, _| { + self.var_for_def(kind, name) + }) + } + + /// Returns `true` if errors have been reported since this infcx was + /// created. This is sometimes used as a heuristic to skip + /// reporting errors that often occur as a result of earlier + /// errors, but where it's hard to be 100% sure (e.g., unresolved + /// inference variables, regionck errors). + #[must_use = "this method does not have any side effects"] + pub fn tainted_by_errors(&self) -> Option { + self.tainted_by_errors.get() + } + + /// Set the "tainted by errors" flag to true. We call this when we + /// observe an error from a prior pass. + pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + debug!("set_tainted_by_errors(ErrorGuaranteed)"); + self.tainted_by_errors.set(Some(e)); + } + + #[instrument(level = "debug", skip(self), ret)] + pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> { + self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() + } + + #[instrument(level = "debug", skip(self), ret)] + pub fn clone_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> { + self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect() + } + + #[inline(always)] + pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { + match self.typing_mode_unchecked() { + TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators.contains(&id.into()) + } + TypingMode::Coherence | TypingMode::PostAnalysis => false, + TypingMode::Borrowck { defining_opaque_types } => unimplemented!(), + TypingMode::PostBorrowckAnalysis { defined_opaque_types } => unimplemented!(), + } + } + + /// If `TyVar(vid)` resolves to a type, return that type. Else, return the + /// universe index of `TyVar(vid)`. + pub fn probe_ty_var(&self, vid: TyVid) -> Result, UniverseIndex> { + use self::type_variable::TypeVariableValue; + + match self.inner.borrow_mut().type_variables().probe(vid) { + TypeVariableValue::Known { value } => Ok(value), + TypeVariableValue::Unknown { universe } => Err(universe), + } + } + + pub fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { + if let TyKind::Infer(v) = ty.kind() { + match v { + InferTy::TyVar(v) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + // + // Note: if these two lines are combined into one we get + // dynamic borrow errors on `self.inner`. + let known = self.inner.borrow_mut().type_variables().probe(v).known(); + known.map_or(ty, |t| self.shallow_resolve(t)) + } + + InferTy::IntVar(v) => { + match self.inner.borrow_mut().int_unification_table().probe_value(v) { + IntVarValue::IntType(ty) => Ty::new_int(self.interner, ty), + IntVarValue::UintType(ty) => Ty::new_uint(self.interner, ty), + IntVarValue::Unknown => ty, + } + } + + InferTy::FloatVar(v) => { + match self.inner.borrow_mut().float_unification_table().probe_value(v) { + FloatVarValue::Known(ty) => Ty::new_float(self.interner, ty), + FloatVarValue::Unknown => ty, + } + } + + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => ty, + } + } else { + ty + } + } + + pub fn shallow_resolve_const(&self, ct: Const<'db>) -> Const<'db> { + match ct.kind() { + ConstKind::Infer(infer_ct) => match infer_ct { + InferConst::Var(vid) => self + .inner + .borrow_mut() + .const_unification_table() + .probe_value(vid) + .known() + .unwrap_or(ct), + InferConst::Fresh(_) => ct, + }, + ConstKind::Param(_) + | ConstKind::Bound(_, _) + | ConstKind::Placeholder(_) + | ConstKind::Unevaluated(_) + | ConstKind::Value(_) + | ConstKind::Error(_) + | ConstKind::Expr(_) => ct, + } + } + + pub fn root_var(&self, var: TyVid) -> TyVid { + self.inner.borrow_mut().type_variables().root_var(var) + } + + pub fn root_const_var(&self, var: ConstVid) -> ConstVid { + self.inner.borrow_mut().const_unification_table().find(var).vid + } + + /// Resolves an int var to a rigid int type, if it was constrained to one, + /// or else the root int var in the unification table. + pub fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'db> { + let mut inner = self.inner.borrow_mut(); + let value = inner.int_unification_table().probe_value(vid); + match value { + IntVarValue::IntType(ty) => Ty::new_int(self.interner, ty), + IntVarValue::UintType(ty) => Ty::new_uint(self.interner, ty), + IntVarValue::Unknown => { + Ty::new_int_var(self.interner, inner.int_unification_table().find(vid)) + } + } + } + + /// Resolves a float var to a rigid int type, if it was constrained to one, + /// or else the root float var in the unification table. + pub fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'db> { + let mut inner = self.inner.borrow_mut(); + let value = inner.float_unification_table().probe_value(vid); + match value { + FloatVarValue::Known(ty) => Ty::new_float(self.interner, ty), + FloatVarValue::Unknown => { + Ty::new_float_var(self.interner, inner.float_unification_table().find(vid)) + } + } + } + + /// Where possible, replaces type/const variables in + /// `value` with their final value. Note that region variables + /// are unaffected. If a type/const variable has not been unified, it + /// is left as is. This is an idempotent operation that does + /// not affect inference state in any way and so you can do it + /// at will. + pub fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + if let Err(guar) = value.error_reported() { + self.set_tainted_by_errors(guar); + } + if !value.has_non_region_infer() { + return value; + } + let mut r = resolve::OpportunisticVarResolver::new(self); + value.fold_with(&mut r) + } + + pub fn probe_const_var(&self, vid: ConstVid) -> Result, UniverseIndex> { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { value } => Ok(value), + ConstVariableValue::Unknown { origin: _, universe } => Err(universe), + } + } + + // Instantiates the bound variables in a given binder with fresh inference + // variables in the current universe. + // + // Use this method if you'd like to find some generic parameters of the binder's + // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] + // that corresponds to your use case, consider whether or not you should + // use [`InferCtxt::enter_forall`] instead. + pub fn instantiate_binder_with_fresh_vars( + &self, + lbrct: BoundRegionConversionTime, + value: Binder<'db, T>, + ) -> T + where + T: TypeFoldable> + Clone, + { + if let Some(inner) = value.clone().no_bound_vars() { + return inner; + } + + let bound_vars = value.clone().bound_vars(); + let mut args = Vec::with_capacity(bound_vars.len()); + + for bound_var_kind in bound_vars { + let arg: GenericArg<'db> = match bound_var_kind { + BoundVarKind::Ty(_) => self.next_ty_var().into(), + BoundVarKind::Region(br) => self.next_region_var().into(), + BoundVarKind::Const => self.next_const_var().into(), + }; + args.push(arg); + } + + struct ToFreshVars<'db> { + args: Vec>, + } + + impl<'db> BoundVarReplacerDelegate<'db> for ToFreshVars<'db> { + fn replace_region(&mut self, br: BoundRegion) -> Region<'db> { + self.args[br.var.index()].expect_region() + } + fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { + self.args[bt.var.index()].expect_ty() + } + fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { + self.args[bv.index()].expect_const() + } + } + let delegate = ToFreshVars { args }; + self.interner.replace_bound_vars_uncached(value, delegate) + } + + /// Obtains the latest type of the given closure; this may be a + /// closure in the current function, in which case its + /// `ClosureKind` may not yet be known. + pub fn closure_kind(&self, closure_ty: Ty<'db>) -> Option { + let unresolved_kind_ty = match closure_ty.kind() { + TyKind::Closure(_, args) => args.as_closure().kind_ty(), + TyKind::CoroutineClosure(_, args) => args.as_coroutine_closure().kind_ty(), + _ => panic!("unexpected type {closure_ty:?}"), + }; + let closure_kind_ty = self.shallow_resolve(unresolved_kind_ty); + closure_kind_ty.to_opt_closure_kind() + } + + pub fn universe(&self) -> UniverseIndex { + self.universe.get() + } + + /// Creates and return a fresh universe that extends all previous + /// universes. Updates `self.universe` to that new universe. + pub fn create_next_universe(&self) -> UniverseIndex { + let u = self.universe.get().next_universe(); + debug!("create_next_universe {u:?}"); + self.universe.set(u); + u + } + + /// The returned function is used in a fast path. If it returns `true` the variable is + /// unchanged, `false` indicates that the status is unknown. + #[inline] + pub fn is_ty_infer_var_definitely_unchanged<'a>( + &'a self, + ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a) { + // This hoists the borrow/release out of the loop body. + let inner = self.inner.try_borrow(); + + move |infer_var: TyOrConstInferVar| match (infer_var, &inner) { + (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { + use self::type_variable::TypeVariableValue; + + matches!( + inner.try_type_variables_probe_ref(ty_var), + Some(TypeVariableValue::Unknown { .. }) + ) + } + _ => false, + } + } + + /// `ty_or_const_infer_var_changed` is equivalent to one of these two: + /// * `shallow_resolve(ty) != ty` (where `ty.kind = Infer(_)`) + /// * `shallow_resolve(ct) != ct` (where `ct.kind = ConstKind::Infer(_)`) + /// + /// However, `ty_or_const_infer_var_changed` is more efficient. It's always + /// inlined, despite being large, because it has only two call sites that + /// are extremely hot (both in `traits::fulfill`'s checking of `stalled_on` + /// inference variables), and it handles both `Ty` and `Const` without + /// having to resort to storing full `GenericArg`s in `stalled_on`. + #[inline(always)] + pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool { + match infer_var { + TyOrConstInferVar::Ty(v) => { + use self::type_variable::TypeVariableValue; + + // If `inlined_probe` returns a `Known` value, it never equals + // `Infer(TyVar(v))`. + match self.inner.borrow_mut().type_variables().inlined_probe(v) { + TypeVariableValue::Unknown { .. } => false, + TypeVariableValue::Known { .. } => true, + } + } + + TyOrConstInferVar::TyInt(v) => { + // If `inlined_probe_value` returns a value it's always a + // `Int(_)` or `UInt(_)`, which never matches a + // `Infer(_)`. + self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_known() + } + + TyOrConstInferVar::TyFloat(v) => { + // If `probe_value` returns a value it's always a + // `Float(_)`, which never matches a `Infer(_)`. + // + // Not `inlined_probe_value(v)` because this call site is colder. + self.inner.borrow_mut().float_unification_table().probe_value(v).is_known() + } + + TyOrConstInferVar::Const(v) => { + // If `probe_value` returns a `Known` value, it never equals + // `ConstKind::Infer(InferConst::Var(v))`. + // + // Not `inlined_probe_value(v)` because this call site is colder. + match self.inner.borrow_mut().const_unification_table().probe_value(v) { + ConstVariableValue::Unknown { .. } => false, + ConstVariableValue::Known { .. } => true, + } + } + } + } +} + +/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently +/// used only for `traits::fulfill`'s list of `stalled_on` inference variables. +#[derive(Copy, Clone, Debug)] +pub enum TyOrConstInferVar { + /// Equivalent to `Infer(TyVar(_))`. + Ty(TyVid), + /// Equivalent to `Infer(IntVar(_))`. + TyInt(IntVid), + /// Equivalent to `Infer(FloatVar(_))`. + TyFloat(FloatVid), + + /// Equivalent to `ConstKind::Infer(InferConst::Var(_))`. + Const(ConstVid), +} + +impl TyOrConstInferVar { + /// Tries to extract an inference variable from a type or a constant, returns `None` + /// for types other than `Infer(_)` (or `InferTy::Fresh*`) and + /// for constants other than `ConstKind::Infer(_)` (or `InferConst::Fresh`). + pub fn maybe_from_generic_arg<'db>(arg: GenericArg<'db>) -> Option { + match arg.kind() { + GenericArgKind::Type(ty) => Self::maybe_from_ty(ty), + GenericArgKind::Const(ct) => Self::maybe_from_const(ct), + GenericArgKind::Lifetime(_) => None, + } + } + + /// Tries to extract an inference variable from a type, returns `None` + /// for types other than `Infer(_)` (or `InferTy::Fresh*`). + fn maybe_from_ty<'db>(ty: Ty<'db>) -> Option { + match ty.kind() { + TyKind::Infer(InferTy::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), + TyKind::Infer(InferTy::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), + TyKind::Infer(InferTy::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)), + _ => None, + } + } + + /// Tries to extract an inference variable from a constant, returns `None` + /// for constants other than `ConstKind::Infer(_)` (or `InferConst::Fresh`). + fn maybe_from_const<'db>(ct: Const<'db>) -> Option { + match ct.kind() { + ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), + _ => None, + } + } +} + +impl<'db> TypeTrace<'db> { + pub fn types(cause: &ObligationCause, a: Ty<'db>, b: Ty<'db>) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), + } + } + + pub fn trait_refs( + cause: &ObligationCause, + a: TraitRef<'db>, + b: TraitRef<'db>, + ) -> TypeTrace<'db> { + TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) } + } + + pub fn consts(cause: &ObligationCause, a: Const<'db>, b: Const<'db>) -> TypeTrace<'db> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), + } + } +} + +/// Requires that `region` must be equal to one of the regions in `choice_regions`. +/// We often denote this using the syntax: +/// +/// ```text +/// R0 member of [O1..On] +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MemberConstraint<'db> { + /// The `DefId` and args of the opaque type causing this constraint. + /// Used for error reporting. + pub key: OpaqueTypeKey<'db>, + + /// The hidden type in which `member_region` appears: used for error reporting. + pub hidden_ty: Ty<'db>, + + /// The region `R0`. + pub member_region: Region<'db>, + + /// The options `O1..On`. + pub choice_regions: Arc>>, +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs new file mode 100644 index 0000000000000..0f68ec8cdb5b4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs @@ -0,0 +1,56 @@ +//! Things related to the infer context of the next-trait-solver. + +use std::sync::Arc; + +use tracing::{debug, instrument}; + +use crate::next_solver::{ + Clause, ClauseKind, FxIndexMap, GenericArgs, OpaqueTypeKey, ProjectionPredicate, SolverDefId, + TypingMode, util::BottomUpFolder, +}; + +pub(crate) mod table; + +pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; + +use crate::next_solver::{ + AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal, + ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind, + fold::FnMutDelegate, + infer::{ + DefineOpaqueTypes, InferCtxt, TypeTrace, + traits::{Obligation, PredicateObligations}, + }, +}; +use rustc_type_ir::{ + AliasRelationDirection, AliasTyKind, BoundConstness, BoundVar, Flags, GenericArgKind, InferTy, + Interner, RegionKind, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, Upcast, Variance, + error::{ExpectedFound, TypeError}, + inherent::{DefId, GenericArgs as _, IntoKind, SliceLike}, + relate::{ + Relate, TypeRelation, VarianceDiagInfo, + combine::{super_combine_consts, super_combine_tys}, + }, +}; + +use super::{InferOk, traits::ObligationCause}; + +#[derive(Copy, Clone, Debug)] +pub struct OpaqueHiddenType<'db> { + pub ty: Ty<'db>, +} + +impl<'db> InferCtxt<'db> { + /// Insert a hidden type into the opaque type storage, making sure + /// it hasn't previously been defined. This does not emit any + /// constraints and it's the responsibility of the caller to make + /// sure that the item bounds of the opaque are checked. + pub fn register_hidden_type_in_storage( + &self, + opaque_type_key: OpaqueTypeKey<'db>, + hidden_ty: OpaqueHiddenType<'db>, + ) -> Option> { + self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs new file mode 100644 index 0000000000000..8ab409d782813 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs @@ -0,0 +1,166 @@ +//! Things related to storage opaques in the infer context of the next-trait-solver. + +use std::ops::Deref; + +use ena::undo_log::UndoLogs; +use tracing::instrument; + +use super::OpaqueHiddenType; +use crate::next_solver::{ + FxIndexMap, OpaqueTypeKey, Ty, + infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}, +}; + +#[derive(Default, Debug, Clone)] +pub(crate) struct OpaqueTypeStorage<'db> { + opaque_types: FxIndexMap, OpaqueHiddenType<'db>>, + duplicate_entries: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>, +} + +/// The number of entries in the opaque type storage at a given point. +/// +/// Used to check that we haven't added any new opaque types after checking +/// the opaque types currently in the storage. +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub struct OpaqueTypeStorageEntries { + opaque_types: usize, + duplicate_entries: usize, +} + +impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries { + fn needs_reevaluation(self, canonicalized: usize) -> bool { + self.opaque_types != canonicalized + } +} + +impl<'db> OpaqueTypeStorage<'db> { + #[instrument(level = "debug")] + pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'db>, prev: Option>) { + if let Some(prev) = prev { + *self.opaque_types.get_mut(&key).unwrap() = prev; + } else { + // FIXME(#120456) - is `swap_remove` correct? + match self.opaque_types.swap_remove(&key) { + None => { + panic!("reverted opaque type inference that was never registered: {key:?}") + } + Some(_) => {} + } + } + } + + pub(crate) fn pop_duplicate_entry(&mut self) { + let entry = self.duplicate_entries.pop(); + assert!(entry.is_some()); + } + + pub fn is_empty(&self) -> bool { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.is_empty() && duplicate_entries.is_empty() + } + + pub(crate) fn take_opaque_types( + &mut self, + ) -> impl Iterator, OpaqueHiddenType<'db>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) + } + + pub fn num_entries(&self) -> OpaqueTypeStorageEntries { + OpaqueTypeStorageEntries { + opaque_types: self.opaque_types.len(), + duplicate_entries: self.duplicate_entries.len(), + } + } + + pub fn opaque_types_added_since( + &self, + prev_entries: OpaqueTypeStorageEntries, + ) -> impl Iterator, OpaqueHiddenType<'db>)> { + self.opaque_types + .iter() + .skip(prev_entries.opaque_types) + .map(|(k, v)| (*k, *v)) + .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied()) + } + + /// Only returns the opaque types from the lookup table. These are used + /// when normalizing opaque types and have a unique key. + /// + /// Outside of canonicalization one should generally use `iter_opaque_types` + /// to also consider duplicate entries. + pub fn iter_lookup_table( + &self, + ) -> impl Iterator, OpaqueHiddenType<'db>)> { + self.opaque_types.iter().map(|(k, v)| (*k, *v)) + } + + /// Only returns the opaque types which are stored in `duplicate_entries`. + /// + /// These have to considered when checking all opaque type uses but are e.g. + /// irrelevant for canonical inputs as nested queries never meaningfully + /// accesses them. + pub fn iter_duplicate_entries( + &self, + ) -> impl Iterator, OpaqueHiddenType<'db>)> { + self.duplicate_entries.iter().copied() + } + + pub fn iter_opaque_types( + &self, + ) -> impl Iterator, OpaqueHiddenType<'db>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) + } + + #[inline] + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'db>, + ) -> OpaqueTypeTable<'a, 'db> { + OpaqueTypeTable { storage: self, undo_log } + } +} + +impl<'db> Drop for OpaqueTypeStorage<'db> { + fn drop(&mut self) { + if !self.opaque_types.is_empty() { + panic!("{:?}", self.opaque_types) + } + } +} + +pub(crate) struct OpaqueTypeTable<'a, 'db> { + storage: &'a mut OpaqueTypeStorage<'db>, + + undo_log: &'a mut InferCtxtUndoLogs<'db>, +} +impl<'db> Deref for OpaqueTypeTable<'_, 'db> { + type Target = OpaqueTypeStorage<'db>; + fn deref(&self) -> &Self::Target { + self.storage + } +} + +impl<'a, 'db> OpaqueTypeTable<'a, 'db> { + #[instrument(skip(self), level = "debug")] + pub fn register( + &mut self, + key: OpaqueTypeKey<'db>, + hidden_type: OpaqueHiddenType<'db>, + ) -> Option> { + if let Some(entry) = self.storage.opaque_types.get_mut(&key) { + let prev = std::mem::replace(entry, hidden_type); + self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev))); + return Some(prev.ty); + } + self.storage.opaque_types.insert(key, hidden_type); + self.undo_log.push(UndoLog::OpaqueTypes(key, None)); + None + } + + pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'db>, hidden_type: OpaqueHiddenType<'db>) { + self.storage.duplicate_entries.push((key, hidden_type)); + self.undo_log.push(UndoLog::DuplicateOpaqueType); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs new file mode 100644 index 0000000000000..50549694c3f23 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs @@ -0,0 +1,640 @@ +//! See `README.md`. + +use std::ops::Range; +use std::sync::Arc; +use std::{cmp, fmt, mem}; + +use ena::undo_log::{Rollback, UndoLogs}; +use ena::unify as ut; +use rustc_hash::FxHashMap; +use rustc_index::IndexVec; +use rustc_type_ir::inherent::IntoKind; +use rustc_type_ir::{RegionKind, RegionVid, UniverseIndex}; +use tracing::{debug, instrument}; + +use self::CombineMapType::*; +use self::UndoLog::*; +use super::MemberConstraint; +use super::unify_key::RegionVidKey; +use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}; +use crate::next_solver::infer::unify_key::RegionVariableValue; +use crate::next_solver::{ + AliasTy, Binder, DbInterner, OpaqueTypeKey, ParamTy, PlaceholderTy, Region, Ty, +}; + +#[derive(Clone, Default)] +pub struct RegionConstraintStorage<'db> { + /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. + pub(super) var_infos: IndexVec, + + pub(super) data: RegionConstraintData<'db>, + + /// For a given pair of regions (R1, R2), maps to a region R3 that + /// is designated as their LUB (edges R1 <= R3 and R2 <= R3 + /// exist). This prevents us from making many such regions. + lubs: CombineMap<'db>, + + /// For a given pair of regions (R1, R2), maps to a region R3 that + /// is designated as their GLB (edges R3 <= R1 and R3 <= R2 + /// exist). This prevents us from making many such regions. + glbs: CombineMap<'db>, + + /// When we add a R1 == R2 constraint, we currently add (a) edges + /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this + /// table. You can then call `opportunistic_resolve_var` early + /// which will map R1 and R2 to some common region (i.e., either + /// R1 or R2). This is important when fulfillment, dropck and other such + /// code is iterating to a fixed point, because otherwise we sometimes + /// would wind up with a fresh stream of region variables that have been + /// equated but appear distinct. + pub(super) unification_table: ut::UnificationTableStorage>, + + /// a flag set to true when we perform any unifications; this is used + /// to micro-optimize `take_and_reset_data` + any_unifications: bool, +} + +pub struct RegionConstraintCollector<'db, 'a> { + storage: &'a mut RegionConstraintStorage<'db>, + undo_log: &'a mut InferCtxtUndoLogs<'db>, +} + +pub type VarInfos = IndexVec; + +/// The full set of region constraints gathered up by the collector. +/// Describes constraints between the region variables and other +/// regions, as well as other conditions that must be verified, or +/// assumptions that can be made. +#[derive(Debug, Default, Clone)] +pub struct RegionConstraintData<'db> { + /// Constraints of the form `A <= B`, where either `A` or `B` can + /// be a region variable (or neither, as it happens). + pub constraints: Vec>, + + /// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that + /// `R0` must be equal to one of the regions `R1..Rn`. These occur + /// with `impl Trait` quite frequently. + pub member_constraints: Vec>, + + /// A "verify" is something that we need to verify after inference + /// is done, but which does not directly affect inference in any + /// way. + /// + /// An example is a `A <= B` where neither `A` nor `B` are + /// inference variables. + pub verifys: Vec>, +} + +/// Represents a constraint that influences the inference process. +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum Constraint<'db> { + /// A region variable is a subregion of another. + VarSubVar(RegionVid, RegionVid), + + /// A concrete region is a subregion of region variable. + RegSubVar(Region<'db>, RegionVid), + + /// A region variable is a subregion of a concrete region. This does not + /// directly affect inference, but instead is checked after + /// inference is complete. + VarSubReg(RegionVid, Region<'db>), + + /// A constraint where neither side is a variable. This does not + /// directly affect inference, but instead is checked after + /// inference is complete. + RegSubReg(Region<'db>, Region<'db>), +} + +impl<'db> Constraint<'db> { + pub fn involves_placeholders(&self) -> bool { + match self { + Constraint::VarSubVar(_, _) => false, + Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), + Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Verify<'db> { + pub kind: GenericKind<'db>, + pub region: Region<'db>, + pub bound: VerifyBound<'db>, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum GenericKind<'db> { + Param(ParamTy), + Placeholder(PlaceholderTy), + Alias(AliasTy<'db>), +} + +/// Describes the things that some `GenericKind` value `G` is known to +/// outlive. Each variant of `VerifyBound` can be thought of as a +/// function: +/// ```ignore (pseudo-rust) +/// fn(min: Region) -> bool { .. } +/// ``` +/// where `true` means that the region `min` meets that `G: min`. +/// (False means nothing.) +/// +/// So, for example, if we have the type `T` and we have in scope that +/// `T: 'a` and `T: 'b`, then the verify bound might be: +/// ```ignore (pseudo-rust) +/// fn(min: Region) -> bool { +/// ('a: min) || ('b: min) +/// } +/// ``` +/// This is described with an `AnyRegion('a, 'b)` node. +#[derive(Debug, Clone)] +pub enum VerifyBound<'db> { + /// See [`VerifyIfEq`] docs + IfEq(Binder<'db, VerifyIfEq<'db>>), + + /// Given a region `R`, expands to the function: + /// + /// ```ignore (pseudo-rust) + /// fn(min) -> bool { + /// R: min + /// } + /// ``` + /// + /// This is used when we can establish that `G: R` -- therefore, + /// if `R: min`, then by transitivity `G: min`. + OutlivedBy(Region<'db>), + + /// Given a region `R`, true if it is `'empty`. + IsEmpty, + + /// Given a set of bounds `B`, expands to the function: + /// + /// ```ignore (pseudo-rust) + /// fn(min) -> bool { + /// exists (b in B) { b(min) } + /// } + /// ``` + /// + /// In other words, if we meet some bound in `B`, that suffices. + /// This is used when all the bounds in `B` are known to apply to `G`. + AnyBound(Vec>), + + /// Given a set of bounds `B`, expands to the function: + /// + /// ```ignore (pseudo-rust) + /// fn(min) -> bool { + /// forall (b in B) { b(min) } + /// } + /// ``` + /// + /// In other words, if we meet *all* bounds in `B`, that suffices. + /// This is used when *some* bound in `B` is known to suffice, but + /// we don't know which. + AllBounds(Vec>), +} + +/// This is a "conditional bound" that checks the result of inference +/// and supplies a bound if it ended up being relevant. It's used in situations +/// like this: +/// +/// ```rust,ignore (pseudo-Rust) +/// fn foo<'a, 'b, T: SomeTrait<'a>> +/// where +/// >::Item: 'b +/// ``` +/// +/// If we have an obligation like `>::Item: 'c`, then +/// we don't know yet whether it suffices to show that `'b: 'c`. If `'?x` winds +/// up being equal to `'a`, then the where-clauses on function applies, and +/// in that case we can show `'b: 'c`. But if `'?x` winds up being something +/// else, the bound isn't relevant. +/// +/// In the [`VerifyBound`], this struct is enclosed in `Binder` to account +/// for cases like +/// +/// ```rust,ignore (pseudo-Rust) +/// where for<'a> ::Item: 'a +/// ``` +/// +/// The idea is that we have to find some instantiation of `'a` that can +/// make `>::Item` equal to the final value of `G`, +/// the generic we are checking. +/// +/// ```ignore (pseudo-rust) +/// fn(min) -> bool { +/// exists<'a> { +/// if G == K { +/// B(min) +/// } else { +/// false +/// } +/// } +/// } +/// ``` +#[derive(Debug, Clone)] +pub struct VerifyIfEq<'db> { + /// Type which must match the generic `G` + pub ty: Ty<'db>, + + /// Bound that applies if `ty` is equal. + pub bound: Region<'db>, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct TwoRegions<'db> { + a: Region<'db>, + b: Region<'db>, +} + +#[derive(Clone, PartialEq)] +pub(crate) enum UndoLog<'db> { + /// We added `RegionVid`. + AddVar(RegionVid), + + /// We added the given `constraint`. + AddConstraint(usize), + + /// We added the given `verify`. + AddVerify(usize), + + /// We added a GLB/LUB "combination variable". + AddCombination(CombineMapType, TwoRegions<'db>), +} + +#[derive(Clone, PartialEq)] +pub(crate) enum CombineMapType { + Lub, + Glb, +} + +type CombineMap<'db> = FxHashMap, RegionVid>; + +#[derive(Debug, Clone)] +pub struct RegionVariableInfo { + // FIXME: This is only necessary for `fn take_and_reset_data` and + // `lexical_region_resolve`. We should rework `lexical_region_resolve` + // in the near/medium future anyways and could move the unverse info + // for `fn take_and_reset_data` into a separate table which is + // only populated when needed. + // + // For both of these cases it is fine that this can diverge from the + // actual universe of the variable, which is directly stored in the + // unification table for unknown region variables. At some point we could + // stop emitting bidirectional outlives constraints if equate succeeds. + // This would be currently unsound as it would cause us to drop the universe + // changes in `lexical_region_resolve`. + pub universe: UniverseIndex, +} + +pub(crate) struct RegionSnapshot { + any_unifications: bool, +} + +impl<'db> RegionConstraintStorage<'db> { + #[inline] + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'db>, + ) -> RegionConstraintCollector<'db, 'a> { + RegionConstraintCollector { storage: self, undo_log } + } +} + +impl<'db> RegionConstraintCollector<'db, '_> { + pub fn num_region_vars(&self) -> usize { + self.storage.var_infos.len() + } + + pub fn region_constraint_data(&self) -> &RegionConstraintData<'db> { + &self.storage.data + } + + /// Takes (and clears) the current set of constraints. Note that + /// the set of variables remains intact, but all relationships + /// between them are reset. This is used during NLL checking to + /// grab the set of constraints that arose from a particular + /// operation. + /// + /// We don't want to leak relationships between variables between + /// points because just because (say) `r1 == r2` was true at some + /// point P in the graph doesn't imply that it will be true at + /// some other point Q, in NLL. + /// + /// Not legal during a snapshot. + pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'db> { + assert!(!UndoLogs::>::in_snapshot(&self.undo_log)); + + // If you add a new field to `RegionConstraintCollector`, you + // should think carefully about whether it needs to be cleared + // or updated in some way. + let RegionConstraintStorage { + var_infos: _, + data, + lubs, + glbs, + unification_table: _, + any_unifications, + } = self.storage; + + // Clear the tables of (lubs, glbs), so that we will create + // fresh regions if we do a LUB operation. As it happens, + // LUB/GLB are not performed by the MIR type-checker, which is + // the one that uses this method, but it's good to be correct. + lubs.clear(); + glbs.clear(); + + let data = mem::take(data); + + // Clear all unifications and recreate the variables a "now + // un-unified" state. Note that when we unify `a` and `b`, we + // also insert `a <= b` and a `b <= a` edges, so the + // `RegionConstraintData` contains the relationship here. + if *any_unifications { + *any_unifications = false; + // Manually inlined `self.unification_table_mut()` as `self` is used in the closure. + ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log) + .reset_unifications(|key| RegionVariableValue::Unknown { + universe: self.storage.var_infos[key.vid].universe, + }); + } + + data + } + + pub fn data(&self) -> &RegionConstraintData<'db> { + &self.storage.data + } + + pub(super) fn start_snapshot(&self) -> RegionSnapshot { + debug!("RegionConstraintCollector: start_snapshot"); + RegionSnapshot { any_unifications: self.storage.any_unifications } + } + + pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { + debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); + self.storage.any_unifications = snapshot.any_unifications; + } + + pub(super) fn new_region_var(&mut self, universe: UniverseIndex) -> RegionVid { + let vid = self.storage.var_infos.push(RegionVariableInfo { universe }); + + let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe }); + assert_eq!(vid, u_vid.vid); + self.undo_log.push(AddVar(vid)); + debug!("created new region variable {:?} in {:?}", vid, universe); + vid + } + + fn add_constraint(&mut self, constraint: Constraint<'db>) { + // cannot add constraints once regions are resolved + debug!("RegionConstraintCollector: add_constraint({:?})", constraint); + + let index = self.storage.data.constraints.len(); + self.storage.data.constraints.push(constraint); + self.undo_log.push(AddConstraint(index)); + } + + pub(super) fn make_eqregion(&mut self, a: Region<'db>, b: Region<'db>) { + if a != b { + // Eventually, it would be nice to add direct support for + // equating regions. + self.make_subregion(a, b); + self.make_subregion(b, a); + + match (a.kind(), b.kind()) { + (RegionKind::ReVar(a), RegionKind::ReVar(b)) => { + debug!("make_eqregion: unifying {:?} with {:?}", a, b); + if self.unification_table_mut().unify_var_var(a, b).is_ok() { + self.storage.any_unifications = true; + } + } + (RegionKind::ReVar(vid), _) => { + debug!("make_eqregion: unifying {:?} with {:?}", vid, b); + if self + .unification_table_mut() + .unify_var_value(vid, RegionVariableValue::Known { value: b }) + .is_ok() + { + self.storage.any_unifications = true; + }; + } + (_, RegionKind::ReVar(vid)) => { + debug!("make_eqregion: unifying {:?} with {:?}", a, vid); + if self + .unification_table_mut() + .unify_var_value(vid, RegionVariableValue::Known { value: a }) + .is_ok() + { + self.storage.any_unifications = true; + }; + } + (_, _) => {} + } + } + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn make_subregion(&mut self, sub: Region<'db>, sup: Region<'db>) { + // cannot add constraints once regions are resolved + + match (sub.kind(), sup.kind()) { + (RegionKind::ReBound(..), _) | (_, RegionKind::ReBound(..)) => { + panic!("cannot relate bound region: {sub:?} <= {sup:?}"); + } + (_, RegionKind::ReStatic) => { + // all regions are subregions of static, so we can ignore this + } + (RegionKind::ReVar(sub_id), RegionKind::ReVar(sup_id)) => { + self.add_constraint(Constraint::VarSubVar(sub_id, sup_id)); + } + (_, RegionKind::ReVar(sup_id)) => { + self.add_constraint(Constraint::RegSubVar(sub, sup_id)); + } + (RegionKind::ReVar(sub_id), _) => { + self.add_constraint(Constraint::VarSubReg(sub_id, sup)); + } + _ => { + self.add_constraint(Constraint::RegSubReg(sub, sup)); + } + } + } + + /// Resolves a region var to its value in the unification table, if it exists. + /// Otherwise, it is resolved to the root `ReVar` in the table. + pub fn opportunistic_resolve_var( + &mut self, + cx: DbInterner<'db>, + vid: RegionVid, + ) -> Region<'db> { + let mut ut = self.unification_table_mut(); + let root_vid = ut.find(vid).vid; + match ut.probe_value(root_vid) { + RegionVariableValue::Known { value } => value, + RegionVariableValue::Unknown { .. } => Region::new_var(cx, root_vid), + } + } + + pub fn probe_value(&mut self, vid: RegionVid) -> Result, UniverseIndex> { + match self.unification_table_mut().probe_value(vid) { + RegionVariableValue::Known { value } => Ok(value), + RegionVariableValue::Unknown { universe } => Err(universe), + } + } + + fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'db> { + match t { + Glb => &mut self.storage.glbs, + Lub => &mut self.storage.lubs, + } + } + + fn combine_vars( + &mut self, + cx: DbInterner<'db>, + t: CombineMapType, + a: Region<'db>, + b: Region<'db>, + ) -> Region<'db> { + let vars = TwoRegions { a, b }; + if let Some(c) = self.combine_map(t.clone()).get(&vars) { + return Region::new_var(cx, *c); + } + let a_universe = self.universe(a); + let b_universe = self.universe(b); + let c_universe = cmp::max(a_universe, b_universe); + let c = self.new_region_var(c_universe); + self.combine_map(t.clone()).insert(vars.clone(), c); + self.undo_log.push(AddCombination(t.clone(), vars)); + let new_r = Region::new_var(cx, c); + for old_r in [a, b] { + match t { + Glb => self.make_subregion(new_r, old_r), + Lub => self.make_subregion(old_r, new_r), + } + } + debug!("combine_vars() c={:?}", c); + new_r + } + + pub fn universe(&mut self, region: Region<'db>) -> UniverseIndex { + match region.kind() { + RegionKind::ReStatic + | RegionKind::ReErased + | RegionKind::ReLateParam(..) + | RegionKind::ReEarlyParam(..) + | RegionKind::ReError(_) => UniverseIndex::ROOT, + RegionKind::RePlaceholder(placeholder) => placeholder.universe, + RegionKind::ReVar(vid) => match self.probe_value(vid) { + Ok(value) => self.universe(value), + Err(universe) => universe, + }, + RegionKind::ReBound(..) => panic!("universe(): encountered bound region {region:?}"), + } + } + + #[inline] + fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'db, RegionVidKey<'db>> { + ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) + } +} + +impl fmt::Debug for RegionSnapshot { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "RegionSnapshot") + } +} + +impl<'db> fmt::Debug for GenericKind<'db> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + GenericKind::Param(ref p) => write!(f, "{p:?}"), + GenericKind::Placeholder(ref p) => write!(f, "{p:?}"), + GenericKind::Alias(ref p) => write!(f, "{p:?}"), + } + } +} + +impl<'db> fmt::Display for GenericKind<'db> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + GenericKind::Param(ref p) => write!(f, "{p:?}"), + GenericKind::Placeholder(ref p) => write!(f, "{p:?}"), + GenericKind::Alias(ref p) => write!(f, "{p}"), + } + } +} + +impl<'db> GenericKind<'db> { + pub fn to_ty(&self, interner: DbInterner<'db>) -> Ty<'db> { + match *self { + GenericKind::Param(ref p) => (*p).to_ty(interner), + GenericKind::Placeholder(ref p) => Ty::new_placeholder(interner, *p), + GenericKind::Alias(ref p) => (*p).to_ty(interner), + } + } +} + +impl<'db> VerifyBound<'db> { + pub fn must_hold(&self) -> bool { + match self { + VerifyBound::IfEq(..) => false, + VerifyBound::OutlivedBy(re) => re.is_static(), + VerifyBound::IsEmpty => false, + VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()), + VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()), + } + } + + pub fn cannot_hold(&self) -> bool { + match self { + VerifyBound::IfEq(..) => false, + VerifyBound::IsEmpty => false, + VerifyBound::OutlivedBy(_) => false, + VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()), + VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()), + } + } + + pub fn or(self, vb: VerifyBound<'db>) -> VerifyBound<'db> { + if self.must_hold() || vb.cannot_hold() { + self + } else if self.cannot_hold() || vb.must_hold() { + vb + } else { + VerifyBound::AnyBound(vec![self, vb]) + } + } +} + +impl<'db> RegionConstraintData<'db> { + /// Returns `true` if this region constraint data contains no constraints, and `false` + /// otherwise. + pub fn is_empty(&self) -> bool { + let RegionConstraintData { constraints, member_constraints, verifys } = self; + constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty() + } +} + +impl<'db> Rollback> for RegionConstraintStorage<'db> { + fn reverse(&mut self, undo: UndoLog<'db>) { + match undo { + AddVar(vid) => { + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index()); + } + AddConstraint(index) => { + self.data.constraints.pop().unwrap(); + assert_eq!(self.data.constraints.len(), index); + } + AddVerify(index) => { + self.data.verifys.pop(); + assert_eq!(self.data.verifys.len(), index); + } + AddCombination(Glb, ref regions) => { + self.glbs.remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.remove(regions); + } + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs new file mode 100644 index 0000000000000..de336c69b3180 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs @@ -0,0 +1,720 @@ +//! Type generation code. + +use std::mem; + +use rustc_hash::FxHashMap; +use rustc_type_ir::error::TypeError; +use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _}; +use rustc_type_ir::relate::VarianceDiagInfo; +use rustc_type_ir::{ + AliasRelationDirection, AliasTyKind, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind, + TermKind, TyVid, UniverseIndex, Variance, +}; +use rustc_type_ir::{Interner, TypeVisitable, TypeVisitableExt}; +use tracing::{debug, instrument, warn}; + +use super::{ + PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, +}; +use crate::next_solver::infer::type_variable::TypeVariableValue; +use crate::next_solver::infer::unify_key::ConstVariableValue; +use crate::next_solver::infer::{InferCtxt, relate}; +use crate::next_solver::util::MaxUniverse; +use crate::next_solver::{ + AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind, + ProjectionPredicate, Region, SolverDefId, Term, TermVid, Ty, TyKind, TypingMode, + UnevaluatedConst, +}; + +impl<'db> InferCtxt<'db> { + /// The idea is that we should ensure that the type variable `target_vid` + /// is equal to, a subtype of, or a supertype of `source_ty`. + /// + /// For this, we will instantiate `target_vid` with a *generalized* version + /// of `source_ty`. Generalization introduces other inference variables wherever + /// subtyping could occur. This also does the occurs checks, detecting whether + /// instantiating `target_vid` would result in a cyclic type. We eagerly error + /// in this case. + /// + /// This is *not* expected to be used anywhere except for an implementation of + /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all + /// other usecases (i.e. setting the value of a type var). + #[instrument(level = "debug", skip(self, relation))] + pub fn instantiate_ty_var>>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: TyVid, + instantiation_variance: Variance, + source_ty: Ty<'db>, + ) -> RelateResult<'db, ()> { + debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); + + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. + let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self + .generalize( + relation.structurally_relate_aliases(), + target_vid, + instantiation_variance, + source_ty, + )?; + + // Constrain `b_vid` to the generalized type `generalized_ty`. + if let TyKind::Infer(InferTy::TyVar(generalized_vid)) = generalized_ty.kind() { + self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); + } else { + self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); + } + + // See the comment on `Generalization::has_unconstrained_ty_var`. + if has_unconstrained_ty_var { + relation.register_predicates([ClauseKind::WellFormed(generalized_ty.into())]); + } + + // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + if generalized_ty.is_ty_var() { + // This happens for cases like `::Assoc == ?0`. + // We can't instantiate `?0` here as that would result in a + // cyclic type. We instead delay the unification in case + // the alias can be normalized to something which does not + // mention `?0`. + let (lhs, rhs, direction) = match instantiation_variance { + Variance::Invariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) + } + Variance::Covariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) + } + Variance::Contravariant => { + (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) + } + Variance::Bivariant => unreachable!("bivariant generalization"), + }; + + relation.register_predicates([PredicateKind::AliasRelate(lhs, rhs, direction)]); + } else { + // NOTE: The `instantiation_variance` is not the same variance as + // used by the relation. When instantiating `b`, `target_is_expected` + // is flipped and the `instantiation_variance` is also flipped. To + // constrain the `generalized_ty` while using the original relation, + // we therefore only have to flip the arguments. + // + // ```ignore (not code) + // ?a rel B + // instantiate_ty_var(?a, B) # expected and variance not flipped + // B' rel B + // ``` + // or + // ```ignore (not code) + // A rel ?b + // instantiate_ty_var(?b, A) # expected and variance flipped + // A rel A' + // ``` + if target_is_expected { + relation.relate(generalized_ty, source_ty)?; + } else { + debug!("flip relation"); + relation.relate(source_ty, generalized_ty)?; + } + } + + Ok(()) + } + + /// Instantiates the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continuously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused args, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```compile_fail,E0308 + /// #![feature(generic_const_exprs)] + /// + /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its args contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its args, this must not succeed. + /// + /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. + #[instrument(level = "debug", skip(self, relation))] + pub(crate) fn instantiate_const_var>>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ConstVid, + source_ct: Const<'db>, + ) -> RelateResult<'db, ()> { + // FIXME(generic_const_exprs): Occurs check failures for unevaluated + // constants and generic expressions are not yet handled correctly. + let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self + .generalize( + relation.structurally_relate_aliases(), + target_vid, + Variance::Invariant, + source_ct, + )?; + + debug_assert!(!generalized_ct.is_ct_infer()); + if has_unconstrained_ty_var { + panic!("unconstrained ty var when generalizing `{source_ct:?}`"); + } + + self.inner + .borrow_mut() + .const_unification_table() + .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); + + // Make sure that the order is correct when relating the + // generalized const and the source. + if target_is_expected { + relation.relate_with_variance( + Variance::Invariant, + VarianceDiagInfo::default(), + generalized_ct, + source_ct, + )?; + } else { + relation.relate_with_variance( + Variance::Invariant, + VarianceDiagInfo::default(), + source_ct, + generalized_ct, + )?; + } + + Ok(()) + } + + /// Attempts to generalize `source_term` for the type variable `target_vid`. + /// This checks for cycles -- that is, whether `source_term` references `target_vid`. + fn generalize> + Relate>>( + &self, + structurally_relate_aliases: StructurallyRelateAliases, + target_vid: impl Into, + ambient_variance: Variance, + source_term: T, + ) -> RelateResult<'db, Generalization> { + assert!(!source_term.clone().has_escaping_bound_vars()); + let (for_universe, root_vid) = match target_vid.into() { + TermVid::Ty(ty_vid) => { + (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid))) + } + TermVid::Const(ct_vid) => ( + self.probe_const_var(ct_vid).unwrap_err(), + TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid), + ), + }; + + let mut generalizer = Generalizer { + infcx: self, + structurally_relate_aliases, + root_vid, + for_universe, + root_term: source_term.into(), + ambient_variance, + in_alias: false, + cache: Default::default(), + has_unconstrained_ty_var: false, + }; + + let value_may_be_infer = generalizer.relate(source_term, source_term)?; + let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; + Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) + } +} + +/// The "generalizer" is used when handling inference variables. +/// +/// The basic strategy for handling a constraint like `?A <: B` is to +/// apply a "generalization strategy" to the term `B` -- this replaces +/// all the lifetimes in the term `B` with fresh inference variables. +/// (You can read more about the strategy in this [blog post].) +/// +/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x +/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the +/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which +/// establishes `'0: 'x` as a constraint. +/// +/// [blog post]: https://is.gd/0hKvIr +struct Generalizer<'me, 'db> { + infcx: &'me InferCtxt<'db>, + + /// Whether aliases should be related structurally. If not, we have to + /// be careful when generalizing aliases. + structurally_relate_aliases: StructurallyRelateAliases, + + /// The vid of the type variable that is in the process of being + /// instantiated. If we find this within the value we are folding, + /// that means we would have created a cyclic value. + root_vid: TermVid, + + /// The universe of the type variable that is in the process of being + /// instantiated. If we find anything that this universe cannot name, + /// we reject the relation. + for_universe: UniverseIndex, + + /// The root term (const or type) we're generalizing. Used for cycle errors. + root_term: Term<'db>, + + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: Variance, + + /// This is set once we're generalizing the arguments of an alias. + /// + /// This is necessary to correctly handle + /// `::Assoc>::Assoc == ?0`. This equality can + /// hold by either normalizing the outer or the inner associated type. + in_alias: bool, + + cache: FxHashMap<(Ty<'db>, Variance, bool), Ty<'db>>, + + /// See the field `has_unconstrained_ty_var` in `Generalization`. + has_unconstrained_ty_var: bool, +} + +impl<'db> Generalizer<'_, 'db> { + /// Create an error that corresponds to the term kind in `root_term` + fn cyclic_term_error(&self) -> TypeError> { + match self.root_term.kind() { + TermKind::Ty(ty) => TypeError::CyclicTy(ty), + TermKind::Const(ct) => TypeError::CyclicConst(ct), + } + } + + /// Create a new type variable in the universe of the target when + /// generalizing an alias. This has to set `has_unconstrained_ty_var` + /// if we're currently in a bivariant context. + fn next_ty_var_for_alias(&mut self) -> Ty<'db> { + self.has_unconstrained_ty_var |= self.ambient_variance == Variance::Bivariant; + self.infcx.next_ty_var_in_universe(self.for_universe) + } + + /// An occurs check failure inside of an alias does not mean + /// that the types definitely don't unify. We may be able + /// to normalize the alias after all. + /// + /// We handle this by lazily equating the alias and generalizing + /// it to an inference variable. In the new solver, we always + /// generalize to an infer var unless the alias contains escaping + /// bound variables. + /// + /// Correctly handling aliases with escaping bound variables is + /// difficult and currently incomplete in two opposite ways: + /// - if we get an occurs check failure in the alias, replace it with a new infer var. + /// This causes us to later emit an alias-relate goal and is incomplete in case the + /// alias normalizes to type containing one of the bound variables. + /// - if the alias contains an inference variable not nameable by `for_universe`, we + /// continue generalizing the alias. This ends up pulling down the universe of the + /// inference variable and is incomplete in case the alias would normalize to a type + /// which does not mention that inference variable. + fn generalize_alias_ty( + &mut self, + alias: AliasTy<'db>, + ) -> Result, TypeError>> { + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + return Ok(self.next_ty_var_for_alias()); + } + + let is_nested_alias = mem::replace(&mut self.in_alias, true); + let result = match self.relate(alias, alias) { + Ok(alias) => Ok(alias.to_ty(self.cx())), + Err(e) => { + if is_nested_alias { + return Err(e); + } else { + let mut visitor = MaxUniverse::new(); + alias.visit_with(&mut visitor); + let infer_replacement_is_complete = + self.for_universe.can_name(visitor.max_universe()) + && !alias.has_escaping_bound_vars(); + if !infer_replacement_is_complete { + warn!("may incompletely handle alias type: {alias:?}"); + } + + debug!("generalization failure in alias"); + Ok(self.next_ty_var_for_alias()) + } + } + }; + self.in_alias = is_nested_alias; + result + } +} + +impl<'db> TypeRelation> for Generalizer<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn relate_item_args( + &mut self, + item_def_id: SolverDefId, + a_arg: GenericArgs<'db>, + b_arg: GenericArgs<'db>, + ) -> RelateResult<'db, GenericArgs<'db>> { + if self.ambient_variance == Variance::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate::relate_args_invariantly(self, a_arg, b_arg) + } else { + let tcx = self.cx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_args_with_variances( + self, + item_def_id, + opt_variances, + a_arg, + b_arg, + false, + ) + } + } + + #[instrument(level = "debug", skip(self, variance, b), ret)] + fn relate_with_variance>>( + &mut self, + variance: Variance, + _info: VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'db, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + // Recursive calls to `relate` can overflow the stack. For example a deeper version of + // `ui/associated-consts/issue-93775.rs`. + let r = self.relate(a, b); + self.ambient_variance = old_ambient_variance; + r + } + + #[instrument(level = "debug", skip(self, t2), ret)] + fn tys(&mut self, t: Ty<'db>, t2: Ty<'db>) -> RelateResult<'db, Ty<'db>> { + assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + if let Some(result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) { + return Ok(*result); + } + + // Check to see whether the type we are generalizing references + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. + let g = match t.kind() { + TyKind::Infer( + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_), + ) => { + panic!("unexpected infer type: {t:?}") + } + + TyKind::Infer(InferTy::TyVar(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let vid = inner.type_variables().root_var(vid); + if TermVid::Ty(vid) == self.root_vid { + // If sub-roots are equal, then `root_vid` and + // `vid` are related via subtyping. + Err(self.cyclic_term_error()) + } else { + let probe = inner.type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + TypeVariableValue::Unknown { universe } => { + match self.ambient_variance { + // Invariant: no need to make a fresh type variable + // if we can name the universe. + Variance::Invariant => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + } + + // Bivariant: make a fresh var, but remember that + // it is unconstrained. See the comment in + // `Generalization`. + Variance::Bivariant => self.has_unconstrained_ty_var = true, + + // Co/contravariant: this will be + // sufficiently constrained later on. + Variance::Covariant | Variance::Contravariant => (), + } + + let origin = inner.type_variables().var_origin(vid); + let new_var_id = + inner.type_variables().new_var(self.for_universe, origin); + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // We only need to do so for type and const variables, as + // region variables do not impact normalization, and will get + // correctly constrained by `AliasRelate` later on. + // + // cc trait-system-refactor-initiative#108 + if self.infcx.next_trait_solver() + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) + && self.in_alias + { + inner.type_variables().equate(vid, new_var_id); + } + + debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); + Ok(Ty::new_var(self.infcx.interner, new_var_id)) + } + } + } + } + + TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => { + // No matter what mode we are in, + // integer/floating-point types must be equal to be + // relatable. + Ok(t) + } + + TyKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + + TyKind::Alias(_, data) => match self.structurally_relate_aliases { + StructurallyRelateAliases::No => self.generalize_alias_ty(data), + StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), + }, + + _ => relate::structurally_relate_tys(self, t, t), + }?; + + self.cache.insert((t, self.ambient_variance, self.in_alias), g); + Ok(g) + } + + #[instrument(level = "debug", skip(self, r2), ret)] + fn regions(&mut self, r: Region<'db>, r2: Region<'db>) -> RelateResult<'db, Region<'db>> { + assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match r.kind() { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + RegionKind::ReBound(..) | RegionKind::ReErased => { + return Ok(r); + } + + // It doesn't really matter for correctness if we generalize ReError, + // since we're already on a doomed compilation path. + RegionKind::ReError(_) => { + return Ok(r); + } + + RegionKind::RePlaceholder(..) + | RegionKind::ReVar(..) + | RegionKind::ReStatic + | RegionKind::ReEarlyParam(..) + | RegionKind::ReLateParam(..) => { + // see common code below + } + } + + // If we are in an invariant context, we can re-use the region + // as is, unless it happens to be in some universe that we + // can't name. + if let Variance::Invariant = self.ambient_variance { + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } + } + + Ok(self.infcx.next_region_var_in_universe(self.for_universe)) + } + + #[instrument(level = "debug", skip(self, c2), ret)] + fn consts(&mut self, c: Const<'db>, c2: Const<'db>) -> RelateResult<'db, Const<'db>> { + assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match c.kind() { + ConstKind::Infer(InferConst::Var(vid)) => { + // If root const vids are equal, then `root_vid` and + // `vid` are related and we'd be inferring an infinitely + // deep const. + if TermVid::Const( + self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid, + ) == self.root_vid + { + return Err(self.cyclic_term_error()); + } + + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + match variable_table.probe_value(vid) { + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + ConstVariableValue::Unknown { origin, universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table + .new_key(ConstVariableValue::Unknown { + origin, + universe: self.for_universe, + }) + .vid; + + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) + && self.in_alias + { + variable_table.union(vid, new_var_id); + } + Ok(Const::new_var(self.infcx.interner, new_var_id)) + } + } + } + } + // FIXME: Unevaluated constants are also not rigid, so the current + // approach of always relating them structurally is incomplete. + // + // FIXME: remove this branch once `structurally_relate_consts` is fully + // structural. + ConstKind::Unevaluated(UnevaluatedConst { def, args }) => { + let args = self.relate_with_variance( + Variance::Invariant, + VarianceDiagInfo::default(), + args, + args, + )?; + Ok(Const::new_unevaluated(self.infcx.interner, UnevaluatedConst { def, args })) + } + ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + _ => relate::structurally_relate_consts(self, c, c), + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn binders( + &mut self, + a: Binder<'db, T>, + _: Binder<'db, T>, + ) -> RelateResult<'db, Binder<'db, T>> + where + T: Relate>, + { + let result = self.relate(a.skip_binder(), a.skip_binder())?; + Ok(a.rebind(result)) + } +} + +/// Result from a generalization operation. This includes +/// not only the generalized type, but also a bool flag +/// indicating whether further WF checks are needed. +#[derive(Debug)] +struct Generalization { + /// When generalizing `::Assoc` or + /// `::Assoc>>::Assoc` + /// for `?0` generalization returns an inference + /// variable. + /// + /// This has to be handled wotj care as it can + /// otherwise very easily result in infinite + /// recursion. + pub value_may_be_infer: T, + + /// In general, we do not check whether all types which occur during + /// type checking are well-formed. We only check wf of user-provided types + /// and when actually using a type, e.g. for method calls. + /// + /// This means that when subtyping, we may end up with unconstrained + /// inference variables if a generalized type has bivariant parameters. + /// A parameter may only be bivariant if it is constrained by a projection + /// bound in a where-clause. As an example, imagine a type: + /// + /// struct Foo where A: Iterator { + /// data: A + /// } + /// + /// here, `A` will be covariant, but `B` is unconstrained. + /// + /// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`. + /// If we have an input `Foo`, then after generalization we will wind + /// up with a type like `Foo`. When we enforce `Foo <: Foo`, + /// we will wind up with the requirement that `?A <: ?C`, but no particular + /// relationship between `?B` and `?D` (after all, these types may be completely + /// different). If we do nothing else, this may mean that `?D` goes unconstrained + /// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases. + pub has_unconstrained_ty_var: bool, +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs new file mode 100644 index 0000000000000..bb80c5157109c --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs @@ -0,0 +1,89 @@ +//! Helper routines for higher-ranked things. See the `doc` module at +//! the end of the file for details. + +use rustc_type_ir::TypeFoldable; +use rustc_type_ir::{BoundVar, UniverseIndex}; +use tracing::{debug, instrument}; + +use super::RelateResult; +use crate::next_solver::fold::FnMutDelegate; +use crate::next_solver::infer::InferCtxt; +use crate::next_solver::infer::snapshot::CombinedSnapshot; +use crate::next_solver::{ + Binder, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst, PlaceholderRegion, + PlaceholderTy, Region, Ty, +}; + +impl<'db> InferCtxt<'db> { + /// Replaces all bound variables (lifetimes, types, and constants) bound by + /// `binder` with placeholder variables in a new universe. This means that the + /// new placeholders can only be named by inference variables created after + /// this method has been called. + /// + /// This is the first step of checking subtyping when higher-ranked things are involved. + /// For more details visit the relevant sections of the [rustc dev guide]. + /// + /// `fn enter_forall` should be preferred over this method. + /// + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html + #[instrument(level = "debug", skip(self), ret)] + pub fn enter_forall_and_leak_universe(&self, binder: Binder<'db, T>) -> T + where + T: TypeFoldable> + Clone, + { + if let Some(inner) = binder.clone().no_bound_vars() { + return inner; + } + + let next_universe = self.create_next_universe(); + + let delegate = FnMutDelegate { + regions: &mut |br: BoundRegion| { + Region::new_placeholder( + self.interner, + PlaceholderRegion { universe: next_universe, bound: br }, + ) + }, + types: &mut |bound_ty: BoundTy| { + Ty::new_placeholder( + self.interner, + PlaceholderTy { universe: next_universe, bound: bound_ty }, + ) + }, + consts: &mut |bound_var: BoundVar| { + Const::new_placeholder( + self.interner, + PlaceholderConst { universe: next_universe, bound: bound_var }, + ) + }, + }; + + debug!(?next_universe); + self.interner.replace_bound_vars_uncached(binder, delegate) + } + + /// Replaces all bound variables (lifetimes, types, and constants) bound by + /// `binder` with placeholder variables in a new universe and then calls the + /// closure `f` with the instantiated value. The new placeholders can only be + /// named by inference variables created inside of the closure `f` or afterwards. + /// + /// This is the first step of checking subtyping when higher-ranked things are involved. + /// For more details visit the relevant sections of the [rustc dev guide]. + /// + /// This method should be preferred over `fn enter_forall_and_leak_universe`. + /// + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html + #[instrument(level = "debug", skip(self, f))] + pub fn enter_forall(&self, forall: Binder<'db, T>, f: impl FnOnce(T) -> U) -> U + where + T: TypeFoldable> + Clone, + { + // FIXME: currently we do nothing to prevent placeholders with the new universe being + // used after exiting `f`. For example region subtyping can result in outlives constraints + // that name placeholders created in this function. Nested goals from type relations can + // also contain placeholders created by this function. + let value = self.enter_forall_and_leak_universe(forall); + debug!(?value); + f(value) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs new file mode 100644 index 0000000000000..836ae39dc5253 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs @@ -0,0 +1,13 @@ +//! This module contains the definitions of most `TypeRelation`s in the type system +//! (except for some relations used for diagnostics and heuristics in the compiler). +//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). + +pub use rustc_type_ir::relate::combine::PredicateEmittingRelation; +pub use rustc_type_ir::relate::*; + +use crate::next_solver::DbInterner; + +mod generalize; +mod higher_ranked; + +pub type RelateResult<'db, T> = rustc_type_ir::relate::RelateResult, T>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs new file mode 100644 index 0000000000000..84338ade6e354 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs @@ -0,0 +1,62 @@ +//! Things for resolving vars in the infer context of the next-trait-solver. + +use rustc_type_ir::{ + ConstKind, FallibleTypeFolder, InferConst, InferTy, RegionKind, TyKind, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, data_structures::DelayedMap, + inherent::IntoKind, +}; + +use crate::next_solver::{Const, DbInterner, Region, Ty}; + +use super::{FixupError, FixupResult, InferCtxt}; + +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC VAR RESOLVER + +/// The opportunistic resolver can be used at any time. It simply replaces +/// type/const variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticVarResolver<'a, 'db> { + infcx: &'a InferCtxt<'db>, + /// We're able to use a cache here as the folder does + /// not have any mutable state. + cache: DelayedMap, Ty<'db>>, +} + +impl<'a, 'db> OpportunisticVarResolver<'a, 'db> { + #[inline] + pub fn new(infcx: &'a InferCtxt<'db>) -> Self { + OpportunisticVarResolver { infcx, cache: Default::default() } + } +} + +impl<'a, 'db> TypeFolder> for OpportunisticVarResolver<'a, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner + } + + #[inline] + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + if !t.has_non_region_infer() { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else if let Some(ty) = self.cache.get(&t) { + *ty + } else { + let shallow = self.infcx.shallow_resolve(t); + let res = shallow.super_fold_with(self); + assert!(self.cache.insert(t, res)); + res + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + if !ct.has_non_region_infer() { + ct // micro-optimize -- if there is nothing in this const that this fold affects... + } else { + let ct = self.infcx.shallow_resolve_const(ct); + ct.super_fold_with(self) + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs new file mode 100644 index 0000000000000..eb426205575ad --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs @@ -0,0 +1,111 @@ +//! Snapshotting in the infer ctxt of the next-trait-solver. + +use ena::undo_log::UndoLogs; +use rustc_type_ir::UniverseIndex; +use tracing::{debug, instrument}; + +use super::InferCtxt; +use super::region_constraints::RegionSnapshot; + +pub(crate) mod undo_log; + +use undo_log::{Snapshot, UndoLog}; + +#[must_use = "once you start a snapshot, you should always consume it"] +pub struct CombinedSnapshot { + pub(super) undo_snapshot: Snapshot, + region_constraints_snapshot: RegionSnapshot, + universe: UniverseIndex, +} + +struct VariableLengths { + region_constraints_len: usize, + type_var_len: usize, + int_var_len: usize, + float_var_len: usize, + const_var_len: usize, +} + +impl<'db> InferCtxt<'db> { + fn variable_lengths(&self) -> VariableLengths { + let mut inner = self.inner.borrow_mut(); + VariableLengths { + region_constraints_len: inner.unwrap_region_constraints().num_region_vars(), + type_var_len: inner.type_variables().num_vars(), + int_var_len: inner.int_unification_table().len(), + float_var_len: inner.float_unification_table().len(), + const_var_len: inner.const_unification_table().len(), + } + } + + pub fn in_snapshot(&self) -> bool { + UndoLogs::>::in_snapshot(&self.inner.borrow_mut().undo_log) + } + + pub fn num_open_snapshots(&self) -> usize { + UndoLogs::>::num_open_snapshots(&self.inner.borrow_mut().undo_log) + } + + fn start_snapshot(&self) -> CombinedSnapshot { + debug!("start_snapshot()"); + + let mut inner = self.inner.borrow_mut(); + + CombinedSnapshot { + undo_snapshot: inner.undo_log.start_snapshot(), + region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), + universe: self.universe(), + } + } + + #[instrument(skip(self, snapshot), level = "debug")] + fn rollback_to(&self, snapshot: CombinedSnapshot) { + let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot; + + self.universe.set(universe); + + let mut inner = self.inner.borrow_mut(); + inner.rollback_to(undo_snapshot); + inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); + } + + #[instrument(skip(self, snapshot), level = "debug")] + fn commit_from(&self, snapshot: CombinedSnapshot) { + let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _ } = + snapshot; + + self.inner.borrow_mut().commit(undo_snapshot); + } + + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. + #[instrument(skip(self, f), level = "debug")] + pub fn commit_if_ok(&self, f: F) -> Result + where + F: FnOnce(&CombinedSnapshot) -> Result, + { + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); + match r { + Ok(_) => { + self.commit_from(snapshot); + } + Err(_) => { + self.rollback_to(snapshot); + } + } + r + } + + /// Execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] + pub fn probe(&self, f: F) -> R + where + F: FnOnce(&CombinedSnapshot) -> R, + { + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + self.rollback_to(snapshot); + r + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs new file mode 100644 index 0000000000000..0fa6421f517de --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs @@ -0,0 +1,198 @@ +//! Snapshotting in the infer ctxt of the next-trait-solver. + +use std::marker::PhantomData; + +use ena::snapshot_vec as sv; +use ena::undo_log::{Rollback, UndoLogs}; +use ena::unify as ut; +use rustc_type_ir::FloatVid; +use rustc_type_ir::IntVid; +use tracing::debug; + +use crate::next_solver::OpaqueTypeKey; +use crate::next_solver::infer::opaque_types::OpaqueHiddenType; +use crate::next_solver::infer::unify_key::ConstVidKey; +use crate::next_solver::infer::unify_key::RegionVidKey; +use crate::next_solver::infer::{InferCtxtInner, region_constraints, type_variable}; +use crate::traits; + +pub struct Snapshot { + pub(crate) undo_len: usize, +} + +/// Records the "undo" data for a single operation that affects some form of inference variable. +#[derive(Clone)] +pub(crate) enum UndoLog<'db> { + DuplicateOpaqueType, + OpaqueTypes(OpaqueTypeKey<'db>, Option>), + TypeVariables(sv::UndoLog>>), + ConstUnificationTable(sv::UndoLog>>), + IntUnificationTable(sv::UndoLog>), + FloatUnificationTable(sv::UndoLog>), + RegionConstraintCollector(region_constraints::UndoLog<'db>), + RegionUnificationTable(sv::UndoLog>>), + PushRegionObligation, +} + +macro_rules! impl_from { + ($($ctor:ident ($ty:ty),)*) => { + $( + impl<'db> From<$ty> for UndoLog<'db> { + fn from(x: $ty) -> Self { + UndoLog::$ctor(x.into()) + } + } + )* + } +} + +// Upcast from a single kind of "undoable action" to the general enum +impl_from! { + RegionConstraintCollector(region_constraints::UndoLog<'db>), + + TypeVariables(sv::UndoLog>>), + IntUnificationTable(sv::UndoLog>), + FloatUnificationTable(sv::UndoLog>), + + ConstUnificationTable(sv::UndoLog>>), + + RegionUnificationTable(sv::UndoLog>>), +} + +/// The Rollback trait defines how to rollback a particular action. +impl<'db> Rollback> for InferCtxtInner<'db> { + fn reverse(&mut self, undo: UndoLog<'db>) { + match undo { + UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), + UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), + UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), + UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), + UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), + UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), + UndoLog::RegionConstraintCollector(undo) => { + self.region_constraint_storage.as_mut().unwrap().reverse(undo) + } + UndoLog::RegionUnificationTable(undo) => { + self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) + } + UndoLog::PushRegionObligation => { + self.region_obligations.pop(); + } + } + } +} + +/// The combined undo log for all the various unification tables. For each change to the storage +/// for any kind of inference variable, we record an UndoLog entry in the vector here. +#[derive(Clone, Default)] +pub(crate) struct InferCtxtUndoLogs<'db> { + logs: Vec>, + num_open_snapshots: usize, +} + +/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any +/// action that is convertible into an UndoLog (per the From impls above). +impl<'db, T> UndoLogs for InferCtxtUndoLogs<'db> +where + UndoLog<'db>: From, +{ + #[inline] + fn num_open_snapshots(&self) -> usize { + self.num_open_snapshots + } + + #[inline] + fn push(&mut self, undo: T) { + if self.in_snapshot() { + self.logs.push(undo.into()) + } + } + + fn clear(&mut self) { + self.logs.clear(); + self.num_open_snapshots = 0; + } + + fn extend(&mut self, undos: J) + where + Self: Sized, + J: IntoIterator, + { + if self.in_snapshot() { + self.logs.extend(undos.into_iter().map(UndoLog::from)) + } + } +} + +impl<'db> InferCtxtInner<'db> { + pub fn rollback_to(&mut self, snapshot: Snapshot) { + debug!("rollback_to({})", snapshot.undo_len); + self.undo_log.assert_open_snapshot(&snapshot); + + while self.undo_log.logs.len() > snapshot.undo_len { + let undo = self.undo_log.logs.pop().unwrap(); + self.reverse(undo); + } + + self.type_variable_storage.finalize_rollback(); + + if self.undo_log.num_open_snapshots == 1 { + // After the root snapshot the undo log should be empty. + assert!(snapshot.undo_len == 0); + assert!(self.undo_log.logs.is_empty()); + } + + self.undo_log.num_open_snapshots -= 1; + } + + pub fn commit(&mut self, snapshot: Snapshot) { + debug!("commit({})", snapshot.undo_len); + + if self.undo_log.num_open_snapshots == 1 { + // The root snapshot. It's safe to clear the undo log because + // there's no snapshot further out that we might need to roll back + // to. + assert!(snapshot.undo_len == 0); + self.undo_log.logs.clear(); + } + + self.undo_log.num_open_snapshots -= 1; + } +} + +impl<'db> InferCtxtUndoLogs<'db> { + pub(crate) fn start_snapshot(&mut self) -> Snapshot { + self.num_open_snapshots += 1; + Snapshot { undo_len: self.logs.len() } + } + + pub(crate) fn region_constraints_in_snapshot( + &self, + s: &Snapshot, + ) -> impl Iterator> + Clone { + self.logs[s.undo_len..].iter().filter_map(|log| match log { + UndoLog::RegionConstraintCollector(log) => Some(log), + _ => None, + }) + } + + fn assert_open_snapshot(&self, snapshot: &Snapshot) { + // Failures here may indicate a failure to follow a stack discipline. + assert!(self.logs.len() >= snapshot.undo_len); + assert!(self.num_open_snapshots > 0); + } +} + +impl<'db> std::ops::Index for InferCtxtUndoLogs<'db> { + type Output = UndoLog<'db>; + + fn index(&self, key: usize) -> &Self::Output { + &self.logs[key] + } +} + +impl<'db> std::ops::IndexMut for InferCtxtUndoLogs<'db> { + fn index_mut(&mut self, key: usize) -> &mut Self::Output { + &mut self.logs[key] + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs new file mode 100644 index 0000000000000..f1df806ab3187 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs @@ -0,0 +1,175 @@ +//! Trait Resolution. See the [rustc-dev-guide] for more information on how this works. +//! +//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html + +use std::{ + cmp, + hash::{Hash, Hasher}, +}; + +use rustc_type_ir::{ + PredicatePolarity, Upcast, + solve::{Certainty, NoSolution}, +}; + +use crate::next_solver::{ + Binder, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, TraitPredicate, + Ty, +}; + +use super::InferCtxt; + +/// The reason why we incurred this obligation; used for error reporting. +/// +/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the +/// best trade-off between keeping the type small (which makes copies cheaper) +/// while not doing too many heap allocations. +/// +/// We do not want to intern this as there are a lot of obligation causes which +/// only live for a short period of time. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ObligationCause { + /// The ID of the fn body that triggered this obligation. This is + /// used for region obligations to determine the precise + /// environment in which the region obligation should be evaluated + /// (in particular, closures can add new assumptions). See the + /// field `region_obligations` of the `FulfillmentContext` for more + /// information. + pub body_id: Option, +} + +impl ObligationCause { + #[inline] + pub fn new(body_id: SolverDefId) -> ObligationCause { + ObligationCause { body_id: Some(body_id) } + } + + #[inline(always)] + pub fn dummy() -> ObligationCause { + ObligationCause { body_id: None } + } +} + +/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for +/// which the "impl_source" must be found. The process of finding an "impl_source" is +/// called "resolving" the `Obligation`. This process consists of +/// either identifying an `impl` (e.g., `impl Eq for i32`) that +/// satisfies the obligation, or else finding a bound that is in +/// scope. The eventual result is usually a `Selection` (defined below). +#[derive(Clone, Debug)] +pub struct Obligation<'db, T> { + /// The reason we have to prove this thing. + pub cause: ObligationCause, + + /// The environment in which we should prove this thing. + pub param_env: ParamEnv<'db>, + + /// The thing we are trying to prove. + pub predicate: T, + + /// If we started proving this as a result of trying to prove + /// something else, track the total depth to ensure termination. + /// If this goes over a certain threshold, we abort compilation -- + /// in such cases, we can not say whether or not the predicate + /// holds for certain. Stupid halting problem; such a drag. + pub recursion_depth: usize, +} + +impl<'db, T: Copy> Obligation<'db, T> { + pub fn as_goal(&self) -> Goal<'db, T> { + Goal { param_env: self.param_env, predicate: self.predicate } + } +} + +impl<'db, T: PartialEq> PartialEq> for Obligation<'db, T> { + #[inline] + fn eq(&self, other: &Obligation<'db, T>) -> bool { + // Ignore `cause` and `recursion_depth`. This is a small performance + // win for a few crates, and a huge performance win for the crate in + // https://github.com/rust-lang/rustc-perf/pull/1680, which greatly + // stresses the trait system. + self.param_env == other.param_env && self.predicate == other.predicate + } +} + +impl<'db, T: Eq> Eq for Obligation<'db, T> {} + +impl<'db, T: Hash> Hash for Obligation<'db, T> { + fn hash(&self, state: &mut H) { + // See the comment on `Obligation::eq`. + self.param_env.hash(state); + self.predicate.hash(state); + } +} + +impl<'db, P> From> for Goal<'db, P> { + fn from(value: Obligation<'db, P>) -> Self { + Goal { param_env: value.param_env, predicate: value.predicate } + } +} + +pub type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>; +pub type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>; + +pub type PredicateObligations<'db> = Vec>; + +impl<'db> PredicateObligation<'db> { + /// Flips the polarity of the inner predicate. + /// + /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. + pub fn flip_polarity(&self, tcx: DbInterner<'db>) -> Option> { + Some(PredicateObligation { + cause: self.cause.clone(), + param_env: self.param_env, + predicate: self.predicate.flip_polarity()?, + recursion_depth: self.recursion_depth, + }) + } +} + +impl<'db, O> Obligation<'db, O> { + pub fn new( + tcx: DbInterner<'db>, + cause: ObligationCause, + param_env: ParamEnv<'db>, + predicate: impl Upcast, O>, + ) -> Obligation<'db, O> { + Self::with_depth(tcx, cause, 0, param_env, predicate) + } + + /// We often create nested obligations without setting the correct depth. + /// + /// To deal with this evaluate and fulfill explicitly update the depth + /// of nested obligations using this function. + pub fn set_depth_from_parent(&mut self, parent_depth: usize) { + self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth); + } + + pub fn with_depth( + tcx: DbInterner<'db>, + cause: ObligationCause, + recursion_depth: usize, + param_env: ParamEnv<'db>, + predicate: impl Upcast, O>, + ) -> Obligation<'db, O> { + let predicate = predicate.upcast(tcx); + Obligation { cause, param_env, recursion_depth, predicate } + } + + pub fn misc( + tcx: DbInterner<'db>, + body_id: SolverDefId, + param_env: ParamEnv<'db>, + trait_ref: impl Upcast, O>, + ) -> Obligation<'db, O> { + Obligation::new(tcx, ObligationCause::new(body_id), param_env, trait_ref) + } + + pub fn with

m%Wc2r_mQBjet(QI+`v=+sawb7ftVOe;HW<>17 zX>W#H>6-ibS)db3dldiJ*jOjhk~y^D$Dkm72tq?${V<^E%a+7c*^_!Nz z-<4^ao0}^ux1HXnyLxqHWyP=HiwtO9TR(D?;}zSBW~96~el6k4!xyZKP^f3)Td}dR zBBqNm{{ZTbS6rKJJU-f8J*tHvnwOXD61(oet$t)ylM4~b-g?r^v$DE+;b}?{wT5Ph>U;O6H2NKFwRvd4+L+)QgquO?-aurM+-6bZSH1eF6u4p6q8$a&tH^mJx&Rvi#vG-u|TQzWMfid0a4~-#g0TghJuupr6BQb#4NZN4}AsPr(|sb{5M0Zun68DNwZA9`p|Hxc zx~>fJSbe%cO!0}4phyvP6(vxq6YIJk>b%xdh#t`cOGM`bOz+$Y{oF=eEUiolrQV6% zRh5-?YT&A%68r}iD@di~)ZNJIV9M-Tof6KP#%N1T%~bZ)A3M_Q%3PaWOGaf(K4k=d%E-u!U0&j*dmEn)P1ml5X?u zHW`77yMADJ2K;(nIS>a!!R0yIOTo@?{rWvk&Eqo>u<8WI394S-JulO1gI0g|KRR{W z$`^BN-qQWQtd=(aq5bc_EwZdk{+h1}Mg6*55-axjFN84ot4U(Wo|p$YO1QB za!dpgC)Url&A?(ecpi%pJpaDb>zp@WS3R-1vZAKeW!mJImYU*qGMMZnwO^!PZW?4= zdiI<@=Cd4uzDTeZ3J&P7p``IBido!lqnU%cLEEPHeD65TTcS4CYGIe0oFaT~XQ`L} z{7#_gAu?9u@G12JWp{V5b?3##(h8bQscKC5&-A4dMjTVp3wSzCMBjsUnogUjNCq*# z$yl1geJ1IEIbFBC0UH*%_`A7ry43B>*NprYOa1p)Qbe4rb;1R<3%4<}NP;FjRC@qc z_PsJzfp4S;6SU){U>-ABp%cbso*=+1>xE(#*Sd`wm4qQJpEYOChviAXny9l#G~Q_p z+NsLU)^fhfd&%C`)@N&F_s69?rRa>yj8~lIOVbc5#NbVZxQFG>R{n_r;a~?_TOHY@ zC%RSAUGwYOsC+zmc$9S6Z3Sol=~{2hhYw2AqdH9*vWs87Dlar@A1T96X+g`23ngZ% z+e;C3nO!IxacbEV{i7*v5dVaA+1AzPA`Lq_h=3I>^f|4r*syv_MYpQKy5Pjr$z&>w ze_}ioO$8>GgIlQ4O1*PWhU!WG-=98yJQ7Tlly4&UrP)hdE}vh}2b~HJdmDaC!FaT| zF16dM;7qYOUXK;8{)j|_6}W-!r$^l&=6RcD84-IVG}8VSMfXut89g*9J|nn1_R8ja zvL=e+j?a>UNnMhOhmkmk#%TfRq*;W-AU61L9H)1Un_HXCFWL7-=Fl@N^x5oASEeNLMX z@d?%CEzN(iIsO)b&x&rkA+^7zZQFQE$=peO8D;ASY)&m*9lMe?J`J5LeG52U~ALhjhv5 z_T!Y_ynRQD%_W9pb<6PSmTIRzYw%Tr@~xaj3v2QktIho7n35%!l#~N{@a0mQ{AxL^ zV0<2{e>VcGp?#C(Zrw)-30D@Vq-R>fV&$Rbp` zI^U(NS^N6b`eQ-&g9Lr(P0wrMvD5eT?C#PlEuE^Vbl5yI*txRzORDcG&AGelFO2Na zW}Cd)BU>GhwvxHvWX^L19*>yf(HWyJ3yTX>IJ*aOZOkMr?)s{xaJftxHw1VNR5A58 zC@3nodaPMTy(0UhbavVDG-bzeA?@DsWBq&KK!XX!v;N?e*h<=ScQ@7-XN}K$aasX0 zry;_Oso6KhsxEo&JAbSLl~=L3d9=Uv>!a+ zsg_*eA9zZ_CbCh%lbEzaD_EFcq!Si%xVpJ*gfsKoj=O78LvQw3%JsrGw5lvNRxGzX zEdLy+l;!CAtDzNwW_x6gjB7kv7TkC)aP#v6v;V4a-~M9&WhZU;*R2DUs>!`I;TvE2 zjJ_2cY2}cdUh=bV}|R zu&JGL&h2OJMH&>ve@D|SH+z; zaDU!2USclOtLZnN=#lw*{qyZ_E0RBgHlHf~{o9U~k&}-eT4m+oryldH$J^Va5K$md za%maQP!ZT*921yn+E3 zJXSd3;^wyFSoJfuzyDQd=gJD08pl({4U_AR{0s<3M+e{E3x{g)UWjO!GWMzPl7O_w zfxcgB>7A;_f{xqS^pO7&`1d!gK|?b!ePCzn_@`Mm!w*WkH@hTA^P5b>?2)4to^6}n z8$m}pKRqOA;Glp0qTF=n)JP53+8%oKN|g|YPWR`{2W*$P7-hY(Ge7<6N)#joR7#6} zLtw~erJ|^67&fr11%b+nJ`*l$cNwaSYT3l{LAxgcg-LnyBB_!=yh~DU;~4}hIGXrv z)fp+l%s2(cSAcPlrNlQD?@f?RgixSRzigE2j1o#s^>lShX8w|bU)|oy`Pv~FAtf&T z*Mu#4PMWX1d$t6bY&*XHc-VP#&Gpu0X=NO@$zHB7t@AVa;*KN89hIkgrC6Qcj1VN< z4GvYQuM1}+aH}XDDG;;g}t078=*bv znD(9e%)gK^H(WQ=GW>9HrhCHM#BXnRMaKLuT#dxBad^^xu{4ifzQKkAcT2&dj&16C zP`5C@*y6b{yWXpTgPCqBtFUXKzeyo-?L2#S?r(7d9s0{&v)d01M!~JDYCsBj!|i-^ zn%H>tspf1c+k=C@`oXXf7w)dgXHc89^si?r7-V`1j`6Ze@}7e`ydYN7*}3Di6iTh0 zoFL>O%;@_XbJ~U+OfmvIP!52D-$&gOew2DCvi|8+(a?ARL-{Oi1m;FhtTT)GU59|J zK%xyaGk5}1HEa@1PydoeC6nY9NYLEqDd%dX7HE2rr$imNyN-fB7cWar9)+B}>4za0 z`|;sZ`(iXMJm#)G_nb|e`tzEazEBq&zWNQCFGP-CLFxcgG|)GAo7937vijR*Z4-)} z{sfVLvA4aeurA>>R0a2UYA^XI{_?6Prew(7Vz8y94w~(!$?e$EwgFX<1~=EgN4(Au z)stE;KPP^}VfxyBqM+(q;Uz(kZjw~ZZ(iuHBO5#x3_+hsh-R56@ZUP7RL$5)ECIs7 z?=XjN^{K|W5A6(mmzV=RCNGow$Ho^|)IH%#hUz25EGb}XrLx~?yvTRjOx{fCVvz=)?W|;oyU8dK zq*WE*Fc7*^mXRuy#N@vRhz(e6SH8$=@n+p*k43WoO2*B;tF@am=Jiuqkz9h9f2irf z=wqu0_y5DBZ={zO`DNX!tHdH^D-AQ-L9ONIE3C^~7^y1I3B^3$oo9AvRXjdMx~DT? zBFXGr>wEh*63ponJ^JbJ=!~C|`>fE!RFz!*=(7-AZAg85s-*RaVA=9L2U_?Z^9{?d zi%u@sh4w=3PIgmFAnnv=J|saVF*0(s|0`(bb1{l3S_8tvj-%3+-{@-1t}wADEYK~t&emDIYew}J`neNLyNR)7CoCF3^*XbRn&Af&x~g~!5OGL1zx zDB$3iieYPMnana^f*#WvcD*R?jp@W(TCZ@$nbF346~{69(4pZfL^se%*#!VONUs zdM|slcXv^eMsPx)FD{Q41}m6nZR_Rrn(9|S>H0C37dNs#+8Eua1WZ-Dmw`vJySv+Y zo+{z3Q1Wtt0e&%x_j(zRpj)l6%rW^jNX7%}{y}rm53U*J|x8Hr?E$ zyjJf(@Up#b5OX{0w_1n*UH|MmPYvkLWD&1)j3m8&4g&7SQME@91%*-BV^2@@C`uE! zm|5c!;VSKYxkGaOoS*ae;X~G~>M7UG`Eh#xL^4X<#AM!2HUni%mRNFdvv2%kG**CJ zT0+#M@+oJ%%=Nkpkeli^6tW(46xelE*gLH5G2a@Trk)*ZORP`yr(_5JIxlcpnaye2 zhH4LGo1&+(za}?0I+}kkw{|Q!{csi3gc*i#YJR!AJVVyy(2E$+sU(IoVC)Zz(8-sa zwodj9xd8TkPt1A-(Xi8a|LExZCPNjwWXB41$Z>7wUKz`SUvU*4wb=ZN1!ZL`lc8#g z%ABgz<3AaG4L0rsLa><{(W(A37tW9&%>j( zo5fif(9Du<#@U6^Wmd-;5NJou9;-4lqa6dHm6fU){bglyc|8{yM0K~ zX4hZ!-6;E(?NAy-mT(=D7Ry_>>#(}Q?zxiTfA-S~thf-mfv%P>pG_uD)>({zK^fyq zWm3|6N9^6aS4+z7)bYg|^I7E7EuX;NT#BvO)pfHEQh2(bexDs~<^tzNDNteaWM)2QWdOjofVyL#B Tb%jNN=)hF&XxuJAJ$m+EN?yW= literal 15341 zcmdVAWlUXP^fq{rqQ$j1rFe07cPLU^Tio5kkrr2hK%g~Wz6j9Z3JWY+1O$R+ z<*BOatn%57%-+$?)WX_?%-O@+8qCk)ezImV@I{p7W2C8LbAkp>XD6zNy@Rbx;qk;`|E?SOCBtK~e<`lJebqWF zU#7p(*`z*m8uJJqgTC>+BKLhVF+G#wCSmf_Qoltn+PjPu(v7L=?r(YX%7a*Ib(H4n z)X0`}({0pp@33!Qk}ldlaW7Xt$#JYv8PTjY2B)1~DD}d#gKupFO=w`zuw=jWTnbI} zx1#jt5R4D=*WBI4;WG8A(QiL)w#^zQGG0(oEVyy2=p8!rNK#RyM(8HZH3jq8Hk{#? zvz#L>(*`8RZC$S&Z-sO``d;Tcl@BA@dqv?~V3sizeon1fTb2;*^5|t>yMeprzKJnN znwN&VKyfk(=swuON$ZYT4Cfk~Fzc%r5W1tBzVwD7H#{6R7JUcPuC$s1Yan5X@Vh!L z``0ifl`<>(&!L|w1^M{M0~Urx7xF0A`UB^UuUlik%15ZGOl^^A(e9}JX^=!jNjCbx zv-i!)wrNkzc7@6nFrW!mh6Z+Y^qivv%@%qEhoybTTB;!_X zI2!Znj9Xk4%%O~(VYe{GK%HS$9Y^&ak#WCjgSN5sovtaI40cB_R)j{?%!Ei={81jiOh!l#tx3GCFMe~cnJFNbo}Q*$otpxWP~fX4wA#tZSDT- zSMl3n`Ly%ncZI|A!*%z~$qj^3_<8l^7VIiHB6=FH?i4GOlSXUb z;b*Gn%v(|Ly_RBiUH?4UK%0$wgv7(=3Y)c`%EF`9lC_ga;$I-!7!yYGk)K+b5L;P? zk^xD}#X^?Dauj<|JDrgahWWyX+nqLpRq^7g{5U0sRI4HU2fmuDZN1n~ML`ZVyC|tc zQuCIk$gf`I0|E}dzhNQA?v{*r?7`P?vS-`Ge0u%&idtghM(oeIjLBpTgSxb&3)7b7 zR`OCe-?G{*(TZs6s_N`go!@^XEh@!d8gWv^VzT<}SwZ9)QICsiv;y16FvyEu6oF6x+iWO*FClI+wFTF3PZEK@&^FDzyE zZ6{ij`>2~tTYybG%`X3=paN!hMIGJWFF0Rz^UmazAvb^cS(9UX8l41+VmpnymsK7% z|MPfL@?T})R^A`Bao zbkLt$!mGIUYg*-~6xQVQNt;Z^5qUDw=R+{_9h7?B3)qGiYt4kZyk|D{!J5GFTu7M7 zQ8c_vk1qJ|r!=!Iq9_3>w&(dt*zR@s7o^`29 z=i4_((oLVx*Tbe$*5TBDa3*MA+-#?-tv`LfZB>u)q9w)pP4h1s`A>oO`H+C!;2xQI zda)u8ukh?tsj#WiKhcp3?6btmb)7c{waBhgtjpeG{)+Z#B)`YjqgkJoo|vdzhktNl z1TlUz2(C7*Dx*M-G=<_0SGQu3k|a!*6E(DIps7MeH245)}!3hy@vb_Am4!IRA+y?u5M0VIDzR_tNoj zTCA9j8DV{uVjoI>RS2e%b7MTedEM9-#)%E>^D1Bhp=jKf>=R99hZKv2i2oucfm+PK zSW|_DCCb8i&Ol3)v872y)L;^ZI*}8el|5Ctav>r)CV_U-5qwo{otbSW7Mfk|_dum? z#&X+Xcj47|zQ#-uTkCNVy?_IsF2W>d0^;g$2_vWjeXTE4!9=8_+%5lZB2QPxXquu< z#ot|_yr;PP3~z55DWOkEw)6={A>i-Mo8E!ecAnp9D)WWJb{h&pOh}`!GktSV9T@{d z;>+o&_-t9YGs0%b+uY?7dB((Yi5Y~xN*SDMaBUw8By2bfk@Zki2^$mX{GyWF{_t^* zQd{pjvHHVWuOX&k1(bGg=X>!fe~Q%2K6o0(ZA>$!K?-Mz(4e)boD>@ zyRG=R%BXl<%}p#x+)EFq!?tX;5$4~I=IC7D#x1W@qznl9AnEU}dioIK#C3F}C;ib+ zKe8)0^h2%PNq%aG>O@1V6c`|26GdH$|4ty>M8uJgn}?)`zoj0pv8s-qQp0OG;r}M~ zN=Z3Hm0w}V(|vK;BkQ|kuL`}V@9!wzwclOlzIA77=y{ti-yboEDlkN_lo2^|3V5>; z1_SO9+?;TnVV|kF0*l{Si4p{Vf;b^m{B?S>z!`QP(#aHa?8fDNeG`GF_DAcrU<-?o zH3z16_TSFQt1B#_-2lGIM8Wi+9k;x~KH+Eb-mf1*DC0UFI1a>iIK_|7F`_lP31t%( zd#_?U=o2xDkFN%iB0nYbs#Gt9!v6DWmJt@z2=qNQ_%aDM@@mg`!}QyqB`;_Wz69Q? zb8}UzKQ^*KSc^OD_yJhtyl`J48^3P;xgGt93HkR)sAL&_rG@&$X`@@SN^D1r;Kb{Y zp{i=MKdO0o>uQcVdu-u&swn=!GJM7-Wy4Gk*#Pa*=-YAiBHG0RZ9+#({=GhpAF0f> z2hGRgc9gGWPZp^u4o07SM8*s{nGDfLs1O=Tds&0 z-_n}MJeGIwzTq$oVYdlN5TAy8E(_eRaW+bO(tN9aFqV83McJIp@iaxr3oA(XuD_I8 z1HXp+wbDtqc-MY^JF3j2L(j7lW+FhXLTUQmJkfNEgoux3mghf9 zbGk1cJpzUEnaHeO;giQFFFP{h-jhS9Or{$+ya-JRqo`mWf?GK9kaL-?HPRIgQl&pB z#a}r0>))8J=8i>tg((pen{Bvm9J3Y0sEe-m#+DbUO&ledxYZan+{HU4M9s!Am^V+Dl5|TR^vyUYY!z8Hs>Tq!pV^*9`r+14j)i;=+E%U;a;-Q9~Su)viFboV%2# z(4BJkw#gv*SP+e}QA zV0|p($eW%)W$FcI1tMM2h_|i*cd;bQP0|8~K6cbHx{d9=#roD=@7hIcVNgBc3)QG> zvA-pkah-*~qi@Ebd1Op^<#+wvW-c}^-S4By9UO`ZTee{3wjHZMUB~^$8vlb2)5jIW z)q|2JB$0P&bu#NSJqV7#@hlM3Kdk8uV&x%;@1D6&9Eey4PbZ6 z+tT$wj9vDjJLAa1+;fZxk%;uW^N2cwKNQ6dXOt5}xP;o^wKnaOBx4OxH^Yr>%=<0G z3I}U+y*E<|xK&O{=a}OAyz|61)<`|!pE6%7rQh}xBI(K`xU=6LA&oU`+s~GHUm6`E zrPTFs;H68t{muTw?5y-%X+u$Zvh`CNCv4HtsE16c(_12(^q*BzN*5Jo>@Mk)iqHYE zoui4tPJhj_P2h5-_ANNY-@luBZOS@}EE3RXJ=BfqyXo^QVO0-z96e-U#J$Lt61_U7KR~?UTK?1-jB?^0>9w2-ad`&_k{KbFS=4)!=0v z^xE9o7|!6{aW_h~>R#7R(O%|3UPMOzV3T!Cmcq86gS5p;l2f}c>b;j+ojAL=s+_;< zD3r14s}!D*c)kRD+K-Ryn=LkkMfPX)gP3}L(bC5yREfAQ+W*Rb##kX~r!%hd2JyFa zF=HCcl05nl!u+nXCqt_XjLwovHqHXYtY{(T67+)^ho-R><@W&*?@lkRZrXWsRn}`G zJoK;}44(NSm~ITixB_Oq0w?dOc>Pw`Zt|lhVvn!iPNiw%z2emO=Y^L1>!M!E%vj|4 z4b?}9(&IT14$yD*)pKZ?eMf%O|BCk~xd+2LEE#`swA&j>j#qB^$|nao$E40Chju9L^U3B5p9EcLxv+1yC0kgmA?uGQ6tXy*7W#ekNLbdeYPJfIu}Ng~Y58u=!jJeW zB6;kmy$0uvcE=yzJ|mO3p+&dr6hBqNUwpDy`ufraJ+pu3f}ZH??r{YWIFq*S_WYq6DJ?T)Gv$r1LdP(`~&(ya`IAJ6++ zCw}`+|2DXKE_UPV^(1BT-uNqE9r$CG?>@m$x3;*mEmj{vAW*>;Vq!`%Vq*V`b_24V z;S(ny-K~TjqWH1yZ6c~Gx6}%~}|IpId-_bHg2U`95mEBVs z6j4)&S{X=o1GBmPC;!h|%GG3S?ceU*6r_7APVOgy!seupUErdg5W(LP>rJqK_Pz=ON{NbbAb=+6BGZ zd)r*E_bwAnDyIk}F(WhsVKI;_Y4V^69qtbDHKnI~yZVH-?2=6STAOXJ(g@y))gS{{s z2!W76WW+^O-4~Bm+`O?(HgC={D=b?6`q0Xd<-j4d(FHpC7tdD*&`1cV3ZoNxu4;Wy z{P&OBJ>dJg2aR;~clN((SozWjIq%+)w^=VW?mJDz02!RVC!O-G98&f{cU|O)BJjbNYGBw#%CH`eaQ=KtOA_(sT z6uKyFg+a&D&DoZTi3vG5xud&eWl4!c%gXb^o=}veQG{)AY3cs@ub_k33Y`{L8zZAU z)%%vu-Jv>mZHa!$5bQoh!S^5a^aLC>#Sz&~y^dQ>+9&d)8peZkDrOH44-@G%7#aHk32y)F&h+-kw6m zkO~R99WMhRbkuQFOH?s1Fy3=PM86sgjf^nR(3}p4HLV=alxf5e@i_jSEMQ&!7(eja z5r!=I21Sr3e$2Lk$)Noq%j>wLygXq;(Dm;mB|CdU9h@-28DabVF<--yPZW;#^W$}q zLORuw4-to@s=Yn46^cLlCRc`#Uwd=&U1>*KWu@)zaO#-geR;+;3j;$GIy9KyCNVKl zdp{W#78czg zLJ0Zqlf_z#k4{b(I6e{G8=5~p1-zvzRw>EN&DAskUfN+blE!g)d71otnM+ft(_s7b za2r0~(%9H|dTOu!20Y(`jf122glD%@fAqH~TYa$d@1^HxCddd5h-PD1ZNpW=LqlG- zJIOm9?dx`|=_4W{BJWv%SaRDV8}_>ALv(a>SsuHoLGWmF=5ws9tj@f|a<75bhQ3d? zdvf~D(>sn8dM&P7y-|aUb@et&=W)tFuH+vMTfJ;%qq+}Pu1AZPzp)f)Z09hsu(S+b zZn|#%4vToOv9YNbW+J`t!oL4BJz1 zucwESlF~s=A8hhDtHoq~wNc;I;Q|{KRj)a_B|Cu#`mm{!j7*pvS3+!TY)XnW0?1DN zJ%1+hvVHIV{tAMB-cJafpPx^f*Y)=1cY6!WO^zH-t(e99xobQ}3vg>08J91yNGTSN`g~a(S}fQd66(7k&o7zz=SW@YoI@`%{S4*1N6wT!#|c z#twXH#3F}8BTRUzeEjHkIPdUyIX7g?@3!KC2Xq5Q)E?tIX{E@1NtLT@USEQPe=tJ0 z--=sl)>+OpI&2wpCn~#*FK!yd+y;8^)1U9ov z-czfHlB6Jg^GX!>MdiT}!gMDt*z!h~yx0 zlD;J-x(qQiAOw;vVVD{l+f%;$&Sq{o)1|JF}Sm_s)VwU%m0@r{?u!Doc z@;5x7hg_EB^kQIcCB z$as}IVvM;oAi&4P&|D7Z<9eWl5jMOUR$SA6eL8(4u&M)FPb%o$ICp>}akg(Dpj75z zh5oWq(^fQJGjQ(QbP!6mcqed>fisdEUH+$=t&9wKNHDWKJ&7 zFbo8}OBj?I4*PZCT_^~`Xa6)_7dkgDc!((e_hHkE(~a&_cwkg0%i$Cj3k!??9)NIo z-`I~H!Mu!NWn;U)Jm}*GpzO8M^_ribq2b#LfYg|UQAqex#v-7>bzJ}^?}Gok|Nj`wof0#Agy?c8V-ur(=`k#+s%ls|ii(QDjp(tgLkdJEARxfS z#RX{>`~lDk2F7P*{Ao+yOIQT*bvyz>Ld8tpI)H4{%G8Mky>Gr5WM^dwI&A(vsOk`; zpa5ws4H1m|F3p+Fz{F&Cvf7r;W%qQ}M@mmm&vZd}adBbbzVRw=Vjh5-I0`A$H>~+m zF(g#+VYIKnQ}}zMnL5CaBbeIV8T#Uuz@T=Y7TE&N^8spVg|z7!Ger^f6dhsFRwF1~ zZ4r@Qfv=D!CnqZl0z1y1?oZ52OkTnhSUZ=7bpYVo?fxA{oB1CbB}G|j0$#3i{7)d! zbA9d#2FQnli;HdPWlWE04TEl@{lm?ff#0LckPW4f&~uF6!xq~ZKR_@e88D#l5&_W0 z8#dG744xVn&Ib3h&A(Gc*@8Z4sqhHoWNiSORoC%~f*v3_>@cSQOmTSBu;$vbQjRQ) z5TO1oKAz3*$@?~PFN$k*{>NvS188*7?;M&Hvkj}B2j^A9i@Yx}w$b%U9iA*$IAW>8 z?>UXbYMZmPx3?FR2v2?zTm*0fxwN=gv(>$tzwc^NjwzGZC7c5qfqXoW({{Ph^+?+z zx*|V+drDDgr*s(@QagOc@^L#}ahtyjWX{+rBq*Rn!o$NuCZF4&M=$_7K<&-%=w!kE zCjePX=q@<{&;~rO91qxuw5+5=tIf0Sp|8pN_Wb8h(1`&9V{mYAY*w1pFvJ905AhFP zp^K7EnX_ZsW|o-^i1_-ptAu)99csM{ZAZ(QJ4m!VP*YR$eh_h_{*a+Gs3a#Vd+5q1 z2Zt_dP+C=GXKo&Ac>op!V;&G>`?t=xGd~nW*4Nk18dm?X^dGZ$G*y(9lRI*4>Dy8+ zW72a|#y)br2T(xh{*Vo^uhn*?d87M_l%%Boy_iSaDlir(Zui?0(7{uGYZt6#-`MEs z=_x2Eh>AiZ!=rbtjZaUryX;R#5pvO4&4ZY^Jc4 z8nFKDfLtCBuf^@el&3^zkT6cLuGmPSUtrrHSi zwNo1R3hsF5>Vq!_PIDtKE&Wx!EZ+?t_$1>VgFSGT#`nMe`vCDkGE8B0JkCE?Dlir0Kz~0oK@=^VR&pWR- zx3^X3f(V+m zzdvdi%N8;a+-d?81R&3m8RM6j#B9?S0z2Ar+$={WRa|2_A}cR%toL#!YkPZJ=<%)|}8QL>u9zL5HA=1u$n zl?OJT9HDEz+UWXth0poV`0TQ+rRDzqOc_8jL_|cxbdccFLGwE8S(O46fC-rq1#>3M z;m}APe!-L0F1FF$T^+R;4}1gIfQ^Rc>n%LO1`aYJV%)P!yv{G+w5hP9`xAM6-zen( zjcH0+9jA!l|LJ+Tk3k`M+DNjLm>MRIHrW$XheE zU=7fFJp-T^AVUlK+1D&Q^b*=d5^^!}^JkR6fh1@Eh{nNOmEYBZ8A$a$mnl_kSBsz; z$H&K~>H`lLRMOLH0|XI}*hZ<{;*&+EaSWX!&MY8N_8&}lT` z!RQFipaRPXf3h?;Z=A0RlShY;#bSVN(f`N}(aZk*A0_|)tKB8cs$B?yREB_tk7XTi zrh3(sm5X+!Iv%$1OZzA2g_%*BKXq@Nxr@i_2|aH)^Xf4s5A8UDB2+ZBVZV6fx*LxU z?a#W2hl@)5f@mLl z4|yV|%v(BnOw_L6OqG|PP=g)I$iODW!^6TNCd7(QNr_E}MJFZ216?aj%<`$1CYWU2 zZGr1tV}$|q-^+0QsyT{q#-f^%rl!KeD^UwAWd{e5joYpZ2}(Rhc23S}Mvc;(oQ<~~ zD(Iqs9Q!3QvA=uAz)M&u+3w-VcwFJD3T~C&2DR^j=ffC-s00?<2pB=Z|*PkpuUWDm} zzwpB@dUQ-oB0{XGdWH08Vimspf;zi7PEIN+{^k6szt{~-ph$;E^hiaMEY;XOhhb5t zSE$b>qeBPBqCeR_Px3kUAFfuI#SFK%)pT`?bcXwJKmit3I>HH_|#8c z?%vhM%S?~US~~f|8>)DjimQu@B9Jrhs@iW|r;^yr#?E2_!KBQ>V#VrZSesidZU?O9 z!p~U(tRn+5zH1!@CB?@k#N#9$mU^30U}Rytpbj#}yMR z?aVc=&IZTk%3XN%fRxa|_`6KH^hAH=aWvEtdqBIZUk~^7`3h@CU@weFH|`2(8%#t;J&+)OvI;s z>*Ci9)~?7B+=-(^eqJqbqBaFmopRyeBr1&Px*tw@nq7K6&LrCrv1F8huJMDc(Z`Rj zql&}bJLYrsBZPjwCc~t*hIF9M+;P6LTjAOg&qKP(0t9 zv1~IE#`s^KQttZmWzbd?kpW8-`s~L2(+QOgEm^T_M)3CcKX|I;ZdK5@_T3zh;gRo3 z^faCnP8bl|1nn#-0fko{SiJj zxa|AX-(Ao_WoHit%l$lBtZ68$Px5F)5@2mva~C7i_W?b;Q+jH}oxPnMu;5<1*U1O@ zuhhYi@1NAmT;@Ont$XJ0Jh{#C`~*ls2{zZOj{zQY0@?Unu950xlrQ6EI5>p%vW!V8 zqj`8NZd|%wR7mODTDUo)0`9GfH1;k>I3bgWHwj83{CdWBHNzzAKvr zLts;BG@t&mU0$MWY!sH=Up4c}orNIpjpAVA;v^<(=r$^8YpL0|&1Zf{UOGB=|2^b~ zHo1ji!bCw}y=>;MGh9%+-&%WjDC+)dofVy7iv6;KI{RaR=Mu2<uWnHs|>8|W&H8Ss;B;X%9LdJX3v$GNs z5>I17py%&`D+jVUC!;3&|bq@o5O5sNSTm!2IUYfKpRk^24#Nbh?PDVmZI^aAmU z0@t>3e0raa1>DuHNw<<=slDSU$w5Q}E>YH`VM%d&_lVElek~yAwrH&1zO#oCPv7UU z3V5Xu+l5TqG(%)m6w4b0S1+8GjlDN~Oa}WH7#I{yB%rUP2^webp6Bjn%k>O&boib_ zJgD-NyFM4s?Ej0lNK||A+QY-9z?wZIY_7u-x5ID*wCu-!k?ZT95Wh@-^wS1q?)NeB`h2i98BGrIEP7!Y2pRc`TSFfQnXq7(uVG=hupnq5`O0S1?{Dsfe49+u z-vNe!x%v1k*ap_ww%R*x1E!L$yX^1(3X&Pv)Y!>rJ+J&lXGcTB#)0i?HhB;Qv#8I` z`Q@#m-xR)tgoK3NJx3t|7wgxy&{_bt%U|>~m;SLf#td}Ts#!Q(_!0vq1l_Qg*)&&6 zyh}J4zLaHQib4>aIXLQ6^xlkqVg~8O|94t?dI4|x_@{BKm;V4ZT(LDH0geDm6GO9T z{gQHpzhlDwI<{v<1JXh#KiK7gN&{h#z?P`eF#d0(Edntr^~JboqnH4s_TeL7a1VYO z4{fMl*p`jMqr(jeUIa}hL(q<*qT!x5evOQRf`W|9@g~Z$PO?HBRCf@Ags7;^BQStx;G9Ovr0-y^z{Dz{ad`RxA%ANZ&>(Ogs(j_KbVal zT*9@1P$}jJBrAqZlr2yxo3Ru@pWYvjMK6p4yU_*v>J=p=m9w911aivECA= zB?q+{ur5L@EZi#;5_bFPD2h;&H|28&Dd=De0=mrEqi?$vuGhRY2y0Ro0E9yq2G!TD z$z#}N%l3nu!iJg>7zZVe9(?cx#mBRE%Vx&K#rcn+lq6oWw*mHI5mMnHi2c z;5p#H@z}mmm$9hZqHZCBv1n-rfWBg zvn)&ivOpFH5_)Jn>HLM&L`_JT?(HfM4vX6Kld^z=lp3t90w5B*R6ICD?|QP-adb~? zHi`p|L$jsi&|wq9H6(%WXZ@&Md=sO9jKtb+Chgkd(>+Hhq<85t5Hgvx6i$W^D2#we z?(aWGQIqa1NMTg7B&74$vu99VR$Ods0V1)MTLj&ffJc-nh?c49=DtfJy}@@(#|=oT zEhFjK_gM^X=<_>|qVsH@&%VkIh!LU)P~R_??H^qL%>0H%aeu1FmgU=fZ2#k}ZxHZf+fM5t&RQ_++wtPGE-ONFuM8C8U;Gkqt zoV&&r@b-WD4(~$YZ~>O|S0!hcYjmlay9ZFWVQEAZtQIRN?%o)zgC|i9(23g1W2x)0 zpAZ|4&)h974>Vta;GP8BBQNPZb#Utp?8$!)XpUUGBQDN=J79=#*q;m#G-!( z6{?mT`~+%m7RidBgLI^tP6g&HSpQB|mrp$T*SYtHk_9z61BXPZj*^UTm<9;IaT#Cn z+$oE^yxe>Ns`l$jzWg+Juq>uilOBK`T~OxiX}^ENBEmC2G=FZ0B&6SfVgUxBZCW82 z=wmh)_A6PxBI zL4hwL26i0z^cXGr&`I&qSF4Ta?Nrf&g*qNo)T^>4kG-6o6V{$10rdO1d*%*~=eN5X zJ%&lOFH5v4d>vLZ(j`~PZlnA9dOm3>xcfz9eTZGH?iO0TU+RQlXXMwUg)2iq_yR8%BS z!@KF2WX9uVS~1%TAhfn_VR@6(BReK3RC)?uQAtiq|74cY-&(9va*s55&U~;@>Dy=i+_~4+Mo7^eiD3} zJ6QQ?bAQLwA?SG6*uBx1+dYVCQ37*!NzCV|+J|akS;vYh{UK}6&+=-ywA7OF>4BY{ zU3Xhh{e>_g#m1sP&){VboHi#%MJWgwo9#U~{}VqRKrSe7O<$q#6rZ>+D^ib=v>7J^ z{cB#6{OjSv)iN_vN0o1z$M&^0_tCFTnBLRVYb=kUk;5Y7Y>Lqot6B*?vlsaA@t^^} zR9DkTPDZ?yjD+#H`t{(T<_ z@TtMmsfj!ZiJsvgc~FV@GCu$hsVFKebRDWc0@vn`qQeL2Uaswz*|pah41^(>^W2(^ z0+t6>HeU(qT3k$gzT>(e<59-GK3qECY5|p$W;pw z2|c*Kx*)3n;)l!0zIeXT(lwvrZl)p0JLmOrw5M9WV08bkX|4Cq+Lt^RWH}&@zj)X` zz`ulu1$z0VH-{IT5(iuVagxKX3$^N>WIvsoihTauIoi3;H2ZwCa{YX1hZr5%V7+8p zr~PQbTK5nE{at)7B7C>)bnr`r5NOB-)Sp<*R{CAoA-C$=+1sDS{(@O*uv)TAcWu%I zwD`Q{cKa*3zsgQF&&4LaU%fUsbI8xG(7HdqNA_zn2plohX$A+x^!oed#f{s#0Ug9& zfhCaYy-uEX=miloTK-rs{ybXgcqdzXI|TG9HtU?^8C|xvHoAs*_f?^>wrgw$O}jsRuh-P;5+`T2_Vx^{b8MNQ73U zT2`LA9yF4DTF<#+dY5glhnp_6H%yy~#xexr(&a#nbS+n3LT2h{J|3!ia6ADthtFcr zXw7E9Gj8r3G3wqh&lpaY&{{6VEel^!dFx9iCIUTCt~KB5nYm|ev+A3PfbU!BC!8ZG zJbRAEuk5NdsRVfiK+R#`%6f!H)7ut2dD+Ze$EI1o+soy>z5BjCf(SXr*0U?Vs)yUC z@WH{MhosQZUh1s0w#$2B2FH1unw_kFWAsbF-Fzwe_D+M)6c_H=0_`?*4Ay=)-}bq! zT#sw4c^{m)SN`$J{IJ)GXQ1Eg9WplNA>{COPQ~CPS%@t|39WNY)24oJuR~i&)A_m0 zEhIFQ&U_p7i_`P3pywy+k-F9{+VIU>O48k|;q;qM9|2EiJZ~0eWo);jg}o{vX3_Nw zKbV`ggh<%qL7 z9P+svr5&8am=X8pQ|~xYznAkw#`9yUm)I4;g3a-oV?+as+h5=}t&+X)P zcS!;8Vds_=K|gON$4Qv$6+Ywf&h7l)WxlZj_g6wZR+Wx^uMt2`1BNU3dF4@GfQ@?D zXAfo0fEpoCUQ$h8x!UP^)vja7`$0S+J0m$M&G8~-VypLooR@c>uKn>bBm&!K23iyW z9N405_<^?2@#vD>O9BH$RMn`sxctGluhM4igxm9BPhF6ZoSVBCoMPtL5=}HHp3JBG z8G2xh>AP6pE(vdc!wPgECx0;bI8h(f1h6wWzXJRh9S_gSa^qg3apf57XWC-gVFm>t zHW@r#_2sRbvO=i)VxDb+EaZYUUJamqlV58GdTxZc1f>(^z9$DU&)%EW)Mnsx@+C)& zui?KA{fBDdb8mckG}R)v_o1C3cW8%^fgbp++xGk!2z5Z`jBmWl<_=gVr@Wj`W-F|c zLC;U$tp1y4=^%7WAyKsC-8BTGBT!F7&sUhI9SNZsd#zm=(;j8 z%GC`vy$|-&(soU)e0+Q)Ou#vrnwpD(i^53A8`&E7()qN#$fMOvU0ICmf_CPvZK zZDeF Date: Wed, 20 Aug 2025 10:10:56 +0200 Subject: [PATCH 082/251] Drop no longer needed feature gates --- library/stdarch/crates/core_arch/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index c58580f641780..7d3cbd55ad85c 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -18,8 +18,6 @@ rustc_attrs, staged_api, doc_cfg, - tbm_target_feature, - sse4a_target_feature, riscv_target_feature, arm_target_feature, mips_target_feature, From 135de7c8df64b8ef85ad348db09b02194779e68e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 14 Aug 2025 11:05:03 +0200 Subject: [PATCH 083/251] Use intrinsics for some s390x operations --- .../stdarch/crates/core_arch/src/s390x/vector.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 0ce720a9244cd..9927ff2c62555 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -114,6 +114,9 @@ unsafe extern "unadjusted" { #[link_name = "llvm.s390.vsumqf"] fn vsumqf(a: vector_unsigned_int, b: vector_unsigned_int) -> u128; #[link_name = "llvm.s390.vsumqg"] fn vsumqg(a: vector_unsigned_long_long, b: vector_unsigned_long_long) -> u128; + #[link_name = "llvm.s390.vaccq"] fn vaccq(a: u128, b: u128) -> u128; + #[link_name = "llvm.s390.vacccq"] fn vacccq(a: u128, b: u128, c: u128) -> u128; + #[link_name = "llvm.s390.vscbiq"] fn vscbiq(a: u128, b: u128) -> u128; #[link_name = "llvm.s390.vsbiq"] fn vsbiq(a: u128, b: u128, c: u128) -> u128; #[link_name = "llvm.s390.vsbcbiq"] fn vsbcbiq(a: u128, b: u128, c: u128) -> u128; @@ -4694,7 +4697,9 @@ pub unsafe fn vec_addc_u128( ) -> vector_unsigned_char { let a: u128 = transmute(a); let b: u128 = transmute(b); - transmute(a.overflowing_add(b).1 as u128) + // FIXME(llvm) https://github.com/llvm/llvm-project/pull/153557 + // transmute(a.overflowing_add(b).1 as u128) + transmute(vaccq(a, b)) } /// Vector Add With Carry unsigned 128-bits @@ -4729,8 +4734,10 @@ pub unsafe fn vec_addec_u128( let a: u128 = transmute(a); let b: u128 = transmute(b); let c: u128 = transmute(c); - let (_d, carry) = a.carrying_add(b, c & 1 != 0); - transmute(carry as u128) + // FIXME(llvm) https://github.com/llvm/llvm-project/pull/153557 + // let (_d, carry) = a.carrying_add(b, c & 1 != 0); + // transmute(carry as u128) + transmute(vacccq(a, b, c)) } /// Vector Subtract with Carryout From 4a8b8231b1e7263ae5d8da82ccd5c1490f1db9e7 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 20 Aug 2025 10:18:03 +0200 Subject: [PATCH 084/251] Add missing avx512vl target features --- .../crates/core_arch/src/x86/avx512fp16.rs | 376 +++++++++--------- 1 file changed, 188 insertions(+), 188 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/avx512fp16.rs b/library/stdarch/crates/core_arch/src/x86/avx512fp16.rs index 8c914803c665d..a86fc7199b83c 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512fp16.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512fp16.rs @@ -17282,14 +17282,14 @@ mod tests { assert_eq_m512h(a, b); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_load_sh() { let a = _mm_set_sh(1.0); let b = _mm_load_sh(addr_of!(a).cast()); assert_eq_m128h(a, b); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_load_sh() { let a = _mm_set_sh(1.0); let src = _mm_set_sh(2.); @@ -17299,7 +17299,7 @@ mod tests { assert_eq_m128h(src, b); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_load_sh() { let a = _mm_set_sh(1.0); let b = _mm_maskz_load_sh(1, addr_of!(a).cast()); @@ -17344,7 +17344,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_move_sh() { let a = _mm_set_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let b = _mm_set_sh(9.0); @@ -17353,7 +17353,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_move_sh() { let a = _mm_set_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let b = _mm_set_sh(9.0); @@ -17363,7 +17363,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_move_sh() { let a = _mm_set_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let b = _mm_set_sh(9.0); @@ -17402,7 +17402,7 @@ mod tests { assert_eq_m512h(a, b); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_store_sh() { let a = _mm_set_sh(1.0); let mut b = _mm_setzero_ph(); @@ -17410,7 +17410,7 @@ mod tests { assert_eq_m128h(a, b); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_store_sh() { let a = _mm_set_sh(1.0); let mut b = _mm_setzero_ph(); @@ -17655,7 +17655,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_add_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17664,7 +17664,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_add_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17681,7 +17681,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_add_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17695,7 +17695,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_add_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17704,7 +17704,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_add_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17717,7 +17717,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_add_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17945,7 +17945,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_sub_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17954,7 +17954,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_sub_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17971,7 +17971,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_sub_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17985,7 +17985,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_sub_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -17994,7 +17994,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_sub_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18007,7 +18007,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_sub_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18235,7 +18235,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mul_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18244,7 +18244,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_mul_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18261,7 +18261,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_mul_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18275,7 +18275,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mul_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18284,7 +18284,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_mul_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18297,7 +18297,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_mul_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18457,7 +18457,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_div_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18466,7 +18466,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_div_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18483,7 +18483,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_div_round_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18497,7 +18497,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_div_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18506,7 +18506,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_div_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18519,7 +18519,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_div_sh() { let a = _mm_set_sh(1.0); let b = _mm_set_sh(2.0); @@ -18680,7 +18680,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18689,7 +18689,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_mul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18701,7 +18701,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_mul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18711,7 +18711,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18720,7 +18720,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_mul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18730,7 +18730,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_mul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18888,7 +18888,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18897,7 +18897,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18909,7 +18909,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18919,7 +18919,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18928,7 +18928,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -18938,7 +18938,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 1.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19096,7 +19096,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19105,7 +19105,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19115,7 +19115,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19124,7 +19124,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19133,7 +19133,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19145,7 +19145,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19304,7 +19304,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fcmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19313,7 +19313,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fcmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19323,7 +19323,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fcmul_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19332,7 +19332,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fcmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19341,7 +19341,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fcmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19353,7 +19353,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fcmul_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, -1.0, 8.0, -9.0, 10.0, -11.0, 12.0, -13.0); @@ -19692,7 +19692,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19702,7 +19702,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19715,7 +19715,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19728,7 +19728,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19741,7 +19741,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19751,7 +19751,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19768,7 +19768,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -19785,7 +19785,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20002,7 +20002,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fcmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20012,7 +20012,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fcmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20025,7 +20025,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fcmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20038,7 +20038,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fcmadd_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20051,7 +20051,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fcmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20061,7 +20061,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fcmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20078,7 +20078,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fcmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20095,7 +20095,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fcmadd_round_sch() { let a = _mm_setr_ph(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0); let b = _mm_setr_ph(0.0, 2.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0); @@ -20311,7 +20311,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20321,7 +20321,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20334,7 +20334,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20347,7 +20347,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20360,7 +20360,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20370,7 +20370,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20387,7 +20387,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20404,7 +20404,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20620,7 +20620,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20630,7 +20630,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20643,7 +20643,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20656,7 +20656,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20669,7 +20669,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fmsub_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20930,7 +20930,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fnmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20940,7 +20940,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fnmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20953,7 +20953,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fnmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20966,7 +20966,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fnmadd_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20979,7 +20979,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fnmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -20989,7 +20989,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fnmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21006,7 +21006,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fnmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21023,7 +21023,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fnmadd_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21240,7 +21240,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fnmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21250,7 +21250,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fnmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21263,7 +21263,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fnmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21276,7 +21276,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fnmsub_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21289,7 +21289,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_fnmsub_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21299,7 +21299,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_fnmsub_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21316,7 +21316,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask3_fnmsub_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21333,7 +21333,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_fnmsub_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(2.0, 20., 21., 22., 23., 24., 25., 26.); @@ -21851,7 +21851,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_rcp_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -21860,7 +21860,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_rcp_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -21873,7 +21873,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_rcp_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -21970,7 +21970,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_rsqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -21979,7 +21979,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_rsqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -21992,7 +21992,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_rsqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22127,7 +22127,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_sqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22136,7 +22136,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_sqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22149,7 +22149,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_sqrt_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22161,7 +22161,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_sqrt_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22170,7 +22170,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_sqrt_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22187,7 +22187,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_sqrt_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(4.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0); @@ -22338,7 +22338,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_max_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22347,7 +22347,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_max_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22360,7 +22360,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_max_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22372,7 +22372,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_max_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22381,7 +22381,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_max_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22398,7 +22398,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_max_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22549,7 +22549,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_min_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22558,7 +22558,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_min_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22571,7 +22571,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_min_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22583,7 +22583,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_min_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22592,7 +22592,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_min_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22609,7 +22609,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_min_round_sh() { let a = _mm_setr_ph(1.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); let b = _mm_setr_ph(2.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); @@ -22746,7 +22746,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_getexp_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22755,7 +22755,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_getexp_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22768,7 +22768,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_getexp_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22780,7 +22780,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_getexp_round_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22789,7 +22789,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_getexp_round_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22802,7 +22802,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_getexp_round_sh() { let a = _mm_setr_ph(4.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22958,7 +22958,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_getmant_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22967,7 +22967,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_getmant_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22980,7 +22980,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_getmant_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -22992,7 +22992,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_getmant_round_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23003,7 +23003,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_getmant_round_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23024,7 +23024,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_getmant_round_sh() { let a = _mm_setr_ph(15.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(10.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23167,7 +23167,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_roundscale_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23176,7 +23176,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_roundscale_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23189,7 +23189,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_roundscale_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23201,7 +23201,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_roundscale_round_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23210,7 +23210,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_roundscale_round_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23223,7 +23223,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_roundscale_round_sh() { let a = _mm_setr_ph(2.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.1, 20., 21., 22., 23., 24., 25., 26.); @@ -23372,7 +23372,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_scalef_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23381,7 +23381,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_scalef_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23394,7 +23394,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_scalef_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23406,7 +23406,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_scalef_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23415,7 +23415,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_scalef_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23432,7 +23432,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_scalef_round_sh() { let a = _mm_setr_ph(1.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(3.0, 20., 21., 22., 23., 24., 25., 26.); @@ -23576,7 +23576,7 @@ mod tests { assert_eq_m512h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_reduce_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -23585,7 +23585,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_reduce_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -23598,7 +23598,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_reduce_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -23610,7 +23610,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_reduce_round_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -23619,7 +23619,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_reduce_round_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -23636,7 +23636,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_reduce_round_sh() { let a = _mm_setr_ph(3.0, 10., 11., 12., 13., 14., 15., 16.); let b = _mm_setr_ph(1.25, 20., 21., 22., 23., 24., 25., 26.); @@ -24505,7 +24505,7 @@ mod tests { assert_eq_m256h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvti32_sh() { let a = _mm_setr_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm_cvti32_sh(a, 10); @@ -24513,7 +24513,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvt_roundi32_sh() { let a = _mm_setr_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm_cvt_roundi32_sh::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>(a, 10); @@ -24645,7 +24645,7 @@ mod tests { assert_eq_m256h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvtu32_sh() { let a = _mm_setr_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm_cvtu32_sh(a, 10); @@ -24653,7 +24653,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvt_roundu32_sh() { let a = _mm_setr_ph(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm_cvt_roundu32_sh::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>(a, 10); @@ -24711,7 +24711,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvtepi64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_cvtepi64_ph(a); @@ -24719,7 +24719,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_mask_cvtepi64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let src = _mm_set_ph(10., 11., 12., 13., 14., 15., 16., 17.); @@ -24728,7 +24728,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvtepi64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_maskz_cvtepi64_ph(0b01010101, a); @@ -24736,7 +24736,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvt_roundepi64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_cvt_roundepi64_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>(a); @@ -24755,7 +24755,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvt_roundepi64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_maskz_cvt_roundepi64_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>( @@ -24815,7 +24815,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvtepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_cvtepu64_ph(a); @@ -24823,7 +24823,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_mask_cvtepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let src = _mm_set_ph(10., 11., 12., 13., 14., 15., 16., 17.); @@ -24832,7 +24832,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvtepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_maskz_cvtepu64_ph(0b01010101, a); @@ -24840,7 +24840,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvt_roundepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_cvt_roundepu64_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>(a); @@ -24848,7 +24848,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_mask_cvt_roundepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let src = _mm_set_ph(10., 11., 12., 13., 14., 15., 16., 17.); @@ -24859,7 +24859,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvt_roundepu64_ph() { let a = _mm512_set_epi64(1, 2, 3, 4, 5, 6, 7, 8); let r = _mm512_maskz_cvt_roundepu64_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>( @@ -25005,7 +25005,7 @@ mod tests { assert_eq_m256h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvtss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25014,7 +25014,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cvtss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25027,7 +25027,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cvtss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25039,7 +25039,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvt_roundss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25048,7 +25048,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cvt_roundss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25065,7 +25065,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cvt_roundss_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); @@ -25129,7 +25129,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvtpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm512_cvtpd_ph(a); @@ -25137,7 +25137,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_mask_cvtpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let src = _mm_set_ph(10., 11., 12., 13., 14., 15., 16., 17.); @@ -25146,7 +25146,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvtpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm512_maskz_cvtpd_ph(0b01010101, a); @@ -25154,7 +25154,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_cvt_roundpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm512_cvt_roundpd_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>(a); @@ -25162,7 +25162,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_mask_cvt_roundpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let src = _mm_set_ph(10., 11., 12., 13., 14., 15., 16., 17.); @@ -25173,7 +25173,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm512_maskz_cvt_roundpd_ph() { let a = _mm512_set_pd(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0); let r = _mm512_maskz_cvt_roundpd_ph::<{ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC }>( @@ -25183,7 +25183,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvtsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); @@ -25192,7 +25192,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cvtsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); @@ -25205,7 +25205,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cvtsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); @@ -25217,7 +25217,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_cvt_roundsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); @@ -25226,7 +25226,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_mask_cvt_roundsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); @@ -25243,7 +25243,7 @@ mod tests { assert_eq_m128h(r, e); } - #[simd_test(enable = "avx512fp16")] + #[simd_test(enable = "avx512fp16,avx512vl")] unsafe fn test_mm_maskz_cvt_roundsd_sh() { let a = _mm_setr_ph(10., 11., 12., 13., 14., 15., 16., 17.); let b = _mm_setr_pd(1.0, 2.0); From 92f6310890e16790eb44abcb33cffa0f8090e0c3 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 20 Aug 2025 11:00:47 +0200 Subject: [PATCH 085/251] Work around selection failure without avx512vl --- library/stdarch/crates/core_arch/src/x86/avx512f.rs | 8 ++++++-- library/stdarch/crates/core_arch/src/x86_64/avx512f.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index d53f83c0a10bc..cad8ca0c63ce0 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -49621,7 +49621,9 @@ mod tests { assert_eq_m512i(r, e); } - #[simd_test(enable = "avx512f")] + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 + //#[simd_test(enable = "avx512f")] + #[simd_test(enable = "avx512f,avx512vl")] unsafe fn test_mm512_mask_cvttps_epu32() { let a = _mm512_setr_ps( 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, @@ -49634,7 +49636,9 @@ mod tests { assert_eq_m512i(r, e); } - #[simd_test(enable = "avx512f")] + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 + //#[simd_test(enable = "avx512f")] + #[simd_test(enable = "avx512f,avx512vl")] unsafe fn test_mm512_maskz_cvttps_epu32() { let a = _mm512_setr_ps( 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, diff --git a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs index 934c9e2812c42..a8dd340bd6605 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs @@ -5311,7 +5311,9 @@ mod tests { assert_eq_m256i(r, e); } - #[simd_test(enable = "avx512f")] + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 + //#[simd_test(enable = "avx512f")] + #[simd_test(enable = "avx512f,avx512vl")] unsafe fn test_mm512_mask_cvttpd_epu32() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); let src = _mm256_set1_epi32(0); @@ -5322,7 +5324,9 @@ mod tests { assert_eq_m256i(r, e); } - #[simd_test(enable = "avx512f")] + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 + //#[simd_test(enable = "avx512f")] + #[simd_test(enable = "avx512f,avx512vl")] unsafe fn test_mm512_maskz_cvttpd_epu32() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); let r = _mm512_maskz_cvttpd_epu32(0, a); From 3302e3e09a2f843ba7a20102f0f5f18909bc0b47 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 20 Aug 2025 11:12:26 +0200 Subject: [PATCH 086/251] Adjust immediate for vrndscalepd tests The immediate here encodes both the rounding mode (in the low bits) and the scale (in the high bits). Make sure the scale is non-zero. --- library/stdarch/crates/core_arch/src/x86/avx512f.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index cad8ca0c63ce0..0803f2f81b215 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -5823,7 +5823,7 @@ pub fn _mm512_maskz_roundscale_pd(k: __mmask8, a: __m512d) -> _ #[inline] #[target_feature(enable = "avx512f,avx512vl")] #[stable(feature = "stdarch_x86_avx512", since = "1.89")] -#[cfg_attr(test, assert_instr(vrndscalepd, IMM8 = 0))] +#[cfg_attr(test, assert_instr(vrndscalepd, IMM8 = 16))] #[rustc_legacy_const_generics(1)] pub fn _mm256_roundscale_pd(a: __m256d) -> __m256d { unsafe { @@ -5897,7 +5897,7 @@ pub fn _mm256_maskz_roundscale_pd(k: __mmask8, a: __m256d) -> _ #[inline] #[target_feature(enable = "avx512f,avx512vl")] #[stable(feature = "stdarch_x86_avx512", since = "1.89")] -#[cfg_attr(test, assert_instr(vrndscalepd, IMM8 = 0))] +#[cfg_attr(test, assert_instr(vrndscalepd, IMM8 = 16))] #[rustc_legacy_const_generics(1)] pub fn _mm_roundscale_pd(a: __m128d) -> __m128d { unsafe { From fa163a1fcaa1d46a62d4a19b9354da5583dbf5d1 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 18:02:12 +0200 Subject: [PATCH 087/251] s390x: define `unpack_low` using `core::intrinsics::simd` --- .../crates/core_arch/src/s390x/vector.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 9927ff2c62555..2969516c9ae44 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -169,13 +169,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.s390.vpklsfs"] fn vpklsfs(a: vector_unsigned_int, b: vector_unsigned_int) -> PackedTuple; #[link_name = "llvm.s390.vpklsgs"] fn vpklsgs(a: vector_unsigned_long_long, b: vector_unsigned_long_long) -> PackedTuple; - #[link_name = "llvm.s390.vuplb"] fn vuplb (a: vector_signed_char) -> vector_signed_short; - #[link_name = "llvm.s390.vuplhw"] fn vuplhw (a: vector_signed_short) -> vector_signed_int; - #[link_name = "llvm.s390.vuplf"] fn vuplf (a: vector_signed_int) -> vector_signed_long_long; - #[link_name = "llvm.s390.vupllb"] fn vupllb (a: vector_unsigned_char) -> vector_unsigned_short; - #[link_name = "llvm.s390.vupllh"] fn vupllh (a: vector_unsigned_short) -> vector_unsigned_int; - #[link_name = "llvm.s390.vupllf"] fn vupllf (a: vector_unsigned_int) -> vector_unsigned_long_long; - #[link_name = "llvm.s390.vavgb"] fn vavgb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_char; #[link_name = "llvm.s390.vavgh"] fn vavgh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_short; #[link_name = "llvm.s390.vavgf"] fn vavgf(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int; @@ -2583,8 +2576,14 @@ mod sealed { unsafe fn vec_unpackl(self) -> Self::Result; } - // FIXME(llvm): a shuffle + simd_as does not currently optimize into a single instruction like - // unpachk above. Tracked in https://github.com/llvm/llvm-project/issues/129576. + // NOTE: `vuplh` is used for "unpack logical high", hence `vuplhw`. + impl_vec_unpack!(unpack_low vuplb vector_signed_char i8x8 vector_signed_short 8); + impl_vec_unpack!(unpack_low vuplhw vector_signed_short i16x4 vector_signed_int 4); + impl_vec_unpack!(unpack_low vuplf vector_signed_int i32x2 vector_signed_long_long 2); + + impl_vec_unpack!(unpack_low vupllb vector_unsigned_char u8x8 vector_unsigned_short 8); + impl_vec_unpack!(unpack_low vupllh vector_unsigned_short u16x4 vector_unsigned_int 4); + impl_vec_unpack!(unpack_low vupllf vector_unsigned_int u32x2 vector_unsigned_long_long 2); impl_vec_trait! {[VectorUnpackl vec_unpackl] vuplb (vector_signed_char) -> vector_signed_short} impl_vec_trait! {[VectorUnpackl vec_unpackl] vuplhw (vector_signed_short) -> vector_signed_int} From c5ec0960f0a1d78584b4957dd71613bdbcb91de8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 18:03:04 +0200 Subject: [PATCH 088/251] s390x: add `assert_instr` for `vec_round` --- library/stdarch/crates/core_arch/src/s390x/vector.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 2969516c9ae44..066ae1607316d 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -1194,10 +1194,8 @@ mod sealed { test_impl! { vec_roundc_f32 (a: vector_float) -> vector_float [nearbyint_v4f32, "vector-enhancements-1" vfisb] } test_impl! { vec_roundc_f64 (a: vector_double) -> vector_double [nearbyint_v2f64, vfidb] } - // FIXME(llvm) llvm trunk already lowers roundeven to vfidb, but rust does not use it yet - // use https://godbolt.org/z/cWq95fexe to check, and enable the instruction test when it works - test_impl! { vec_round_f32 (a: vector_float) -> vector_float [roundeven_v4f32, _] } - test_impl! { vec_round_f64 (a: vector_double) -> vector_double [roundeven_v2f64, _] } + test_impl! { vec_round_f32 (a: vector_float) -> vector_float [roundeven_v4f32, "vector-enhancements-1" vfisb] } + test_impl! { vec_round_f64 (a: vector_double) -> vector_double [roundeven_v2f64, vfidb] } #[unstable(feature = "stdarch_s390x", issue = "135681")] pub trait VectorRoundc { From 97d64665b9e4e390cd3cadf403de5cfa67b3216a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 18:03:41 +0200 Subject: [PATCH 089/251] s390x: add `assert_instr` for `vec_extend` --- library/stdarch/crates/core_arch/src/s390x/vector.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 066ae1607316d..b010b7e38267e 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -3319,8 +3319,7 @@ mod sealed { #[inline] #[target_feature(enable = "vector")] - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/129899 - // #[cfg_attr(test, assert_instr(vsegb))] + #[cfg_attr(test, assert_instr(vsegb))] pub unsafe fn vsegb(a: vector_signed_char) -> vector_signed_long_long { simd_as(simd_shuffle::<_, _, i8x2>( a, @@ -3331,8 +3330,7 @@ mod sealed { #[inline] #[target_feature(enable = "vector")] - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/129899 - // #[cfg_attr(test, assert_instr(vsegh))] + #[cfg_attr(test, assert_instr(vsegh))] pub unsafe fn vsegh(a: vector_signed_short) -> vector_signed_long_long { simd_as(simd_shuffle::<_, _, i16x2>( a, @@ -3343,8 +3341,7 @@ mod sealed { #[inline] #[target_feature(enable = "vector")] - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/129899 - // #[cfg_attr(test, assert_instr(vsegf))] + #[cfg_attr(test, assert_instr(vsegf))] pub unsafe fn vsegf(a: vector_signed_int) -> vector_signed_long_long { simd_as(simd_shuffle::<_, _, i32x2>( a, From 1cda88aca15307dbcd1f6404875999373105a93d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 18:04:15 +0200 Subject: [PATCH 090/251] s390x: implement `vec_mule` using `core::intrinsics::simd` --- .../crates/core_arch/src/s390x/vector.rs | 85 ++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index b010b7e38267e..2af5edb9fb005 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -181,14 +181,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.s390.vcksm"] fn vcksm(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_int; - #[link_name = "llvm.s390.vmeb"] fn vmeb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_short; - #[link_name = "llvm.s390.vmeh"] fn vmeh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_int; - #[link_name = "llvm.s390.vmef"] fn vmef(a: vector_signed_int, b: vector_signed_int) -> vector_signed_long_long; - - #[link_name = "llvm.s390.vmleb"] fn vmleb(a: vector_unsigned_char, b: vector_unsigned_char) -> vector_unsigned_short; - #[link_name = "llvm.s390.vmleh"] fn vmleh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_unsigned_int; - #[link_name = "llvm.s390.vmlef"] fn vmlef(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_long_long; - #[link_name = "llvm.s390.vmob"] fn vmob(a: vector_signed_char, b: vector_signed_char) -> vector_signed_short; #[link_name = "llvm.s390.vmoh"] fn vmoh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_int; #[link_name = "llvm.s390.vmof"] fn vmof(a: vector_signed_int, b: vector_signed_int) -> vector_signed_long_long; @@ -372,6 +364,19 @@ impl ShuffleMask { ShuffleMask(mask) } + const fn even() -> Self { + let mut mask = [0; N]; + let mut i = 0; + let mut index = 0; + while index < N { + mask[index] = i as u32; + + i += 2; + index += 1; + } + ShuffleMask(mask) + } + const fn pack() -> Self { let mut mask = [0; N]; let mut i = 1; @@ -2642,40 +2647,44 @@ mod sealed { unsafe fn vec_mule(self, b: Self) -> Result; } - // FIXME(llvm) sadly this does not yet work https://github.com/llvm/llvm-project/issues/129705 - // #[target_feature(enable = "vector")] - // #[cfg_attr(test, assert_instr(vmleh))] - // unsafe fn vec_vmleh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_unsigned_int { - // let even_a: vector_unsigned_int = simd_as(simd_shuffle::<_, _, u16x4>( - // a, - // a, - // const { ShuffleMask([0, 2, 4, 6]) }, - // )); - // - // let even_b: vector_unsigned_int = simd_as(simd_shuffle::<_, _, u16x4>( - // b, - // b, - // const { ShuffleMask([0, 2, 4, 6]) }, - // )); - // - // simd_mul(even_a, even_b) - // } + macro_rules! impl_vec_mule { + ($instr:ident $src:ident $shuffled:ident $dst:ident $width:literal) => { + #[inline] + #[target_feature(enable = "vector")] + #[cfg_attr(test, assert_instr($instr))] + unsafe fn $instr(a: $src, b: $src) -> $dst { + let even_a: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( + a, + a, + const { ShuffleMask::<$width>::even() }, + )); + + let even_b: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( + b, + b, + const { ShuffleMask::<$width>::even() }, + )); + + simd_mul(even_a, even_b) + } + }; + } - test_impl! { vec_vmeb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_short [ vmeb, vmeb ] } - test_impl! { vec_vmeh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_int[ vmeh, vmeh ] } - test_impl! { vec_vmef(a: vector_signed_int, b: vector_signed_int) -> vector_signed_long_long [ vmef, vmef ] } + impl_vec_mule! { vmeb vector_signed_char i8x8 vector_signed_short 8 } + impl_vec_mule! { vmeh vector_signed_short i16x4 vector_signed_int 4 } + impl_vec_mule! { vmef vector_signed_int i32x2 vector_signed_long_long 2 } - test_impl! { vec_vmleb(a: vector_unsigned_char, b: vector_unsigned_char) -> vector_unsigned_short [ vmleb, vmleb ] } - test_impl! { vec_vmleh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_unsigned_int[ vmleh, vmleh ] } - test_impl! { vec_vmlef(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_long_long [ vmlef, vmlef ] } + impl_vec_mule! { vmleb vector_unsigned_char u8x8 vector_unsigned_short 8 } + impl_vec_mule! { vmleh vector_unsigned_short u16x4 vector_unsigned_int 4 } + impl_vec_mule! { vmlef vector_unsigned_int u32x2 vector_unsigned_long_long 2 } - impl_mul!([VectorMule vec_mule] vec_vmeb (vector_signed_char, vector_signed_char) -> vector_signed_short ); - impl_mul!([VectorMule vec_mule] vec_vmeh (vector_signed_short, vector_signed_short) -> vector_signed_int); - impl_mul!([VectorMule vec_mule] vec_vmef (vector_signed_int, vector_signed_int) -> vector_signed_long_long ); + impl_mul!([VectorMule vec_mule] vmeb (vector_signed_char, vector_signed_char) -> vector_signed_short ); + impl_mul!([VectorMule vec_mule] vmeh (vector_signed_short, vector_signed_short) -> vector_signed_int); + impl_mul!([VectorMule vec_mule] vmef (vector_signed_int, vector_signed_int) -> vector_signed_long_long ); - impl_mul!([VectorMule vec_mule] vec_vmleb (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_short ); - impl_mul!([VectorMule vec_mule] vec_vmleh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_int); - impl_mul!([VectorMule vec_mule] vec_vmlef (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_long_long ); + impl_mul!([VectorMule vec_mule] vmleb (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_short ); + impl_mul!([VectorMule vec_mule] vmleh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_int); + impl_mul!([VectorMule vec_mule] vmlef (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_long_long ); #[unstable(feature = "stdarch_s390x", issue = "135681")] pub trait VectorMulo { From d5cb1c49fa415b512c0616730193467fd5fe2a9a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 14 Aug 2025 18:51:39 +0200 Subject: [PATCH 091/251] wasm: use `{read, write}_unaligned` methods --- .../crates/core_arch/src/wasm32/simd128.rs | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs index 108bc3125c5f3..c864d6a516e08 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs @@ -141,16 +141,6 @@ unsafe extern "unadjusted" { fn llvm_f64x2_max(x: simd::f64x2, y: simd::f64x2) -> simd::f64x2; } -#[repr(C, packed)] -#[derive(Copy)] -struct Unaligned(T); - -impl Clone for Unaligned { - fn clone(&self) -> Unaligned { - *self - } -} - /// Loads a `v128` vector from the given heap address. /// /// This intrinsic will emit a load with an alignment of 1. While this is @@ -179,7 +169,7 @@ impl Clone for Unaligned { #[doc(alias("v128.load"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn v128_load(m: *const v128) -> v128 { - (*(m as *const Unaligned)).0 + m.read_unaligned() } /// Load eight 8-bit integers and sign extend each one to a 16-bit lane @@ -196,8 +186,8 @@ pub unsafe fn v128_load(m: *const v128) -> v128 { #[doc(alias("v128.load8x8_s"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i16x8_load_extend_i8x8(m: *const i8) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::i16x8>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::i16x8>(m).v128() } /// Load eight 8-bit integers and zero extend each one to a 16-bit lane @@ -214,8 +204,8 @@ pub unsafe fn i16x8_load_extend_i8x8(m: *const i8) -> v128 { #[doc(alias("v128.load8x8_u"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i16x8_load_extend_u8x8(m: *const u8) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::u16x8>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::u16x8>(m).v128() } #[stable(feature = "wasm_simd", since = "1.54.0")] @@ -235,8 +225,8 @@ pub use i16x8_load_extend_u8x8 as u16x8_load_extend_u8x8; #[doc(alias("v128.load16x4_s"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i32x4_load_extend_i16x4(m: *const i16) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::i32x4>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::i32x4>(m).v128() } /// Load four 16-bit integers and zero extend each one to a 32-bit lane @@ -253,8 +243,8 @@ pub unsafe fn i32x4_load_extend_i16x4(m: *const i16) -> v128 { #[doc(alias("v128.load16x4_u"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i32x4_load_extend_u16x4(m: *const u16) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::u32x4>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::u32x4>(m).v128() } #[stable(feature = "wasm_simd", since = "1.54.0")] @@ -274,8 +264,8 @@ pub use i32x4_load_extend_u16x4 as u32x4_load_extend_u16x4; #[doc(alias("v128.load32x2_s"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i64x2_load_extend_i32x2(m: *const i32) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::i64x2>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::i64x2>(m).v128() } /// Load two 32-bit integers and zero extend each one to a 64-bit lane @@ -292,8 +282,8 @@ pub unsafe fn i64x2_load_extend_i32x2(m: *const i32) -> v128 { #[doc(alias("v128.load32x2_u"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn i64x2_load_extend_u32x2(m: *const u32) -> v128 { - let m = *(m as *const Unaligned); - simd_cast::<_, simd::u64x2>(m.0).v128() + let m = m.cast::().read_unaligned(); + simd_cast::<_, simd::u64x2>(m).v128() } #[stable(feature = "wasm_simd", since = "1.54.0")] @@ -453,7 +443,7 @@ pub unsafe fn v128_load64_zero(m: *const u64) -> v128 { #[doc(alias("v128.store"))] #[stable(feature = "wasm_simd", since = "1.54.0")] pub unsafe fn v128_store(m: *mut v128, a: v128) { - *(m as *mut Unaligned) = Unaligned(a); + m.write_unaligned(a) } /// Loads an 8-bit value from `m` and sets lane `L` of `v` to that value. From e1a1b1ded2d14c2bb40d236a93ad629222db4da2 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 21:18:39 +0200 Subject: [PATCH 092/251] s390x: implement `vec_mulo` using `core::intrinsics::simd` --- .../crates/core_arch/src/s390x/vector.rs | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 2af5edb9fb005..6775225788925 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -181,14 +181,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.s390.vcksm"] fn vcksm(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_int; - #[link_name = "llvm.s390.vmob"] fn vmob(a: vector_signed_char, b: vector_signed_char) -> vector_signed_short; - #[link_name = "llvm.s390.vmoh"] fn vmoh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_int; - #[link_name = "llvm.s390.vmof"] fn vmof(a: vector_signed_int, b: vector_signed_int) -> vector_signed_long_long; - - #[link_name = "llvm.s390.vmlob"] fn vmlob(a: vector_unsigned_char, b: vector_unsigned_char) -> vector_unsigned_short; - #[link_name = "llvm.s390.vmloh"] fn vmloh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_unsigned_int; - #[link_name = "llvm.s390.vmlof"] fn vmlof(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_long_long; - #[link_name = "llvm.s390.vmhb"] fn vmhb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_char; #[link_name = "llvm.s390.vmhh"] fn vmhh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_short; #[link_name = "llvm.s390.vmhf"] fn vmhf(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int; @@ -377,7 +369,7 @@ impl ShuffleMask { ShuffleMask(mask) } - const fn pack() -> Self { + const fn odd() -> Self { let mut mask = [0; N]; let mut i = 1; let mut index = 0; @@ -390,6 +382,10 @@ impl ShuffleMask { ShuffleMask(mask) } + const fn pack() -> Self { + Self::odd() + } + const fn unpack_low() -> Self { let mut mask = [0; N]; let mut i = 0; @@ -2647,36 +2643,36 @@ mod sealed { unsafe fn vec_mule(self, b: Self) -> Result; } - macro_rules! impl_vec_mule { - ($instr:ident $src:ident $shuffled:ident $dst:ident $width:literal) => { + macro_rules! impl_vec_mul_even_odd { + ($mask:ident $instr:ident $src:ident $shuffled:ident $dst:ident $width:literal) => { #[inline] #[target_feature(enable = "vector")] #[cfg_attr(test, assert_instr($instr))] unsafe fn $instr(a: $src, b: $src) -> $dst { - let even_a: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( - a, + let elems_a: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( a, - const { ShuffleMask::<$width>::even() }, + a, // this argument is ignored entirely. + const { ShuffleMask::<$width>::$mask() }, )); - let even_b: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( + let elems_b: $dst = simd_as(simd_shuffle::<_, _, $shuffled>( b, - b, - const { ShuffleMask::<$width>::even() }, + b, // this argument is ignored entirely. + const { ShuffleMask::<$width>::$mask() }, )); - simd_mul(even_a, even_b) + simd_mul(elems_a, elems_b) } }; } - impl_vec_mule! { vmeb vector_signed_char i8x8 vector_signed_short 8 } - impl_vec_mule! { vmeh vector_signed_short i16x4 vector_signed_int 4 } - impl_vec_mule! { vmef vector_signed_int i32x2 vector_signed_long_long 2 } + impl_vec_mul_even_odd! { even vmeb vector_signed_char i8x8 vector_signed_short 8 } + impl_vec_mul_even_odd! { even vmeh vector_signed_short i16x4 vector_signed_int 4 } + impl_vec_mul_even_odd! { even vmef vector_signed_int i32x2 vector_signed_long_long 2 } - impl_vec_mule! { vmleb vector_unsigned_char u8x8 vector_unsigned_short 8 } - impl_vec_mule! { vmleh vector_unsigned_short u16x4 vector_unsigned_int 4 } - impl_vec_mule! { vmlef vector_unsigned_int u32x2 vector_unsigned_long_long 2 } + impl_vec_mul_even_odd! { even vmleb vector_unsigned_char u8x8 vector_unsigned_short 8 } + impl_vec_mul_even_odd! { even vmleh vector_unsigned_short u16x4 vector_unsigned_int 4 } + impl_vec_mul_even_odd! { even vmlef vector_unsigned_int u32x2 vector_unsigned_long_long 2 } impl_mul!([VectorMule vec_mule] vmeb (vector_signed_char, vector_signed_char) -> vector_signed_short ); impl_mul!([VectorMule vec_mule] vmeh (vector_signed_short, vector_signed_short) -> vector_signed_int); @@ -2691,21 +2687,21 @@ mod sealed { unsafe fn vec_mulo(self, b: Self) -> Result; } - test_impl! { vec_vmob(a: vector_signed_char, b: vector_signed_char) -> vector_signed_short [ vmob, vmob ] } - test_impl! { vec_vmoh(a: vector_signed_short, b: vector_signed_short) -> vector_signed_int[ vmoh, vmoh ] } - test_impl! { vec_vmof(a: vector_signed_int, b: vector_signed_int) -> vector_signed_long_long [ vmof, vmof ] } + impl_vec_mul_even_odd! { odd vmob vector_signed_char i8x8 vector_signed_short 8 } + impl_vec_mul_even_odd! { odd vmoh vector_signed_short i16x4 vector_signed_int 4 } + impl_vec_mul_even_odd! { odd vmof vector_signed_int i32x2 vector_signed_long_long 2 } - test_impl! { vec_vmlob(a: vector_unsigned_char, b: vector_unsigned_char) -> vector_unsigned_short [ vmlob, vmlob ] } - test_impl! { vec_vmloh(a: vector_unsigned_short, b: vector_unsigned_short) -> vector_unsigned_int[ vmloh, vmloh ] } - test_impl! { vec_vmlof(a: vector_unsigned_int, b: vector_unsigned_int) -> vector_unsigned_long_long [ vmlof, vmlof ] } + impl_vec_mul_even_odd! { odd vmlob vector_unsigned_char u8x8 vector_unsigned_short 8 } + impl_vec_mul_even_odd! { odd vmloh vector_unsigned_short u16x4 vector_unsigned_int 4 } + impl_vec_mul_even_odd! { odd vmlof vector_unsigned_int u32x2 vector_unsigned_long_long 2 } - impl_mul!([VectorMulo vec_mulo] vec_vmob (vector_signed_char, vector_signed_char) -> vector_signed_short ); - impl_mul!([VectorMulo vec_mulo] vec_vmoh (vector_signed_short, vector_signed_short) -> vector_signed_int); - impl_mul!([VectorMulo vec_mulo] vec_vmof (vector_signed_int, vector_signed_int) -> vector_signed_long_long ); + impl_mul!([VectorMulo vec_mulo] vmob (vector_signed_char, vector_signed_char) -> vector_signed_short ); + impl_mul!([VectorMulo vec_mulo] vmoh (vector_signed_short, vector_signed_short) -> vector_signed_int); + impl_mul!([VectorMulo vec_mulo] vmof (vector_signed_int, vector_signed_int) -> vector_signed_long_long ); - impl_mul!([VectorMulo vec_mulo] vec_vmlob (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_short ); - impl_mul!([VectorMulo vec_mulo] vec_vmloh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_int); - impl_mul!([VectorMulo vec_mulo] vec_vmlof (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_long_long ); + impl_mul!([VectorMulo vec_mulo] vmlob (vector_unsigned_char, vector_unsigned_char) -> vector_unsigned_short ); + impl_mul!([VectorMulo vec_mulo] vmloh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_int); + impl_mul!([VectorMulo vec_mulo] vmlof (vector_unsigned_int, vector_unsigned_int) -> vector_unsigned_long_long ); #[unstable(feature = "stdarch_s390x", issue = "135681")] pub trait VectorMulh { From dfa95c6fa40374df410d3215d99d697c58f5da50 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 18:08:51 +0200 Subject: [PATCH 093/251] s390x: implement `vec_subc_u128` using `overflowing_sub` --- library/stdarch/crates/core_arch/src/s390x/vector.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 6775225788925..4e4161dbb7f7f 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -4678,11 +4678,9 @@ pub unsafe fn vec_subc_u128( a: vector_unsigned_char, b: vector_unsigned_char, ) -> vector_unsigned_char { - // FIXME(llvm) sadly this does not work https://github.com/llvm/llvm-project/issues/129608 - // let a: u128 = transmute(a); - // let b: u128 = transmute(b); - // transmute(!a.overflowing_sub(b).1 as u128) - transmute(vscbiq(transmute(a), transmute(b))) + let a: u128 = transmute(a); + let b: u128 = transmute(b); + transmute(!a.overflowing_sub(b).1 as u128) } /// Vector Add Compute Carryout unsigned 128-bits @@ -4714,7 +4712,7 @@ pub unsafe fn vec_adde_u128( let a: u128 = transmute(a); let b: u128 = transmute(b); let c: u128 = transmute(c); - // FIXME(llvm) sadly this does not work + // FIXME(llvm) https://github.com/llvm/llvm-project/pull/153557 // let (d, _carry) = a.carrying_add(b, c & 1 != 0); // transmute(d) transmute(vacq(a, b, c)) From e9162f221a154ff8dbf353275f3288f69c2c431f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 20:00:22 +0200 Subject: [PATCH 094/251] s390x: implement `vec_sld` using `fshl` --- .../crates/core_arch/src/s390x/vector.rs | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 4e4161dbb7f7f..9c2941129c869 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -94,8 +94,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.s390.vsrlb"] fn vsrlb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_char; #[link_name = "llvm.s390.vslb"] fn vslb(a: vector_signed_char, b: vector_signed_char) -> vector_signed_char; - #[link_name = "llvm.s390.vsldb"] fn vsldb(a: i8x16, b: i8x16, c: u32) -> i8x16; - #[link_name = "llvm.s390.vsld"] fn vsld(a: i8x16, b: i8x16, c: u32) -> i8x16; #[link_name = "llvm.s390.vsrd"] fn vsrd(a: i8x16, b: i8x16, c: u32) -> i8x16; #[link_name = "llvm.s390.verimb"] fn verimb(a: vector_signed_char, b: vector_signed_char, c: vector_signed_char, d: i32) -> vector_signed_char; @@ -3484,10 +3482,44 @@ mod sealed { unsafe fn vec_sldb(self, b: Self) -> Self; } - // FIXME(llvm) https://github.com/llvm/llvm-project/issues/129955 - // ideally we could implement this in terms of llvm.fshl.i128 - // #[link_name = "llvm.fshl.i128"] fn fshl_i128(a: u128, b: u128, c: u128) -> u128; - // transmute(fshl_i128(transmute(a), transmute(b), const { C * 8 } )) + #[inline] + #[target_feature(enable = "vector")] + #[cfg_attr(test, assert_instr(vsldb))] + unsafe fn test_vec_sld(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int { + a.vec_sld::<13>(b) + } + + #[inline] + #[target_feature(enable = "vector")] + #[cfg_attr(test, assert_instr(vsldb))] + unsafe fn test_vec_sldw(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int { + a.vec_sldw::<3>(b) + } + + #[inline] + #[target_feature(enable = "vector-enhancements-2")] + #[cfg_attr(test, assert_instr(vsld))] + unsafe fn test_vec_sldb(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int { + a.vec_sldb::<7>(b) + } + + #[inline] + #[target_feature(enable = "vector-enhancements-2")] + #[cfg_attr(test, assert_instr(vsrd))] + unsafe fn test_vec_srdb(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int { + a.vec_srdb::<7>(b) + } + + unsafe fn funnel_shl_u128(a: u128, b: u128, c: u128) -> u128 { + #[repr(simd)] + struct Single([u128; 1]); + + transmute(simd_funnel_shl::( + transmute(a), + transmute(b), + transmute(c), + )) + } macro_rules! impl_vec_sld { ($($ty:ident)*) => { @@ -3498,21 +3530,21 @@ mod sealed { #[target_feature(enable = "vector")] unsafe fn vec_sld(self, b: Self) -> Self { static_assert_uimm_bits!(C, 4); - transmute(vsldb(transmute(self), transmute(b), C)) + transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 * 8 })) } #[inline] #[target_feature(enable = "vector")] unsafe fn vec_sldw(self, b: Self) -> Self { static_assert_uimm_bits!(C, 2); - transmute(vsldb(transmute(self), transmute(b), const { 4 * C })) + transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 * 4 * 8 })) } #[inline] #[target_feature(enable = "vector-enhancements-2")] unsafe fn vec_sldb(self, b: Self) -> Self { static_assert_uimm_bits!(C, 3); - transmute(vsld(transmute(self), transmute(b), C)) + transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 })) } } @@ -3523,6 +3555,11 @@ mod sealed { unsafe fn vec_srdb(self, b: Self) -> Self { static_assert_uimm_bits!(C, 3); transmute(vsrd(transmute(self), transmute(b), C)) + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/129955#issuecomment-3207488190 + // LLVM currently rewrites `fshr` to `fshl`, and the logic in the s390x + // backend cannot deal with that yet. + // #[link_name = "llvm.fshr.i128"] fn fshr_i128(a: u128, b: u128, c: u128) -> u128; + // transmute(fshr_i128(transmute(self), transmute(b), const { C as u128 })) } } )* From 45af206618d516571e6f526e4600ebaca92de6c0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 20 Aug 2025 21:12:52 +0200 Subject: [PATCH 095/251] s390x: link to a missed optimization --- library/stdarch/crates/core_arch/src/s390x/vector.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index 9c2941129c869..f6d14c45e0d2b 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -2352,6 +2352,9 @@ mod sealed { unsafe fn vec_packs(self, b: Other) -> Self::Result; } + // FIXME(llvm): https://github.com/llvm/llvm-project/issues/153655 + // Other targets can use a min/max for the saturation + a truncation. + impl_vec_trait! { [VectorPacks vec_packs] vpksh (vector_signed_short, vector_signed_short) -> vector_signed_char } impl_vec_trait! { [VectorPacks vec_packs] vpklsh (vector_unsigned_short, vector_unsigned_short) -> vector_unsigned_char } impl_vec_trait! { [VectorPacks vec_packs] vpksf (vector_signed_int, vector_signed_int) -> vector_signed_short } From 4a9b73bc98417d2335b7d3d86edf301bdd7be230 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 21 Aug 2025 07:14:55 +0300 Subject: [PATCH 096/251] Attach the DB in symbol queries --- .../crates/ide-db/src/symbol_index.rs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 78ade30c7e3ed..76b647f8e9f2d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -133,23 +133,27 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabase { fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Arc { let _p = tracing::info_span!("library_symbols").entered(); - let mut symbol_collector = SymbolCollector::new(db); - - db.source_root_crates(source_root_id) - .iter() - .flat_map(|&krate| Crate::from(krate).modules(db)) - // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing, - // as the index for a library is not going to really ever change, and we do not want to store each - // the module or crate indices for those in salsa unless we need to. - .for_each(|module| symbol_collector.collect(module)); - - Arc::new(SymbolIndex::new(symbol_collector.finish())) + // We call this without attaching because this runs in parallel, so we need to attach here. + salsa::attach(db, || { + let mut symbol_collector = SymbolCollector::new(db); + + db.source_root_crates(source_root_id) + .iter() + .flat_map(|&krate| Crate::from(krate).modules(db)) + // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing, + // as the index for a library is not going to really ever change, and we do not want to store each + // the module or crate indices for those in salsa unless we need to. + .for_each(|module| symbol_collector.collect(module)); + + Arc::new(SymbolIndex::new(symbol_collector.finish())) + }) } fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc { let _p = tracing::info_span!("module_symbols").entered(); - Arc::new(SymbolIndex::new(SymbolCollector::new_module(db, module))) + // We call this without attaching because this runs in parallel, so we need to attach here. + salsa::attach(db, || Arc::new(SymbolIndex::new(SymbolCollector::new_module(db, module)))) } pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc]> { From 73d1aa9e8248d22cc6425714b9f3f44d34257e7a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 21 Aug 2025 08:06:43 +0300 Subject: [PATCH 097/251] Attach the DB when mapping the result of `world_symbols()` We call `try_to_nav()` there. --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 874e04702e241..4b93535c89438 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -481,12 +481,15 @@ impl Analysis { // `world_symbols` currently clones the database to run stuff in parallel, which will make any query panic // if we were to attach it here. Cancelled::catch(|| { - symbol_index::world_symbols(&self.db, query) - .into_iter() - .filter_map(|s| s.try_to_nav(&self.db)) - .take(limit) - .map(UpmappingResult::call_site) - .collect::>() + let symbols = symbol_index::world_symbols(&self.db, query); + salsa::attach(&self.db, || { + symbols + .into_iter() + .filter_map(|s| s.try_to_nav(&self.db)) + .take(limit) + .map(UpmappingResult::call_site) + .collect::>() + }) }) } From 98bd1d744562947b54174668423bee572ed5b7ee Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 2 Jun 2025 00:02:35 +0200 Subject: [PATCH 098/251] use `simd_saturating_{add, sub}` on neon --- .../src/arm_shared/neon/generated.rs | 320 ++---------------- .../spec/neon/arm_shared.spec.yml | 44 +-- 2 files changed, 48 insertions(+), 316 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index fd150bcaf2b7f..22d31d4e25682 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -36978,15 +36978,7 @@ pub fn vqabsq_s32(a: int32x4_t) -> int32x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v8i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v8i8")] - fn _vqadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } - unsafe { _vqadd_s8(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s8)"] @@ -37007,15 +36999,7 @@ pub fn vqadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v16i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v16i8")] - fn _vqaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } - unsafe { _vqaddq_s8(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s16)"] @@ -37036,15 +37020,7 @@ pub fn vqaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v4i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v4i16")] - fn _vqadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } - unsafe { _vqadd_s16(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s16)"] @@ -37065,15 +37041,7 @@ pub fn vqadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v8i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v8i16")] - fn _vqaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } - unsafe { _vqaddq_s16(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s32)"] @@ -37094,15 +37062,7 @@ pub fn vqaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v2i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v2i32")] - fn _vqadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } - unsafe { _vqadd_s32(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s32)"] @@ -37123,15 +37083,7 @@ pub fn vqadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v4i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v4i32")] - fn _vqaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } - unsafe { _vqaddq_s32(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_s64)"] @@ -37152,15 +37104,7 @@ pub fn vqaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v1i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v1i64")] - fn _vqadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t; - } - unsafe { _vqadd_s64(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_s64)"] @@ -37181,15 +37125,7 @@ pub fn vqadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqadd.v2i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.sadd.sat.v2i64")] - fn _vqaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t; - } - unsafe { _vqaddq_s64(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u8)"] @@ -37210,15 +37146,7 @@ pub fn vqaddq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v8i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v8i8")] - fn _vqadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; - } - unsafe { _vqadd_u8(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u8)"] @@ -37239,15 +37167,7 @@ pub fn vqadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v16i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v16i8")] - fn _vqaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; - } - unsafe { _vqaddq_u8(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u16)"] @@ -37268,15 +37188,7 @@ pub fn vqaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v4i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v4i16")] - fn _vqadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; - } - unsafe { _vqadd_u16(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u16)"] @@ -37297,15 +37209,7 @@ pub fn vqadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v8i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v8i16")] - fn _vqaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; - } - unsafe { _vqaddq_u16(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u32)"] @@ -37326,15 +37230,7 @@ pub fn vqaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v2i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v2i32")] - fn _vqadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; - } - unsafe { _vqadd_u32(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u32)"] @@ -37355,15 +37251,7 @@ pub fn vqadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v4i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v4i32")] - fn _vqaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; - } - unsafe { _vqaddq_u32(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqadd_u64)"] @@ -37384,15 +37272,7 @@ pub fn vqaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v1i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v1i64")] - fn _vqadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t; - } - unsafe { _vqadd_u64(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Saturating add"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqaddq_u64)"] @@ -37413,15 +37293,7 @@ pub fn vqadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqadd.v2i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.uadd.sat.v2i64")] - fn _vqaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t; - } - unsafe { _vqaddq_u64(a, b) } + unsafe { simd_saturating_add(a, b) } } #[doc = "Vector widening saturating doubling multiply accumulate with scalar"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqdmlal_lane_s16)"] @@ -41259,15 +41131,7 @@ pub fn vqshrun_n_s64(a: int64x2_t) -> uint32x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v8i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v8i8")] - fn _vqsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t; - } - unsafe { _vqsub_s8(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s8)"] @@ -41288,15 +41152,7 @@ pub fn vqsub_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v16i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v16i8")] - fn _vqsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t; - } - unsafe { _vqsubq_s8(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s16)"] @@ -41317,15 +41173,7 @@ pub fn vqsubq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v4i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v4i16")] - fn _vqsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t; - } - unsafe { _vqsub_s16(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s16)"] @@ -41346,15 +41194,7 @@ pub fn vqsub_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v8i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v8i16")] - fn _vqsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t; - } - unsafe { _vqsubq_s16(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s32)"] @@ -41375,15 +41215,7 @@ pub fn vqsubq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v2i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v2i32")] - fn _vqsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t; - } - unsafe { _vqsub_s32(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s32)"] @@ -41404,15 +41236,7 @@ pub fn vqsub_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v4i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v4i32")] - fn _vqsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t; - } - unsafe { _vqsubq_s32(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_s64)"] @@ -41433,15 +41257,7 @@ pub fn vqsubq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v1i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v1i64")] - fn _vqsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t; - } - unsafe { _vqsub_s64(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_s64)"] @@ -41462,15 +41278,7 @@ pub fn vqsub_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.sqsub.v2i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.ssub.sat.v2i64")] - fn _vqsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t; - } - unsafe { _vqsubq_s64(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u8)"] @@ -41491,15 +41299,7 @@ pub fn vqsubq_s64(a: int64x2_t, b: int64x2_t) -> int64x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v8i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v8i8")] - fn _vqsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t; - } - unsafe { _vqsub_u8(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u8)"] @@ -41520,15 +41320,7 @@ pub fn vqsub_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v16i8" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v16i8")] - fn _vqsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; - } - unsafe { _vqsubq_u8(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u16)"] @@ -41549,15 +41341,7 @@ pub fn vqsubq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v4i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v4i16")] - fn _vqsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t; - } - unsafe { _vqsub_u16(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u16)"] @@ -41578,15 +41362,7 @@ pub fn vqsub_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v8i16" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v8i16")] - fn _vqsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t; - } - unsafe { _vqsubq_u16(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u32)"] @@ -41607,15 +41383,7 @@ pub fn vqsubq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v2i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v2i32")] - fn _vqsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t; - } - unsafe { _vqsub_u32(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u32)"] @@ -41636,15 +41404,7 @@ pub fn vqsub_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v4i32" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v4i32")] - fn _vqsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t; - } - unsafe { _vqsubq_u32(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsub_u64)"] @@ -41665,15 +41425,7 @@ pub fn vqsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v1i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v1i64")] - fn _vqsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t; - } - unsafe { _vqsub_u64(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Saturating subtract"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqsubq_u64)"] @@ -41694,15 +41446,7 @@ pub fn vqsub_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vqsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { - unsafe extern "unadjusted" { - #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), - link_name = "llvm.aarch64.neon.uqsub.v2i64" - )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.usub.sat.v2i64")] - fn _vqsubq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t; - } - unsafe { _vqsubq_u64(a, b) } + unsafe { simd_saturating_sub(a, b) } } #[doc = "Rounding Add returning High Narrow (high half)."] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vraddhn_high_s16)"] diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml index f16a257399bc8..1543ab1f866e8 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml @@ -2290,13 +2290,10 @@ intrinsics: - [uint64x1_t, u64, i64] - [uint64x2_t, u64, i64] compose: - - LLVMLink: - name: "uqsub.{neon_type[0]}" - links: - - link: "llvm.aarch64.neon.uqsub.v{neon_type[0].lane}{type[2]}" - arch: aarch64,arm64ec - - link: "llvm.usub.sat.v{neon_type[0].lane}{type[2]}" - arch: arm + - FnCall: + - simd_saturating_sub + - - a + - b - name: "vqsub{neon_type[0].no}" doc: Saturating subtract @@ -2319,13 +2316,10 @@ intrinsics: - [int64x1_t, s64, i64] - [int64x2_t, s64, i64] compose: - - LLVMLink: - name: "sqsub.{neon_type[0]}" - links: - - link: "llvm.aarch64.neon.sqsub.v{neon_type[0].lane}{type[2]}" - arch: aarch64,arm64ec - - link: "llvm.ssub.sat.v{neon_type[0].lane}{type[2]}" - arch: arm + - FnCall: + - simd_saturating_sub + - - a + - b - name: "vhadd{neon_type.no}" doc: Halving add @@ -2541,13 +2535,10 @@ intrinsics: - uint64x1_t - uint64x2_t compose: - - LLVMLink: - name: "uqadd.{neon_type}" - links: - - link: "llvm.aarch64.neon.uqadd.{neon_type}" - arch: aarch64,arm64ec - - link: "llvm.uadd.sat.{neon_type}" - arch: arm + - FnCall: + - simd_saturating_add + - - a + - b - name: "vqadd{neon_type.no}" doc: Saturating add @@ -2570,13 +2561,10 @@ intrinsics: - int64x1_t - int64x2_t compose: - - LLVMLink: - name: "sqadd.{neon_type}" - links: - - link: "llvm.aarch64.neon.sqadd.{neon_type}" - arch: aarch64,arm64ec - - link: "llvm.sadd.sat.{neon_type}" - arch: arm + - FnCall: + - simd_saturating_add + - - a + - b - name: "vld1{neon_type[1].no}" doc: "Load multiple single-element structures to one, two, three, or four registers" From b5e3230f8f8f66de3f5db05a28ac496fa4a05ad4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 21 Aug 2025 22:40:58 +0300 Subject: [PATCH 099/251] Remove unnecessary `salsa::attach()` calls --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 4b93535c89438..cddf5f04f2442 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -461,9 +461,7 @@ impl Analysis { hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe, ) -> Cancellable> { self.with_db(|db| { - salsa::attach(db, || { - inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher) - }) + inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher) }) } @@ -533,9 +531,7 @@ impl Analysis { let search_scope = AssertUnwindSafe(search_scope); self.with_db(|db| { let _ = &search_scope; - salsa::attach(db, || { - references::find_all_refs(&Semantics::new(db), position, search_scope.0) - }) + references::find_all_refs(&Semantics::new(db), position, search_scope.0) }) } @@ -545,7 +541,7 @@ impl Analysis { config: &HoverConfig, range: FileRange, ) -> Cancellable>> { - self.with_db(|db| salsa::attach(db, || hover::hover(db, range, config))) + self.with_db(|db| hover::hover(db, range, config)) } /// Returns moniker of symbol at position. @@ -553,7 +549,7 @@ impl Analysis { &self, position: FilePosition, ) -> Cancellable>>> { - self.with_db(|db| salsa::attach(db, || moniker::moniker(db, position))) + self.with_db(|db| moniker::moniker(db, position)) } /// Returns URL(s) for the documentation of the symbol under the cursor. @@ -581,7 +577,7 @@ impl Analysis { &self, position: FilePosition, ) -> Cancellable>>> { - self.with_db(|db| salsa::attach(db, || call_hierarchy::call_hierarchy(db, position))) + self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) } /// Computes incoming calls for the given file position. @@ -649,7 +645,7 @@ impl Analysis { /// Returns the set of possible targets to run for the current file. pub fn runnables(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| salsa::attach(db, || runnables::runnables(db, file_id))) + self.with_db(|db| runnables::runnables(db, file_id)) } /// Returns the set of tests for the given file position. @@ -672,9 +668,7 @@ impl Analysis { position: FilePosition, ) -> Cancellable>> { self.with_db(|db| { - salsa::attach(db, || { - highlight_related::highlight_related(&Semantics::new(db), config, position) - }) + highlight_related::highlight_related(&Semantics::new(db), config, position) }) } From 99576aa3f7f6148480608fb62fa10a38cd64f1fd Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 22 Aug 2025 05:24:33 +0900 Subject: [PATCH 100/251] fix: Infinite recursion while lowering assoc type bounds from supertraits --- .../crates/hir-ty/src/lower_nextsolver.rs | 6 ++- .../crates/hir-ty/src/tests/regression.rs | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index ce953fdcb8298..d87181f545d88 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1756,7 +1756,11 @@ fn named_associated_type_shorthand_candidates<'db, R>( db, GenericDefId::TraitId(trait_def_id), PredicateFilter::SelfTrait, - |pred| pred == GenericDefId::TraitId(trait_def_id), + // We are likely in the midst of lowering generic predicates of `def`. + // So, if we allow `pred == def` we might fall into an infinite recursion. + // Actually, we have already checked for the case `pred == def` above as we started + // with a stack including `trait_id` + |pred| pred != def && pred == GenericDefId::TraitId(trait_def_id), ) .0 .deref() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index fd8c641d86eb0..966433369aa88 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2439,3 +2439,56 @@ pub fn null_mut() -> *mut T { "#, ); } + +#[test] +fn issue_20484() { + check_no_mismatches( + r#" +struct Eth; + +trait FullBlockBody { + type Transaction; +} + +impl FullBlockBody for () { + type Transaction = (); +} + +trait NodePrimitives { + type BlockBody; + type SignedTx; +} + +impl NodePrimitives for () { + type BlockBody = (); + type SignedTx = (); +} + +impl NodePrimitives for Eth { + type BlockBody = (); + type SignedTx = (); +} + +trait FullNodePrimitives +where + Self: NodePrimitives>, +{ +} + +impl FullNodePrimitives for T where + T: NodePrimitives>, +{ +} + +fn node(_: N) +where + N: FullNodePrimitives, +{ +} + +fn main() { + node(Eth); +} +"#, + ); +} From b20ddc2d3f029bdbade7d86cdcf021a7cb8c3d8b Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 22 Aug 2025 11:38:19 +0800 Subject: [PATCH 101/251] Fix indent for move_guard_to_arm_body Input: ```rust fn main() { match 92 { x $0if true && true && true => { { false } }, _ => true } } ``` Old output: ```rust fn main() { match 92 { x => if true && true && true { { { false } } }, _ => true }; } ``` This PR fixed: ```rust fn main() { match 92 { x => if true && true && true { { { false } } }, _ => true } } ``` --- .../ide-assists/src/handlers/move_guard.rs | 70 +++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index 644d1f6cafefc..6b50718424c72 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -40,28 +40,34 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } let space_before_guard = guard.syntax().prev_sibling_or_token(); + let space_after_arrow = match_arm.fat_arrow_token()?.next_sibling_or_token(); - let guard_condition = guard.condition()?; + let guard_condition = guard.condition()?.reset_indent(); let arm_expr = match_arm.expr()?; - let if_expr = - make::expr_if(guard_condition, make::block_expr(None, Some(arm_expr.clone())), None) - .indent(arm_expr.indent_level()); + let then_branch = make::block_expr(None, Some(arm_expr.reset_indent().indent(1.into()))); + let if_expr = make::expr_if(guard_condition, then_branch, None).indent(arm_expr.indent_level()); let target = guard.syntax().text_range(); acc.add( AssistId::refactor_rewrite("move_guard_to_arm_body"), "Move guard to arm body", target, - |edit| { - match space_before_guard { - Some(element) if element.kind() == WHITESPACE => { - edit.delete(element.text_range()); - } - _ => (), - }; + |builder| { + let mut edit = builder.make_editor(match_arm.syntax()); + if let Some(element) = space_before_guard + && element.kind() == WHITESPACE + { + edit.delete(element); + } + if let Some(element) = space_after_arrow + && element.kind() == WHITESPACE + { + edit.replace(element, make::tokens::single_space()); + } - edit.delete(guard.syntax().text_range()); - edit.replace_ast(arm_expr, if_expr.into()); + edit.delete(guard.syntax()); + edit.replace(arm_expr.syntax(), if_expr.syntax()); + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } @@ -298,6 +304,44 @@ fn main() { ); } + #[test] + fn move_multiline_guard_to_arm_body_works() { + check_assist( + move_guard_to_arm_body, + r#" +fn main() { + match 92 { + x $0if true + && true + && true => + { + { + false + } + }, + _ => true + } +} +"#, + r#" +fn main() { + match 92 { + x => if true + && true + && true { + { + { + false + } + } + }, + _ => true + } +} +"#, + ); + } + #[test] fn move_guard_to_arm_body_works_complex_match() { check_assist( From cf478a02c74aac664cc2e2cfa7ce91e50be1d3a4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 22 Aug 2025 08:58:48 +0200 Subject: [PATCH 102/251] Fix panic in syntax_highlighting --- .../crates/ide/src/syntax_highlighting.rs | 4 +- .../ide/src/syntax_highlighting/inject.rs | 52 ++++++++++--------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index e3dc3ed3c742a..f98770805a451 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -452,10 +452,10 @@ fn traverse( } hl } - NodeOrToken::Token(token) => { + NodeOrToken::Token(token) => salsa::attach(sema.db, || { highlight::token(sema, token, edition, &is_unsafe_node, tt_level > 0) .zip(Some(None)) - } + }), }; if let Some((mut highlight, binding_hash)) = element { if is_unlinked && highlight.tag == HlTag::UnresolvedReference { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index fb33307249a77..7785891169c64 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -5,7 +5,7 @@ use std::mem; use either::Either; use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym}; use ide_db::{ - SymbolKind, active_parameter::ActiveParameter, defs::Definition, + SymbolKind, active_parameter::ActiveParameter, base_db::salsa, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence, }; use syntax::{ @@ -126,32 +126,34 @@ pub(super) fn doc_comment( // Extract intra-doc links and emit highlights for them. if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) { - extract_definitions_from_docs(&docs) - .into_iter() - .filter_map(|(range, link, ns)| { - doc_mapping - .map(range) - .filter(|(mapping, _)| mapping.file_id == src_file_id) - .and_then(|(InFile { value: mapped_range, .. }, attr_id)| { - Some(mapped_range).zip(resolve_doc_path_for_def( - sema.db, - def, - &link, - ns, - attr_id.is_inner_attr(), - )) + salsa::attach(sema.db, || { + extract_definitions_from_docs(&docs) + .into_iter() + .filter_map(|(range, link, ns)| { + doc_mapping + .map(range) + .filter(|(mapping, _)| mapping.file_id == src_file_id) + .and_then(|(InFile { value: mapped_range, .. }, attr_id)| { + Some(mapped_range).zip(resolve_doc_path_for_def( + sema.db, + def, + &link, + ns, + attr_id.is_inner_attr(), + )) + }) + }) + .for_each(|(range, def)| { + hl.add(HlRange { + range, + highlight: module_def_to_hl_tag(def) + | HlMod::Documentation + | HlMod::Injected + | HlMod::IntraDocLink, + binding_hash: None, }) - }) - .for_each(|(range, def)| { - hl.add(HlRange { - range, - highlight: module_def_to_hl_tag(def) - | HlMod::Documentation - | HlMod::Injected - | HlMod::IntraDocLink, - binding_hash: None, }) - }); + }); } // Extract doc-test sources from the docs and calculate highlighting for them. From 3868f8ad5c2ef77fa823dc17da14ba13c2d508f7 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 22 Aug 2025 17:06:21 +0800 Subject: [PATCH 103/251] fix: convert_integer_literal not on selected `convert_integer_literal` can only convert the first literal, it is not reasonable to apply it when selected Example --- ```rust fn main() { $01+1$0; } ``` **Assist old outputs**: ``` Convert 1 to 0b1 Convert 1 to 0o1 Convert 1 to 0x1 Replace arithmetic with call to checked_* Replace arithmetic with call to saturating_* Replace arithmetic with call to wrapping_* Extract into variable Extract into constant Extract into static Extract into function ``` **Assist this PR outputs**: ``` Replace arithmetic with call to checked_* Replace arithmetic with call to saturating_* Replace arithmetic with call to wrapping_* Extract into variable Extract into constant Extract into static Extract into function ``` --- .../ide-assists/src/handlers/convert_integer_literal.rs | 8 ++++++++ src/tools/rust-analyzer/crates/ide-assists/src/tests.rs | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs index 846f4e9b258ae..bc76ade97f69d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_integer_literal.rs @@ -14,6 +14,9 @@ use crate::{AssistContext, AssistId, Assists, GroupLabel}; // const _: i32 = 0b1010; // ``` pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + if !ctx.has_empty_selection() { + return None; + } let literal = ctx.find_node_at_offset::()?; let literal = match literal.kind() { ast::LiteralKind::IntNumber(it) => it, @@ -265,4 +268,9 @@ mod tests { 111111111111111111111111111111111111111111111111111111111111111111111111$0;"; check_assist_not_applicable(convert_integer_literal, before); } + + #[test] + fn convert_non_empty_selection_literal() { + check_assist_not_applicable(convert_integer_literal, "const _: i32 = $00b1010$0;"); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index f4daabfe915d7..44bf6a4316942 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -456,7 +456,6 @@ pub fn test_some_range(a: int) -> bool { let expected = labels(&assists); expect![[r#" - Convert integer base Extract into... Replace if let with match "#]] @@ -489,7 +488,6 @@ pub fn test_some_range(a: int) -> bool { let expected = labels(&assists); expect![[r#" - Convert integer base Extract into... Replace if let with match "#]] From c9fbcdcfcdc5290639c2a76929bec1ed07c08f8e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 22 Aug 2025 21:58:49 +0800 Subject: [PATCH 104/251] Add let in let-chain completion support Example --- ```rust fn f() { if true && $0 {} } ``` -> ```rust fn f() { if true && let $1 = $0 {} } ``` --- .../crates/ide-completion/src/context/analysis.rs | 10 +++++++--- .../crates/ide-completion/src/tests/expression.rs | 10 ++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 6eb1727b3319e..7d6fa553001cd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1171,19 +1171,23 @@ fn classify_name_ref<'db>( Some(res) }; - let is_in_condition = |it: &ast::Expr| { + fn is_in_condition(it: &ast::Expr) -> bool { (|| { let parent = it.syntax().parent()?; if let Some(expr) = ast::WhileExpr::cast(parent.clone()) { Some(expr.condition()? == *it) - } else if let Some(expr) = ast::IfExpr::cast(parent) { + } else if let Some(expr) = ast::IfExpr::cast(parent.clone()) { Some(expr.condition()? == *it) + } else if let Some(expr) = ast::BinExpr::cast(parent) + && expr.op_token()?.kind() == T![&&] + { + Some(is_in_condition(&expr.into())) } else { None } })() .unwrap_or(false) - }; + } let make_path_kind_expr = |expr: ast::Expr| { let it = expr.syntax(); 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 33f729f016645..07eaeea97e553 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 @@ -2275,3 +2275,13 @@ fn foo() { "#]], ); } + +#[test] +fn let_in_condition() { + check_edit("let", r#"fn f() { if $0 {} }"#, r#"fn f() { if let $1 = $0 {} }"#); +} + +#[test] +fn let_in_let_chain() { + check_edit("let", r#"fn f() { if true && $0 {} }"#, r#"fn f() { if true && let $1 = $0 {} }"#); +} From 183fbdc89b5f7f3944644a5d3d1c762d7ea35f90 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 23 Aug 2025 15:52:54 +0800 Subject: [PATCH 105/251] Fix `else` completion in `let _ = if x {} $0` --- .../ide-completion/src/context/analysis.rs | 11 +- .../ide-completion/src/tests/expression.rs | 347 ++++++++++++++++++ 2 files changed, 355 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 6eb1727b3319e..fc2d9e41989b8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -943,9 +943,14 @@ fn classify_name_ref<'db>( }; let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; - ast::ExprStmt::cast(prev_sibling.clone()) - .and_then(|it| it.expr()) - .or_else(|| ast::Expr::cast(prev_sibling)) + match_ast! { + match prev_sibling { + ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()), + ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()), + ast::Expr(expr) => Some(expr), + _ => None, + } + } })(); matches!(prev_expr, Some(ast::Expr::IfExpr(_))) }; 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 33f729f016645..da5dddc6e8d7d 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 @@ -1210,6 +1210,353 @@ fn foo() { if foo {} el$0 { let x = 92; } } sn ppd "#]], ); + check( + r#" +fn foo() { let x = if foo {} $0 } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} el$0 } +"#, + expect![[r#" + fn foo() fn() + lc x () + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 let y = 92; } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} el$0 let y = 92; } +"#, + expect![[r#" + fn foo() fn() + lc x () + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0; } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} el$0; } +"#, + expect![[r#" + fn foo() fn() + lc x () + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0; let y = 92; } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 else {}; } +"#, + expect![[r#" + fn foo fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); } #[test] From 4715c6d41a949358e8dd8dd96de0650939c8bf6b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 24 Aug 2025 02:26:37 +0300 Subject: [PATCH 106/251] Add an option to remove reborrows from adjustment inlay hints Reborrows are consecutive deref then ref. Make it the default because reborrows are mostly useless to the programmer. Also rename `rust-analyzer.inlayHints.expressionAdjustmentHints.enable: "reborrow"` to `rust-analyzer.inlayHints.expressionAdjustmentHints.enable: "borrows"`, as it's not about reborrows but about any ref/deref and it's confusing with the new setting. --- .../crates/ide/src/inlay_hints.rs | 4 +- .../crates/ide/src/inlay_hints/adjustment.rs | 49 ++++++++++++++++++- .../crates/ide/src/static_index.rs | 1 + .../rust-analyzer/src/cli/analysis_stats.rs | 1 + .../crates/rust-analyzer/src/config.rs | 17 +++++-- .../docs/book/src/configuration_generated.md | 11 +++++ .../rust-analyzer/editors/code/package.json | 10 ++++ 7 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index d7d3171664945..cc44ae8fc8b9e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -306,6 +306,7 @@ pub struct InlayHintsConfig { pub generic_parameter_hints: GenericParameterHints, pub chaining_hints: bool, pub adjustment_hints: AdjustmentHints, + pub adjustment_hints_disable_reborrows: bool, pub adjustment_hints_mode: AdjustmentHintsMode, pub adjustment_hints_hide_outside_unsafe: bool, pub closure_return_type_hints: ClosureReturnTypeHints, @@ -430,7 +431,7 @@ pub enum LifetimeElisionHints { #[derive(Clone, Debug, PartialEq, Eq)] pub enum AdjustmentHints { Always, - ReborrowOnly, + BorrowsOnly, Never, } @@ -886,6 +887,7 @@ mod tests { closure_return_type_hints: ClosureReturnTypeHints::Never, closure_capture_hints: false, adjustment_hints: AdjustmentHints::Never, + adjustment_hints_disable_reborrows: false, adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index e39a5f8889a2c..0fd587a728408 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -47,7 +47,22 @@ pub(super) fn hints( let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let desc_expr = descended.as_ref().unwrap_or(expr); - let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; + let mut adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; + + if config.adjustment_hints_disable_reborrows { + // Remove consecutive deref-ref, i.e. reborrows. + let mut i = 0; + while i < adjustments.len().saturating_sub(1) { + let [current, next, ..] = &adjustments[i..] else { unreachable!() }; + if matches!(current.kind, Adjust::Deref(None)) + && matches!(next.kind, Adjust::Borrow(AutoBorrow::Ref(_))) + { + adjustments.splice(i..i + 2, []); + } else { + i += 1; + } + } + } if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr { // Don't show unnecessary reborrows for these, they will just repeat the inner ones again @@ -716,6 +731,38 @@ fn hello(it: &&[impl T]) { //^^(&** //^^) } +"#, + ); + } + + #[test] + fn disable_reborrows() { + check_with_config( + InlayHintsConfig { + adjustment_hints: AdjustmentHints::Always, + adjustment_hints_disable_reborrows: true, + ..DISABLED_CONFIG + }, + r#" +#![rustc_coherence_is_core] + +trait ToOwned { + type Owned; + fn to_owned(&self) -> Self::Owned; +} + +struct String; +impl ToOwned for str { + type Owned = String; + fn to_owned(&self) -> Self::Owned { String } +} + +fn a(s: &String) {} + +fn main() { + let s = "".to_owned(); + a(&s) +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 14b6529c61f8c..8c3275df1baab 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -169,6 +169,7 @@ impl StaticIndex<'_> { closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, lifetime_elision_hints: crate::LifetimeElisionHints::Never, adjustment_hints: crate::AdjustmentHints::Never, + adjustment_hints_disable_reborrows: true, adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, implicit_drop_hints: false, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 6c0aa19f57482..b17186f8d7b1e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -1137,6 +1137,7 @@ impl flags::AnalysisStats { }, chaining_hints: true, adjustment_hints: ide::AdjustmentHints::Always, + adjustment_hints_disable_reborrows: true, adjustment_hints_mode: ide::AdjustmentHintsMode::Postfix, adjustment_hints_hide_outside_unsafe: false, closure_return_type_hints: ide::ClosureReturnTypeHints::Always, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index d4cd56dc55bf6..c2252185a3aa3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -226,6 +226,14 @@ config_data! { inlayHints_discriminantHints_enable: DiscriminantHintsDef = DiscriminantHintsDef::Never, + /// Disable reborrows in expression adjustments inlay hints. + /// + /// Reborrows are a pair of a builtin deref then borrow, i.e. `&*`. They are inserted by the compiler but are mostly useless to the programmer. + /// + /// Note: if the deref is not builtin (an overloaded deref), or the borrow is `&raw const`/`&raw mut`, they are not removed. + inlayHints_expressionAdjustmentHints_disableReborrows: bool = + true, + /// Show inlay hints for type adjustments. inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = AdjustmentHintsDef::Never, @@ -1888,12 +1896,14 @@ impl Config { AdjustmentHintsDef::Always => ide::AdjustmentHints::Always, AdjustmentHintsDef::Never => match self.inlayHints_reborrowHints_enable() { ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => { - ide::AdjustmentHints::ReborrowOnly + ide::AdjustmentHints::BorrowsOnly } ReborrowHintsDef::Never => ide::AdjustmentHints::Never, }, - AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly, + AdjustmentHintsDef::Borrows => ide::AdjustmentHints::BorrowsOnly, }, + adjustment_hints_disable_reborrows: *self + .inlayHints_expressionAdjustmentHints_disableReborrows(), adjustment_hints_mode: match self.inlayHints_expressionAdjustmentHints_mode() { AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix, AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix, @@ -2822,7 +2832,8 @@ enum ReborrowHintsDef { #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum AdjustmentHintsDef { - Reborrow, + #[serde(alias = "Reborrow")] + Borrows, #[serde(with = "true_or_always")] #[serde(untagged)] Always, diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 6ee956fe0dbf4..9a51212462db5 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -959,6 +959,17 @@ Default: `"never"` Show enum variant discriminant hints. +## rust-analyzer.inlayHints.expressionAdjustmentHints.disableReborrows {#inlayHints.expressionAdjustmentHints.disableReborrows} + +Default: `true` + +Disable reborrows in expression adjustments inlay hints. + +Reborrows are a pair of a builtin deref then borrow, i.e. `&*`. They are inserted by the compiler but are mostly useless to the programmer. + +Note: if the deref is not builtin (an overloaded deref), or the borrow is `&raw const`/`&raw mut`, they are not removed. + + ## rust-analyzer.inlayHints.expressionAdjustmentHints.enable {#inlayHints.expressionAdjustmentHints.enable} Default: `"never"` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 4975ca858671b..2b2e25e11c88a 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2209,6 +2209,16 @@ } } }, + { + "title": "Inlay Hints", + "properties": { + "rust-analyzer.inlayHints.expressionAdjustmentHints.disableReborrows": { + "markdownDescription": "Disable reborrows in expression adjustments inlay hints.\n\nReborrows are a pair of a builtin deref then borrow, i.e. `&*`. They are inserted by the compiler but are mostly useless to the programmer.\n\nNote: if the deref is not builtin (an overloaded deref), or the borrow is `&raw const`/`&raw mut`, they are not removed.", + "default": true, + "type": "boolean" + } + } + }, { "title": "Inlay Hints", "properties": { From 5e81912dae790647395834a027263a8c6160fd0b Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 22 Aug 2025 17:31:55 +0800 Subject: [PATCH 107/251] replace_arith_op not applicable on selected --- .../src/handlers/replace_arith_op.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs index 6b385a03625b7..440ab4d4604f2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs @@ -102,6 +102,9 @@ fn is_primitive_int(ctx: &AssistContext<'_>, expr: &ast::Expr) -> bool { /// Extract the operands of an arithmetic expression (e.g. `1 + 2` or `1.checked_add(2)`) fn parse_binary_op(ctx: &AssistContext<'_>) -> Option<(ast::Expr, ArithOp, ast::Expr)> { + if !ctx.has_empty_selection() { + return None; + } let expr = ctx.find_node_at_offset::()?; let op = match expr.op_kind() { @@ -163,7 +166,7 @@ impl ArithKind { #[cfg(test)] mod tests { - use crate::tests::check_assist; + use crate::tests::{check_assist, check_assist_not_applicable}; use super::*; @@ -220,6 +223,18 @@ fn main() { fn main() { let x = 1.wrapping_add(2); } +"#, + ) + } + + #[test] + fn replace_arith_not_applicable_with_non_empty_selection() { + check_assist_not_applicable( + replace_arith_with_checked, + r#" +fn main() { + let x = 1 $0+$0 2; +} "#, ) } From c92af4d23285428c92e67fedb6d73a9a86a90cff Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 22 Aug 2025 14:21:52 +0800 Subject: [PATCH 108/251] Add ReturnExpr completion suggest --- .../ide-completion/src/context/analysis.rs | 21 +++++++++-- .../ide-completion/src/context/tests.rs | 36 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 6eb1727b3319e..19f3d157beb7c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -559,7 +559,7 @@ fn expected_type_and_name<'db>( token: &SyntaxToken, name_like: &ast::NameLike, ) -> (Option>, Option) { - let token = prev_assign_token_at_trivia(token.clone()); + let token = prev_special_biased_token_at_trivia(token.clone()); let mut node = match token.parent() { Some(it) => it, None => return (None, None), @@ -724,6 +724,18 @@ fn expected_type_and_name<'db>( let def = sema.to_def(&it); (def.map(|def| def.ret_type(sema.db)), None) }, + ast::ReturnExpr(it) => { + let fn_ = sema.ancestors_with_macros(it.syntax().clone()) + .find_map(Either::::cast); + let ty = fn_.and_then(|f| match f { + Either::Left(f) => Some(sema.to_def(&f)?.ret_type(sema.db)), + Either::Right(f) => { + let ty = sema.type_of_expr(&f.into())?.original.as_callable(sema.db)?; + Some(ty.return_type()) + }, + }); + (ty, None) + }, ast::ClosureExpr(it) => { let ty = sema.type_of_expr(&it.into()); ty.and_then(|ty| ty.original.as_callable(sema.db)) @@ -1868,7 +1880,7 @@ fn next_non_trivia_sibling(ele: SyntaxElement) -> Option { None } -fn prev_assign_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { +fn prev_special_biased_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { while token.kind().is_trivia() && let Some(prev) = token.prev_token() && let T![=] @@ -1881,7 +1893,10 @@ fn prev_assign_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { | T![-=] | T![|=] | T![&=] - | T![^=] = prev.kind() + | T![^=] + | T![return] + | T![break] + | T![continue] = prev.kind() { token = prev } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 7a8c70f190efc..9b1e086b666bc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -484,3 +484,39 @@ fn foo() { expect![[r#"ty: State, name: ?"#]], ); } + +#[test] +fn expected_type_return_expr() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() -> State { + let _: i32 = if true { + 8 + } else { + return $0; + }; +} +"#, + expect![[r#"ty: State, name: ?"#]], + ); +} + +#[test] +fn expected_type_return_expr_in_closure() { + check_expected_type_and_name( + r#" +enum State { Stop } +fn foo() { + let _f: fn() -> State = || { + let _: i32 = if true { + 8 + } else { + return $0; + }; + }; +} +"#, + expect![[r#"ty: State, name: ?"#]], + ); +} From 31245cabecfc21c837745ec6253d63d5fc9ac75f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 24 Aug 2025 08:49:40 +0300 Subject: [PATCH 109/251] Fix opaque generics The parent generics were incorrectly not considered for TAIT. I'm not convinced we should follow rustc here, also there are items (opaques) with more than 1 parent (opaque -> fn/type alias -> impl/trait) and I'm not sure we properly account for that in all places, but for now I left it as-is. Also fix a bug where lifetimes' indices were incorrect when there is a self param (they started from 0 instead of 1). --- .../crates/hir-ty/src/next_solver/generics.rs | 68 +++++++------------ .../crates/hir-ty/src/next_solver/util.rs | 1 - .../crates/hir-ty/src/tests/regression.rs | 2 + .../hir-ty/src/tests/regression/new_solver.rs | 26 +++++++ 4 files changed, 54 insertions(+), 43 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index 48f5e73f2562d..a3ba8eb83453e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -12,7 +12,7 @@ use hir_def::{ }, }; use hir_expand::name::Name; -use intern::Symbol; +use intern::{Symbol, sym}; use la_arena::Arena; use rustc_type_ir::inherent::Ty as _; use triomphe::Arc; @@ -24,18 +24,13 @@ use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, Solver use super::{DbInterner, GenericArg}; pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { - let mk_lt = |(index, (_, lt)): (usize, (_, &LifetimeParamData))| { + let mk_lt = |index, lt: &LifetimeParamData| { let name = lt.name.symbol().clone(); - let index = index as u32; let kind = GenericParamDefKind::Lifetime; GenericParamDef { name, index, kind } }; - let mk_ty = |len_lt, (index, p): (usize, &TypeOrConstParamData)| { - let name = p - .name() - .map(|n| n.symbol().clone()) - .unwrap_or_else(|| Name::missing().symbol().clone()); - let index = (len_lt + index) as u32; + let mk_ty = |index, p: &TypeOrConstParamData| { + let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME); let kind = match p { TypeOrConstParamData::TypeParamData(_) => GenericParamDefKind::Type, TypeOrConstParamData::ConstParamData(_) => GenericParamDefKind::Const, @@ -43,33 +38,25 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { GenericParamDef { name, index, kind } }; let own_params_for_generic_params = |params: &GenericParams| { - if params.trait_self_param().is_some() { - let len_lt = params.len_lifetimes() + 1; - params - .iter_type_or_consts() - .take(1) - .enumerate() - .map(|t| mk_ty(0, (t.0, t.1.1))) - .chain(params.iter_lt().enumerate().map(mk_lt)) - .chain( - params - .iter_type_or_consts() - .skip(1) - .enumerate() - .map(|t| mk_ty(len_lt, (t.0, t.1.1))), - ) - .collect() - } else { - let len_lt = params.len_lifetimes(); - params - .iter_lt() - .enumerate() - .map(mk_lt) - .chain( - params.iter_type_or_consts().enumerate().map(|t| mk_ty(len_lt, (t.0, t.1.1))), - ) - .collect() + let mut result = Vec::with_capacity(params.len()); + let mut type_and_consts = params.iter_type_or_consts(); + let mut index = 0; + if let Some(self_param) = params.trait_self_param() { + result.push(mk_ty(0, ¶ms[self_param])); + type_and_consts.next(); + index += 1; } + result.extend(params.iter_lt().map(|(_, data)| { + let lt = mk_lt(index, data); + index += 1; + lt + })); + result.extend(type_and_consts.map(|(_, data)| { + let ty = mk_ty(index, data); + index += 1; + ty + })); + result }; let (parent, own_params) = match (def.try_into(), def) { @@ -82,12 +69,9 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { // The opaque type itself does not have generics - only the parent function (Some(GenericDefId::FunctionId(function_id)), vec![]) } - crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => ( - None, - own_params_for_generic_params( - &db.generic_params(GenericDefId::TypeAliasId(type_alias_id)), - ), - ), + crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => { + (Some(type_alias_id.into()), Vec::new()) + } crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { let param = TypeOrConstParamData::TypeParamData(TypeParamData { name: None, @@ -95,7 +79,7 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { provenance: TypeParamProvenance::TypeParamList, }); // Yes, there is a parent but we don't include it in the generics - (None, vec![mk_ty(0, (0, ¶m))]) + (None, vec![mk_ty(0, ¶m)]) } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index cedc203f7f5aa..1db02e9eb611c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -685,7 +685,6 @@ pub fn explicit_item_bounds<'db>( LifetimeElisionKind::AnonymousReportError, ); - let trait_args = GenericArgs::identity_for_item(interner, trait_.into()); let item_args = GenericArgs::identity_for_item(interner, def_id); let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 966433369aa88..6a3f2286215f4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1,3 +1,5 @@ +mod new_solver; + use expect_test::expect; use super::{check_infer, check_no_mismatches, check_types}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs new file mode 100644 index 0000000000000..059f4ad32a53b --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -0,0 +1,26 @@ +use expect_test::expect; + +use super::check_infer; + +#[test] +fn opaque_generics() { + check_infer( + r#" +//- minicore: iterator +pub struct Grid {} + +impl<'a> IntoIterator for &'a Grid { + type Item = &'a (); + + type IntoIter = impl Iterator; + + fn into_iter(self) -> Self::IntoIter { + } +} + "#, + expect![[r#" + 150..154 'self': &'a Grid + 174..181 '{ }': impl Iterator + "#]], + ); +} From 5ddf6846d5659ed28e1ea25e273e4c84082cf730 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 24 Aug 2025 23:17:23 +0900 Subject: [PATCH 110/251] fix: Masquerade as nightly cargo when invoking flycheck with `-Zscript` --- src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 233bedec6900a..01ac75c09aee6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -588,6 +588,7 @@ impl FlycheckActor { cmd.arg("--manifest-path"); cmd.arg(manifest_path); if manifest_path.extension() == Some("rs") { + cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly"); cmd.arg("-Zscript"); } } From ca42d0775a33ae6f977e4cd42fab17f9aced6a59 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Sun, 24 Aug 2025 08:03:02 -0700 Subject: [PATCH 111/251] Fix rust-analyzer-contributors reference Signed-off-by: Emmanuel Ferdman --- src/tools/rust-analyzer/docs/book/src/contributing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/README.md b/src/tools/rust-analyzer/docs/book/src/contributing/README.md index 57c7a9c5996d1..ad2816b18ac14 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/README.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/README.md @@ -276,7 +276,7 @@ There are two sets of people with extra permissions: Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention. Don't feel pressured to review assigned PRs though. If you don't feel like reviewing for whatever reason, someone else will pick the review up (but please speak up if you don't feel like it)! -* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors]([https://github.com/orgs/rust-analyzer/teams/triage](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml)). +* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml). This team has general triaging permissions allowing to label, close and re-open issues. ## Synchronizing subtree changes From 56bc9c35b9f625154f42f53f4b1e7843f02533ad Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 25 Aug 2025 16:44:42 +0800 Subject: [PATCH 112/251] Fix ExprStmt delete semicolon for toggle_macro_delimiter --- .../src/handlers/toggle_macro_delimiter.rs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs index 504e12f93df61..bf1546986ed27 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -1,6 +1,6 @@ use ide_db::assists::AssistId; use syntax::{ - AstNode, T, + AstNode, SyntaxToken, T, ast::{self, syntax_factory::SyntaxFactory}, }; @@ -39,7 +39,7 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) let makro = ctx.find_node_at_offset::()?; let cursor_offset = ctx.offset(); - let semicolon = makro.semicolon_token(); + let semicolon = macro_semicolon(&makro); let token_tree = makro.token_tree()?; let ltoken = token_tree.left_delimiter_token()?; @@ -95,6 +95,14 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) ) } +fn macro_semicolon(makro: &ast::MacroCall) -> Option { + makro.semicolon_token().or_else(|| { + let macro_expr = ast::MacroExpr::cast(makro.syntax().parent()?)?; + let expr_stmt = ast::ExprStmt::cast(macro_expr.syntax().parent()?)?; + expr_stmt.semicolon_token() + }) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -119,7 +127,29 @@ macro_rules! sth { sth!{ } "#, - ) + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} + +fn foo() { + sth!$0( ); +} + "#, + r#" +macro_rules! sth { + () => {}; +} + +fn foo() { + sth!{ } +} + "#, + ); } #[test] From a0aa1c1360916590f9a10d1b3d8586771c839d38 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 24 Aug 2025 16:44:28 +0300 Subject: [PATCH 113/251] Cache trait solving across queries in the same revision Caching trait solving can do a lot to speed. Unfortunately it also consume a huge amount of memory. Therefore, as part of the migration to the new solver Jack Huey disabled caching of trait solving (he made the query transparent). The PR proposes a middle ground: do cache trait solving, but only for the same revision. This allows us to be safe because during a revision the inputs cannot change. The result is hopefully much better performance to features that tend to do a bulk of trait solving, and also repeat the same query (e.g. inference then IDE features). There is another limitation: results are only cached in the same thread, to remove the need for synchronization which will be expensive. More measurements are required to check whether it's better to use a synchronized global cache, or maybe stay with a thread-local cache but batch multiple feature requests (highlighting, inlay hints etc.) of the same file to the same thread. Alongside the actual cache we store the revision, because we need to verify it (we can't eagerly clear caches when incrementing the revision), and also the address of the db to prevent multiple dbs from interleaving (this is mostly relevant in tests, although injected highlighting also uses a new db, therefore maybe it's better to move it to a separate thread). This "games" analysis-stats to both be way faster and use way more memory; the former is because analysis-stats doesn't increment revisions, therefore all queries share the cache and hit ratio is way too good, the latter is because analysis-stats doesn't increment revisions and therefore the cache isn't cleared. Both are not representative of a typical IDE scenario. --- .../rust-analyzer/crates/base-db/src/lib.rs | 28 ++++++- .../crates/hir-def/src/test_db.rs | 21 ++++- .../rust-analyzer/crates/hir-ty/src/infer.rs | 82 +++++++++---------- .../crates/hir-ty/src/mir/lower.rs | 4 +- .../crates/hir-ty/src/next_solver/interner.rs | 39 +++++---- .../crates/hir-ty/src/test_db.rs | 23 +++++- .../rust-analyzer/crates/ide-db/src/lib.rs | 9 +- 7 files changed, 140 insertions(+), 66 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index dbf949c470c4d..14544acc11bdf 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -7,7 +7,12 @@ pub use salsa_macros; mod change; mod input; -use std::{cell::RefCell, hash::BuildHasherDefault, panic, sync::Once}; +use std::{ + cell::RefCell, + hash::BuildHasherDefault, + panic, + sync::{Once, atomic::AtomicUsize}, +}; pub use crate::{ change::FileChange, @@ -328,6 +333,27 @@ pub trait SourceDatabase: salsa::Database { #[doc(hidden)] fn crates_map(&self) -> Arc; + + fn nonce_and_revision(&self) -> (Nonce, salsa::Revision); +} + +static NEXT_NONCE: AtomicUsize = AtomicUsize::new(0); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Nonce(usize); + +impl Default for Nonce { + #[inline] + fn default() -> Self { + Nonce::new() + } +} + +impl Nonce { + #[inline] + pub fn new() -> Nonce { + Nonce(NEXT_NONCE.fetch_add(1, std::sync::atomic::Ordering::SeqCst)) + } } /// Crate related data shared by the whole workspace. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index e30a5b65a1f79..1e2f354f975cb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -3,7 +3,7 @@ use std::{fmt, panic, sync::Mutex}; use base_db::{ - Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb, + Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, }; use hir_expand::{InFile, files::FilePosition}; @@ -20,12 +20,12 @@ use crate::{ }; #[salsa_macros::db] -#[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, crates_map: Arc, events: Arc>>>, + nonce: Nonce, } impl Default for TestDB { @@ -44,6 +44,7 @@ impl Default for TestDB { events, files: Default::default(), crates_map: Default::default(), + nonce: Nonce::new(), }; this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); // This needs to be here otherwise `CrateGraphBuilder` panics. @@ -53,6 +54,18 @@ impl Default for TestDB { } } +impl Clone for TestDB { + fn clone(&self) -> Self { + Self { + storage: self.storage.clone(), + files: self.files.clone(), + crates_map: self.crates_map.clone(), + events: self.events.clone(), + nonce: Nonce::new(), + } + } +} + #[salsa_macros::db] impl salsa::Database for TestDB {} @@ -117,6 +130,10 @@ impl SourceDatabase for TestDB { fn crates_map(&self) -> Arc { self.crates_map.clone() } + + fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) { + (self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision()) + } } impl TestDB { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index d778cc0e30ed4..71b33a0e9035f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -88,54 +88,52 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - crate::next_solver::with_new_cache(|| { - let _p = tracing::info_span!("infer_query").entered(); - let resolver = def.resolver(db); - let body = db.body(def); - let mut ctx = InferenceContext::new(db, def, &body, resolver); - - match def { - DefWithBodyId::FunctionId(f) => { - ctx.collect_fn(f); - } - DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), - DefWithBodyId::VariantId(v) => { - ctx.return_ty = TyBuilder::builtin( - match db.enum_signature(v.lookup(db).parent).variant_body_type() { - hir_def::layout::IntegerType::Pointer(signed) => match signed { - true => BuiltinType::Int(BuiltinInt::Isize), - false => BuiltinType::Uint(BuiltinUint::Usize), - }, - hir_def::layout::IntegerType::Fixed(size, signed) => match signed { - true => BuiltinType::Int(match size { - Integer::I8 => BuiltinInt::I8, - Integer::I16 => BuiltinInt::I16, - Integer::I32 => BuiltinInt::I32, - Integer::I64 => BuiltinInt::I64, - Integer::I128 => BuiltinInt::I128, - }), - false => BuiltinType::Uint(match size { - Integer::I8 => BuiltinUint::U8, - Integer::I16 => BuiltinUint::U16, - Integer::I32 => BuiltinUint::U32, - Integer::I64 => BuiltinUint::U64, - Integer::I128 => BuiltinUint::U128, - }), - }, + let _p = tracing::info_span!("infer_query").entered(); + let resolver = def.resolver(db); + let body = db.body(def); + let mut ctx = InferenceContext::new(db, def, &body, resolver); + + match def { + DefWithBodyId::FunctionId(f) => { + ctx.collect_fn(f); + } + DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), + DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), + DefWithBodyId::VariantId(v) => { + ctx.return_ty = TyBuilder::builtin( + match db.enum_signature(v.lookup(db).parent).variant_body_type() { + hir_def::layout::IntegerType::Pointer(signed) => match signed { + true => BuiltinType::Int(BuiltinInt::Isize), + false => BuiltinType::Uint(BuiltinUint::Usize), }, - ); - } + hir_def::layout::IntegerType::Fixed(size, signed) => match signed { + true => BuiltinType::Int(match size { + Integer::I8 => BuiltinInt::I8, + Integer::I16 => BuiltinInt::I16, + Integer::I32 => BuiltinInt::I32, + Integer::I64 => BuiltinInt::I64, + Integer::I128 => BuiltinInt::I128, + }), + false => BuiltinType::Uint(match size { + Integer::I8 => BuiltinUint::U8, + Integer::I16 => BuiltinUint::U16, + Integer::I32 => BuiltinUint::U32, + Integer::I64 => BuiltinUint::U64, + Integer::I128 => BuiltinUint::U128, + }), + }, + }, + ); } + } - ctx.infer_body(); + ctx.infer_body(); - ctx.infer_mut_body(); + ctx.infer_mut_body(); - ctx.infer_closures(); + ctx.infer_closures(); - Arc::new(ctx.resolve_all()) - }) + Arc::new(ctx.resolve_all()) } pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 052be11e433f3..8c03ca939e370 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -2168,9 +2168,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result, } -pub(crate) use tls_cache::with_new_cache; mod tls_cache { use crate::db::HirDatabase; use super::DbInterner; + use base_db::Nonce; use rustc_type_ir::search_graph::GlobalCache; + use salsa::Revision; use std::cell::RefCell; - scoped_tls::scoped_thread_local!(static GLOBAL_CACHE: RefCell>>); + struct Cache { + cache: GlobalCache>, + revision: Revision, + db_nonce: Nonce, + } - pub(crate) fn with_new_cache(f: impl FnOnce() -> T) -> T { - GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), f) + thread_local! { + static GLOBAL_CACHE: RefCell> = const { RefCell::new(None) }; } pub(super) fn with_cache<'db, T>( - _db: &'db dyn HirDatabase, + db: &'db dyn HirDatabase, f: impl FnOnce(&mut GlobalCache>) -> T, ) -> T { - // SAFETY: No idea - let call = move |slot: &RefCell<_>| { + GLOBAL_CACHE.with_borrow_mut(|handle| { + let (db_nonce, revision) = db.nonce_and_revision(); + let handle = match handle { + Some(handle) => { + if handle.revision != revision || db_nonce != handle.db_nonce { + *handle = Cache { cache: GlobalCache::default(), revision, db_nonce }; + } + handle + } + None => handle.insert(Cache { cache: GlobalCache::default(), revision, db_nonce }), + }; + + // SAFETY: No idea f(unsafe { std::mem::transmute::< &mut GlobalCache>, &mut GlobalCache>, - >(&mut *slot.borrow_mut()) + >(&mut handle.cache) }) - }; - if GLOBAL_CACHE.is_set() { - GLOBAL_CACHE.with(call) - } else { - GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), || GLOBAL_CACHE.with(call)) - } + }) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 775136dc0cbf7..2a92aa52e0cd2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -3,8 +3,8 @@ use std::{fmt, panic, sync::Mutex}; use base_db::{ - CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb, SourceDatabase, - SourceRoot, SourceRootId, SourceRootInput, + CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Nonce, RootQueryDb, + SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, }; use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map}; @@ -17,12 +17,12 @@ use test_utils::extract_annotations; use triomphe::Arc; #[salsa_macros::db] -#[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, crates_map: Arc, events: Arc>>>, + nonce: Nonce, } impl Default for TestDB { @@ -41,6 +41,7 @@ impl Default for TestDB { events, files: Default::default(), crates_map: Default::default(), + nonce: Nonce::new(), }; this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH); // This needs to be here otherwise `CrateGraphBuilder` panics. @@ -50,6 +51,18 @@ impl Default for TestDB { } } +impl Clone for TestDB { + fn clone(&self) -> Self { + Self { + storage: self.storage.clone(), + files: self.files.clone(), + crates_map: self.crates_map.clone(), + events: self.events.clone(), + nonce: Nonce::new(), + } + } +} + impl fmt::Debug for TestDB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TestDB").finish() @@ -109,6 +122,10 @@ impl SourceDatabase for TestDB { fn crates_map(&self) -> Arc { self.crates_map.clone() } + + fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) { + (self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision()) + } } #[salsa_macros::db] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 9d2474d91da67..44bccd86d8709 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -51,7 +51,7 @@ use salsa::Durability; use std::{fmt, mem::ManuallyDrop}; use base_db::{ - CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, RootQueryDb, + CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, Nonce, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, query_group, }; use hir::{ @@ -83,6 +83,7 @@ pub struct RootDatabase { storage: ManuallyDrop>, files: Arc, crates_map: Arc, + nonce: Nonce, } impl std::panic::RefUnwindSafe for RootDatabase {} @@ -102,6 +103,7 @@ impl Clone for RootDatabase { storage: self.storage.clone(), files: self.files.clone(), crates_map: self.crates_map.clone(), + nonce: Nonce::new(), } } } @@ -165,6 +167,10 @@ impl SourceDatabase for RootDatabase { fn crates_map(&self) -> Arc { self.crates_map.clone() } + + fn nonce_and_revision(&self) -> (Nonce, salsa::Revision) { + (self.nonce, salsa::plumbing::ZalsaDatabase::zalsa(self).current_revision()) + } } impl Default for RootDatabase { @@ -179,6 +185,7 @@ impl RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()), files: Default::default(), crates_map: Default::default(), + nonce: Nonce::new(), }; // This needs to be here otherwise `CrateGraphBuilder` will panic. db.set_all_crates(Arc::new(Box::new([]))); From aa49c0b8bb27700ab77fd8cb7231d18f4f6d2e97 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 25 Aug 2025 20:19:33 +0300 Subject: [PATCH 114/251] Normalize all types when finishing inference The new solver does not eagerly normalize, but things after inference expect types to be normalized. rustc does the same. Also, I'm afraid other things in r-a don't expect results of the solver to be unnormalized. We'll need to handle that. --- .../crates/hir-ty/src/infer/unify.rs | 3 +++ .../hir-ty/src/tests/regression/new_solver.rs | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index a709aebfa9c1b..bb4782bd41942 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -621,6 +621,9 @@ impl<'a> InferenceTable<'a> { where T: HasInterner + TypeFoldable, { + let t = self.resolve_with_fallback(t, &|_, _, d, _| d); + let t = self.normalize_associated_types_in(t); + // Resolve again, because maybe normalization inserted infer vars. self.resolve_with_fallback(t, &|_, _, d, _| d) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 059f4ad32a53b..20190fbc04564 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -24,3 +24,29 @@ impl<'a> IntoIterator for &'a Grid { "#]], ); } + +#[test] +fn normalization() { + check_infer( + r#" +//- minicore: iterator, iterators +fn main() { + _ = [0i32].into_iter().filter_map(|_n| Some(1i32)); +} + "#, + expect![[r#" + 10..69 '{ ...2)); }': () + 16..17 '_': FilterMap, impl FnMut(i32) -> Option> + 16..66 '_ = [0...1i32))': () + 20..26 '[0i32]': [i32; 1] + 20..38 '[0i32]...iter()': IntoIter + 20..66 '[0i32]...1i32))': FilterMap, impl FnMut(i32) -> Option> + 21..25 '0i32': i32 + 50..65 '|_n| Some(1i32)': impl FnMut(i32) -> Option + 51..53 '_n': i32 + 55..59 'Some': fn Some(i32) -> Option + 55..65 'Some(1i32)': Option + 60..64 '1i32': i32 + "#]], + ); +} From 4b5bb18c57270a5b823235397067ae82c64bf1f1 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 25 Aug 2025 20:56:45 +0300 Subject: [PATCH 115/251] Don't map Chalk's `Normalize` to next solver's `NormalizesTo` `NormalizesTo` is a private predicate that should not be used outside the solver. For normalization, rustc uses `AliasRelate`, so replace with that. --- .../crates/hir-ty/src/next_solver/mapping.rs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index cad51fd85f55a..8f6296b145409 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -808,14 +808,24 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal unimplemented!(), }; let args: GenericArgs<'db> = proj_ty.substitution.to_nextsolver(interner); - let alias = rustc_type_ir::AliasTerm::new( + let alias = Ty::new( interner, - from_assoc_type_id(proj_ty.associated_ty_id).into(), - args, - ); + rustc_type_ir::TyKind::Alias( + rustc_type_ir::AliasTyKind::Projection, + rustc_type_ir::AliasTy::new( + interner, + from_assoc_type_id(proj_ty.associated_ty_id).into(), + args, + ), + ), + ) + .into(); let term = normalize.ty.to_nextsolver(interner).into(); - let normalizes_to = rustc_type_ir::NormalizesTo { alias, term }; - PredicateKind::NormalizesTo(normalizes_to) + PredicateKind::AliasRelate( + alias, + term, + rustc_type_ir::AliasRelationDirection::Equate, + ) } chalk_ir::DomainGoal::WellFormed(well_formed) => { let term = match well_formed { From 83f22cc0f87263c0aa3057d55b994d75c6151834 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 26 Aug 2025 19:33:46 +0300 Subject: [PATCH 116/251] Remove `SolverDefId::ForeignId` Replace it with normal `SolverDefId::TypeAliasId`. The split caused a very funny bug where code was getting `TypeAliasId` where it expected `ForeignId`, because `TypeAliasId` had a `From` impl from `hir_def::TypeAliasId` and `ForeignId` had not, plus a careless `into()`. I could've fixed this specific bug but opted to remove the split instead; currently, it just provides more room for bugs, as we don't have typed IDs for the solver anyway, and even when we'll have (hopefully), that doesn't seem like a very useful distinction, for example in hir-def foreign types are just `TypeAliasId` with some flags. Constructing a test for this isn't trivial; the trivial test (creating a foreign type, even proving a trait bound for it) fails to fail before the change, probably because we don't use the new solver everywhere yet so we don't trigger this specific code path. --- src/tools/rust-analyzer/crates/hir-ty/src/display.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/method_resolution.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs | 2 -- .../rust-analyzer/crates/hir-ty/src/next_solver/interner.rs | 1 - .../rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs | 4 ++-- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index ae0113fcbd7f0..0df727a8e5c04 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1473,7 +1473,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } TyKind::Foreign(type_alias) => { let alias = match type_alias { - SolverDefId::ForeignId(id) => id, + SolverDefId::TypeAliasId(id) => id, _ => unreachable!(), }; let type_alias = db.type_alias_signature(alias); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 49438151bbff5..8bd71df7c191d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -155,7 +155,7 @@ impl TyFingerprint { rustc_ast_ir::Mutability::Not => TyFingerprint::RawPtr(Mutability::Not), }, TyKind::Foreign(def) => { - let SolverDefId::ForeignId(def) = def else { unreachable!() }; + let SolverDefId::TypeAliasId(def) = def else { unreachable!() }; TyFingerprint::ForeignType(crate::to_foreign_def_id(def)) } TyKind::Dynamic(bounds, _, _) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index 64eab2d6b8185..c9632ddcd4bb5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -26,7 +26,6 @@ pub enum SolverDefId { StaticId(StaticId), TraitId(TraitId), TypeAliasId(TypeAliasId), - ForeignId(TypeAliasId), InternedClosureId(InternedClosureId), InternedCoroutineId(InternedCoroutineId), InternedOpaqueTyId(InternedOpaqueTyId), @@ -73,7 +72,6 @@ impl TryFrom for GenericDefId { SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id), SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id), SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id), - SolverDefId::ForeignId(_) => return Err(value), SolverDefId::InternedClosureId(_) => return Err(value), SolverDefId::InternedCoroutineId(_) => return Err(value), SolverDefId::InternedOpaqueTyId(_) => return Err(value), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 4fe0b54d68462..11c79ff742d6c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1148,7 +1148,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { let container = match def_id { SolverDefId::FunctionId(it) => it.lookup(self.db()).container, SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container, - SolverDefId::ForeignId(it) => it.lookup(self.db()).container, SolverDefId::ConstId(it) => it.lookup(self.db()).container, SolverDefId::InternedClosureId(it) => { return self diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 8f6296b145409..de2671e28fb5e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -271,7 +271,7 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { ) } chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign( - SolverDefId::ForeignId(crate::from_foreign_def_id(*foreign_def_id)), + SolverDefId::TypeAliasId(crate::from_foreign_def_id(*foreign_def_id)), ), chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed), chalk_ir::TyKind::Placeholder(placeholder_index) => { @@ -1262,7 +1262,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::TyKind::Foreign(foreign) => { let def_id = match foreign { - SolverDefId::ForeignId(id) => id, + SolverDefId::TypeAliasId(id) => id, _ => unreachable!(), }; TyKind::Foreign(to_foreign_def_id(def_id)) From 28a248f4f3a2252942b46bcd611cf4c207f10926 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 26 Aug 2025 21:46:04 +0300 Subject: [PATCH 117/251] In highlight_related, when on an unsafe block, don't highlight unsafe operations of other unsafe blocks --- .../hir-ty/src/diagnostics/unsafe_check.rs | 6 ++--- .../rust-analyzer/crates/hir/src/semantics.rs | 23 +++++++++++++++++-- .../crates/hir/src/source_analyzer.rs | 2 +- .../crates/ide/src/highlight_related.rs | 23 +++++++++++++++---- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 827585e50693a..d6d669258cc1f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -119,11 +119,11 @@ pub fn unsafe_operations( def: DefWithBodyId, body: &Body, current: ExprId, - callback: &mut dyn FnMut(InsideUnsafeBlock), + callback: &mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock), ) { let mut visitor_callback = |diag| { - if let UnsafeDiagnostic::UnsafeOperation { inside_unsafe_block, .. } = diag { - callback(inside_unsafe_block); + if let UnsafeDiagnostic::UnsafeOperation { inside_unsafe_block, node, .. } = diag { + callback(node, inside_unsafe_block); } }; let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback); diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 6d6e08100b044..3acbf81ada089 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -28,13 +28,13 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::AsName, }; -use hir_ty::diagnostics::unsafe_operations_for_body; +use hir_ty::diagnostics::{unsafe_operations, unsafe_operations_for_body}; use intern::{Interned, Symbol, sym}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{SmallVec, smallvec}; use span::{Edition, FileId, SyntaxContext}; -use stdx::TupleExt; +use stdx::{TupleExt, always}; use syntax::{ AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, @@ -1765,6 +1765,25 @@ impl<'db> SemanticsImpl<'db> { res } + pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec { + always!(block.unsafe_token().is_some()); + let block = self.wrap_node_infile(ast::Expr::from(block)); + let Some(def) = self.body_for(block.syntax()) else { return Vec::new() }; + let def = def.into(); + let (body, source_map) = self.db.body_with_source_map(def); + let infer = self.db.infer(def); + let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else { + return Vec::new(); + }; + let mut res = Vec::default(); + unsafe_operations(self.db, &infer, def, &body, block, &mut |node, _| { + if let Ok(node) = source_map.expr_or_pat_syntax(node) { + res.push(node); + } + }); + res + } + pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool { let Some(mac) = self.resolve_macro_call(macro_call) else { return false }; if mac.is_asm_like(self.db) { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index e3070c5f74ce2..dbc2539a9b91c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1283,7 +1283,7 @@ impl<'db> SourceAnalyzer<'db> { { let mut is_unsafe = false; let mut walk_expr = |expr_id| { - unsafe_operations(db, infer, def, body, expr_id, &mut |inside_unsafe_block| { + unsafe_operations(db, infer, def, body, expr_id, &mut |_, inside_unsafe_block| { is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No }) }; diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 9960e79a5380f..af1557f5a9a16 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -805,10 +805,8 @@ pub(crate) fn highlight_unsafe_points( push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); // highlight unsafe operations - if let Some(block) = block_expr - && let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) - { - let unsafe_ops = sema.get_unsafe_ops(body); + if let Some(block) = block_expr { + let unsafe_ops = sema.get_unsafe_ops_for_unsafe_block(block); for unsafe_op in unsafe_ops { push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range())); } @@ -2535,4 +2533,21 @@ fn foo() { "#, ); } + + #[test] + fn different_unsafe_block() { + check( + r#" +fn main() { + unsafe$0 { + // ^^^^^^ + *(0 as *const u8) + // ^^^^^^^^^^^^^^^^^ + }; + unsafe { *(1 as *const u8) }; + unsafe { *(2 as *const u8) }; +} + "#, + ); + } } From f31a378b0a5a612e0d2a91ab1a9ad237d442888c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Aug 2025 01:25:09 +0300 Subject: [PATCH 118/251] Attach the db in one more place in highlighting --- .../rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 7785891169c64..abe7be8c68881 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -26,7 +26,8 @@ pub(super) fn ra_fixture( literal: &ast::String, expanded: &ast::String, ) -> Option<()> { - let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?; + let active_parameter = + salsa::attach(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?; let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| { attrs.filter_map(|attr| attr.as_simple_path()).any(|path| { path.segments() From 0a5502208d7c7625f3a4806c422dfed47cc364ba Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Aug 2025 18:54:46 +0300 Subject: [PATCH 119/251] Add progress bars to more places in analysis-stats Namely, mir lowering, const eval and IDE things. --- .../rust-analyzer/src/cli/analysis_stats.rs | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index b17186f8d7b1e..d685f160ff098 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -333,7 +333,7 @@ impl flags::AnalysisStats { } if self.run_all_ide_things { - self.run_ide_things(host.analysis(), file_ids.clone()); + self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); } if self.run_term_search { @@ -393,15 +393,27 @@ impl flags::AnalysisStats { } fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { + let len = bodies + .iter() + .filter(|body| matches!(body, DefWithBody::Const(_) | DefWithBody::Static(_))) + .count(); + let mut bar = match verbosity { + Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), + _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), + _ => ProgressReport::new(len), + }; + let mut sw = self.stop_watch(); let mut all = 0; let mut fail = 0; for &b in bodies { + bar.set_message(move || format!("const eval: {}", full_name(db, b, b.module(db)))); let res = match b { DefWithBody::Const(c) => c.eval(db), DefWithBody::Static(s) => s.eval(db), _ => continue, }; + bar.inc(1); all += 1; let Err(error) = res else { continue; @@ -409,10 +421,11 @@ impl flags::AnalysisStats { if verbosity.is_spammy() { let full_name = full_name_of_item(db, b.module(db), b.name(db).unwrap_or(Name::missing())); - println!("Const eval for {full_name} failed due {error:?}"); + bar.println(format!("Const eval for {full_name} failed due {error:?}")); } fail += 1; } + bar.finish_and_clear(); let const_eval_time = sw.elapsed(); eprintln!("{:<20} {}", "Const evaluation:", const_eval_time); eprintln!("Failed const evals: {fail} ({}%)", percentage(fail, all)); @@ -662,6 +675,10 @@ impl flags::AnalysisStats { let mut all = 0; let mut fail = 0; for &body_id in bodies { + bar.set_message(move || { + format!("mir lowering: {}", full_name(db, body_id, body_id.module(db))) + }); + bar.inc(1); if matches!(body_id, DefWithBody::Variant(_)) { continue; } @@ -1089,12 +1106,29 @@ impl flags::AnalysisStats { report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } - fn run_ide_things(&self, analysis: Analysis, mut file_ids: Vec) { + fn run_ide_things( + &self, + analysis: Analysis, + mut file_ids: Vec, + db: &RootDatabase, + vfs: &Vfs, + verbosity: Verbosity, + ) { + let len = file_ids.len(); + let create_bar = || match verbosity { + Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), + _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), + _ => ProgressReport::new(len), + }; + file_ids.sort(); file_ids.dedup(); let mut sw = self.stop_watch(); + let mut bar = create_bar(); for &file_id in &file_ids { + let msg = format!("diagnostics: {}", vfs.file_path(file_id.file_id(db))); + bar.set_message(move || msg.clone()); _ = analysis.full_diagnostics( &DiagnosticsConfig { enabled: true, @@ -1121,8 +1155,14 @@ impl flags::AnalysisStats { ide::AssistResolveStrategy::All, analysis.editioned_file_id_to_vfs(file_id), ); + bar.inc(1); } + bar.finish_and_clear(); + + let mut bar = create_bar(); for &file_id in &file_ids { + let msg = format!("inlay hints: {}", vfs.file_path(file_id.file_id(db))); + bar.set_message(move || msg.clone()); _ = analysis.inlay_hints( &InlayHintsConfig { render_colons: false, @@ -1158,8 +1198,14 @@ impl flags::AnalysisStats { analysis.editioned_file_id_to_vfs(file_id), None, ); + bar.inc(1); } + bar.finish_and_clear(); + + let mut bar = create_bar(); for &file_id in &file_ids { + let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db))); + bar.set_message(move || msg.clone()); analysis .annotations( &AnnotationConfig { @@ -1178,7 +1224,10 @@ impl flags::AnalysisStats { .for_each(|annotation| { _ = analysis.resolve_annotation(annotation); }); + bar.inc(1); } + bar.finish_and_clear(); + let ide_time = sw.elapsed(); eprintln!("{:<20} {} ({} files)", "IDE:", ide_time, file_ids.len()); } From c36b75bdc8634f0d9cba824410df7a8c3785bda4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Aug 2025 19:24:46 +0300 Subject: [PATCH 120/251] Don't require a full `InferenceTable` for `CastTy` A DB is enough. --- .../crates/hir-ty/src/infer/cast.rs | 100 ++++++++---------- .../crates/hir-ty/src/mir/lower.rs | 11 +- 2 files changed, 52 insertions(+), 59 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 09b983a580d97..43364963eb054 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -6,7 +6,9 @@ use stdx::never; use crate::{ Adjustment, Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, - QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, from_chalk_trait_id, + QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, + db::HirDatabase, + from_chalk_trait_id, infer::{coerce::CoerceNever, unify::InferenceTable}, }; @@ -30,7 +32,7 @@ pub(crate) enum CastTy { } impl CastTy { - pub(crate) fn from_ty(table: &mut InferenceTable<'_>, t: &Ty) -> Option { + pub(crate) fn from_ty(db: &dyn HirDatabase, t: &Ty) -> Option { match t.kind(Interner) { TyKind::Scalar(Scalar::Bool) => Some(Self::Int(Int::Bool)), TyKind::Scalar(Scalar::Char) => Some(Self::Int(Int::Char)), @@ -43,8 +45,8 @@ impl CastTy { let (AdtId::EnumId(id), _) = t.as_adt()? else { return None; }; - let enum_data = id.enum_variants(table.db); - if enum_data.is_payload_free(table.db) { Some(Self::Int(Int::CEnum)) } else { None } + let enum_data = id.enum_variants(db); + if enum_data.is_payload_free(db) { Some(Self::Int(Int::CEnum)) } else { None } } TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)), TyKind::Function(_) => Some(Self::FnPtr), @@ -142,58 +144,50 @@ impl CastCheck { where F: FnMut(ExprId, Vec), { - let (t_from, t_cast) = - match (CastTy::from_ty(table, &self.expr_ty), CastTy::from_ty(table, &self.cast_ty)) { - (Some(t_from), Some(t_cast)) => (t_from, t_cast), - (None, Some(t_cast)) => match self.expr_ty.kind(Interner) { - TyKind::FnDef(..) => { - let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig"); - let sig = table.eagerly_normalize_and_resolve_shallow_in(sig); - let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner); - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes) - { - apply_adjustments(self.source_expr, adj); - } else { - return Err(CastError::IllegalCast); - } - - (CastTy::FnPtr, t_cast) + let (t_from, t_cast) = match ( + CastTy::from_ty(table.db, &self.expr_ty), + CastTy::from_ty(table.db, &self.cast_ty), + ) { + (Some(t_from), Some(t_cast)) => (t_from, t_cast), + (None, Some(t_cast)) => match self.expr_ty.kind(Interner) { + TyKind::FnDef(..) => { + let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig"); + let sig = table.eagerly_normalize_and_resolve_shallow_in(sig); + let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner); + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes) { + apply_adjustments(self.source_expr, adj); + } else { + return Err(CastError::IllegalCast); } - TyKind::Ref(mutbl, _, inner_ty) => { - return match t_cast { - CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) { - TyKind::Scalar( - Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_), - ) - | TyKind::InferenceVar( - _, - TyVariableKind::Integer | TyVariableKind::Float, - ) => Err(CastError::NeedDeref), - - _ => Err(CastError::NeedViaPtr), - }, - // array-ptr-cast - CastTy::Ptr(t, m) => { - let t = table.eagerly_normalize_and_resolve_shallow_in(t); - if !table.is_sized(&t) { - return Err(CastError::IllegalCast); - } - self.check_ref_cast( - table, - inner_ty, - *mutbl, - &t, - m, - apply_adjustments, - ) + + (CastTy::FnPtr, t_cast) + } + TyKind::Ref(mutbl, _, inner_ty) => { + return match t_cast { + CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) { + TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) + | TyKind::InferenceVar( + _, + TyVariableKind::Integer | TyVariableKind::Float, + ) => Err(CastError::NeedDeref), + + _ => Err(CastError::NeedViaPtr), + }, + // array-ptr-cast + CastTy::Ptr(t, m) => { + let t = table.eagerly_normalize_and_resolve_shallow_in(t); + if !table.is_sized(&t) { + return Err(CastError::IllegalCast); } - _ => Err(CastError::NonScalar), - }; - } - _ => return Err(CastError::NonScalar), - }, + self.check_ref_cast(table, inner_ty, *mutbl, &t, m, apply_adjustments) + } + _ => Err(CastError::NonScalar), + }; + } _ => return Err(CastError::NonScalar), - }; + }, + _ => return Err(CastError::NonScalar), + }; // rustc checks whether the `expr_ty` is foreign adt with `non_exhaustive` sym diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 8c03ca939e370..2d53d16c57a30 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -31,7 +31,7 @@ use crate::{ display::{DisplayTarget, HirDisplay, hir_display_with_store}, error_lifetime, generics::generics, - infer::{CaptureKind, CapturedItem, TypeMismatch, cast::CastTy, unify::InferenceTable}, + infer::{CaptureKind, CapturedItem, TypeMismatch, cast::CastTy}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, mapping::ToChalk, @@ -948,8 +948,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { - let mut table = InferenceTable::new(self.db, self.env.clone()); - cast_kind(&mut table, &source_ty, &target_ty)? + cast_kind(self.db, &source_ty, &target_ty)? }; Rvalue::Cast(cast_kind, it, target_ty) @@ -2017,9 +2016,9 @@ impl<'ctx> MirLowerCtx<'ctx> { } } -fn cast_kind(table: &mut InferenceTable<'_>, source_ty: &Ty, target_ty: &Ty) -> Result { - let from = CastTy::from_ty(table, source_ty); - let cast = CastTy::from_ty(table, target_ty); +fn cast_kind(db: &dyn HirDatabase, source_ty: &Ty, target_ty: &Ty) -> Result { + let from = CastTy::from_ty(db, source_ty); + let cast = CastTy::from_ty(db, target_ty); Ok(match (from, cast) { (Some(CastTy::Ptr(..) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress From dce4f301042c53f91d85befda03b0405d5922916 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Aug 2025 23:53:55 +0300 Subject: [PATCH 121/251] When mapping next-solver's `dyn` type, add `Self` (aka. bound var ^1.0) to auto traits' substitutions Chalk represents dyn types as a list of predicate, the self type should be there. The next solver represents them quite differently. The `Self` was forgotten for the auto trait case. --- .../crates/hir-ty/src/mir/lower.rs | 2 + .../crates/hir-ty/src/mir/lower/tests.rs | 64 +++++++++++++++++++ .../crates/hir-ty/src/next_solver/mapping.rs | 5 +- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 8c03ca939e370..7fbd496e51f25 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -53,6 +53,8 @@ use super::OperandKind; mod as_place; mod pattern_matching; +#[cfg(test)] +mod tests; #[derive(Debug, Clone)] struct LoopBlocks { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs new file mode 100644 index 0000000000000..1d7a16ed72d07 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs @@ -0,0 +1,64 @@ +use hir_def::db::DefDatabase; +use rustc_hash::FxHashMap; +use span::Edition; +use test_fixture::WithFixture; +use triomphe::Arc; + +use crate::{ + db::HirDatabase, + mir::{MirBody, MirLowerError}, + setup_tracing, + test_db::TestDB, +}; + +fn lower_mir( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> FxHashMap, MirLowerError>> { + let _tracing = setup_tracing(); + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + let file_id = *file_ids.last().unwrap(); + let module_id = db.module_for_file(file_id.file_id(&db)); + let def_map = module_id.def_map(&db); + let scope = &def_map[module_id.local_id].scope; + let funcs = scope.declarations().filter_map(|x| match x { + hir_def::ModuleDefId::FunctionId(it) => Some(it), + _ => None, + }); + funcs + .map(|func| { + let name = db.function_signature(func).name.display(&db, Edition::CURRENT).to_string(); + let mir = db.mir_body(func.into()); + (name, mir) + }) + .collect() +} + +#[test] +fn dyn_projection_with_auto_traits_regression_next_solver() { + lower_mir( + r#" +//- minicore: sized, send +pub trait Deserializer {} + +pub trait Strictest { + type Object: ?Sized; +} + +impl Strictest for dyn CustomValue { + type Object = dyn CustomValue + Send; +} + +pub trait CustomValue: Send {} + +impl CustomValue for () {} + +struct Box; + +type DeserializeFn = fn(&mut dyn Deserializer) -> Box; + +fn foo() { + (|deserializer| Box::new(())) as DeserializeFn<::Object>; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index de2671e28fb5e..203f030dfd614 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1207,7 +1207,10 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::TraitId(id) => to_chalk_trait_id(id), _ => unreachable!(), }; - let substitution = chalk_ir::Substitution::empty(Interner); + let substitution = chalk_ir::Substitution::from1( + Interner, + convert_ty_for_result(interner, self_ty), + ); let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; chalk_ir::WhereClause::Implemented(trait_ref) } From ae648be78350638873248b348f4fca3b9bc916e8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 29 Aug 2025 12:15:41 +0200 Subject: [PATCH 122/251] use `llvm.roundeven` on arm --- .../core_arch/src/arm_shared/neon/generated.rs | 12 ++++-------- .../stdarch-gen-arm/spec/neon/arm_shared.spec.yml | 8 ++------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index 22d31d4e25682..b5ba792b18aec 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -58256,10 +58256,9 @@ pub fn vrhaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { pub fn vrndn_f16(a: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), + any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"), link_name = "llvm.roundeven.v4f16" )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v4f16")] fn _vrndn_f16(a: float16x4_t) -> float16x4_t; } unsafe { _vrndn_f16(a) } @@ -58279,10 +58278,9 @@ pub fn vrndn_f16(a: float16x4_t) -> float16x4_t { pub fn vrndnq_f16(a: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), + any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"), link_name = "llvm.roundeven.v8f16" )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v8f16")] fn _vrndnq_f16(a: float16x8_t) -> float16x8_t; } unsafe { _vrndnq_f16(a) } @@ -58308,10 +58306,9 @@ pub fn vrndnq_f16(a: float16x8_t) -> float16x8_t { pub fn vrndn_f32(a: float32x2_t) -> float32x2_t { unsafe extern "unadjusted" { #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), + any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"), link_name = "llvm.roundeven.v2f32" )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v2f32")] fn _vrndn_f32(a: float32x2_t) -> float32x2_t; } unsafe { _vrndn_f32(a) } @@ -58337,10 +58334,9 @@ pub fn vrndn_f32(a: float32x2_t) -> float32x2_t { pub fn vrndnq_f32(a: float32x4_t) -> float32x4_t { unsafe extern "unadjusted" { #[cfg_attr( - any(target_arch = "aarch64", target_arch = "arm64ec"), + any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm"), link_name = "llvm.roundeven.v4f32" )] - #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrintn.v4f32")] fn _vrndnq_f32(a: float32x4_t) -> float32x4_t; } unsafe { _vrndnq_f32(a) } diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml index 1543ab1f866e8..43dd3b9031507 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml @@ -2486,9 +2486,7 @@ intrinsics: name: "llvm.frinn.{neon_type}" links: - link: "llvm.roundeven.{neon_type}" - arch: aarch64,arm64ec - - link: "llvm.arm.neon.vrintn.{neon_type}" - arch: arm + arch: aarch64,arm64ec,arm - name: "vrndn{neon_type.no}" doc: "Floating-point round to integral, to nearest with ties to even" @@ -2510,9 +2508,7 @@ intrinsics: name: "llvm.frinn.{neon_type}" links: - link: "llvm.roundeven.{neon_type}" - arch: aarch64,arm64ec - - link: "llvm.arm.neon.vrintn.{neon_type}" - arch: arm + arch: aarch64,arm64ec,arm - name: "vqadd{neon_type.no}" doc: Saturating add From 00b27f49eb8be37424fb5b21ce5aaac842a1d8b4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 29 Aug 2025 11:24:34 +0100 Subject: [PATCH 123/251] Remove FreeBSD CI It's historically been flaky and is no longer needed now that std_detect has been moved out of this repository. --- library/stdarch/.cirrus.yml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 library/stdarch/.cirrus.yml diff --git a/library/stdarch/.cirrus.yml b/library/stdarch/.cirrus.yml deleted file mode 100644 index a0ecc03b953fd..0000000000000 --- a/library/stdarch/.cirrus.yml +++ /dev/null @@ -1,16 +0,0 @@ -task: - name: x86_64-unknown-freebsd - freebsd_instance: - image_family: freebsd-13-4 - env: - # FIXME(freebsd): FreeBSD has a segfault when `RUST_BACKTRACE` is set - # https://github.com/rust-lang/rust/issues/132185 - RUST_BACKTRACE: "0" - setup_script: - - curl https://sh.rustup.rs -sSf --output rustup.sh - - sh rustup.sh --default-toolchain nightly -y - - . $HOME/.cargo/env - - rustup default nightly - test_script: - - . $HOME/.cargo/env - - cargo build --all From d396d2f79753b7db793a940d8da3ea74d82077d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 20:55:43 +0000 Subject: [PATCH 124/251] Bump tracing-subscriber from 0.3.19 to 0.3.20 Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.19 to 0.3.20. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.19...tracing-subscriber-0.3.20) --- updated-dependencies: - dependency-name: tracing-subscriber dependency-version: 0.3.20 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/Cargo.lock | 4 ++-- src/tools/rust-analyzer/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index f72e698f60631..b008aa1c50f88 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2738,9 +2738,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "sharded-slab", "thread_local", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index bb8444ed73422..05ee190480c97 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -163,7 +163,7 @@ temp-dir = "0.1.16" text-size = "1.1.1" tracing = "0.1.41" tracing-tree = "0.4.0" -tracing-subscriber = { version = "0.3.19", default-features = false, features = [ +tracing-subscriber = { version = "0.3.20", default-features = false, features = [ "registry", "fmt", "local-time", From 823101e0895d4ce17576a2aa487ba6fe3e38ea69 Mon Sep 17 00:00:00 2001 From: Elliot Roberts Date: Sat, 30 Aug 2025 13:36:29 -0700 Subject: [PATCH 125/251] Pass `--target` before `--` for `cargo rustc` --- .../project-model/src/toolchain_info/target_data_layout.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs index a28f468e692d0..f1d99cb8b002c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs @@ -23,14 +23,11 @@ pub fn get( QueryConfig::Cargo(sysroot, cargo_toml, _) => { let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env); cmd.env("RUSTC_BOOTSTRAP", "1"); - cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS).args([ - "--", - "-Z", - "unstable-options", - ]); + cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS); if let Some(target) = target { cmd.args(["--target", target]); } + cmd.args(["--", "-Z", "unstable-options"]); match utf8_stdout(&mut cmd) { Ok(output) => return process(output), Err(e) => { From a324fe956981f4ad736ffc268f222037fd853e83 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 2 Sep 2025 06:39:32 +0300 Subject: [PATCH 126/251] Make sense of the mess that were (are) different kind of generics in the solver To the extent possible. Previously they were confused. Sometimes generic params were treated as `Param` and sometimes as `Placeholder`. A completely redundant (in the new solver) mapping of salsa::Id to ints to intern some info where we could just store it uninterned (not in Chalk though, for some weird reason). Plus fix a cute bug in closure substitution that was caught by the assertions of Chalk but the next solver did not have such assertions. Do we need more assertions? --- .../crates/hir-ty/src/chalk_ext.rs | 2 +- .../crates/hir-ty/src/consteval.rs | 29 ++- .../crates/hir-ty/src/consteval_nextsolver.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 6 +- .../crates/hir-ty/src/display.rs | 46 ++--- .../crates/hir-ty/src/dyn_compatibility.rs | 20 +- .../crates/hir-ty/src/generics.rs | 8 +- .../crates/hir-ty/src/infer/closure.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 17 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 12 +- .../crates/hir-ty/src/lower/path.rs | 8 +- .../crates/hir-ty/src/lower_nextsolver.rs | 13 +- .../hir-ty/src/lower_nextsolver/path.rs | 2 + .../crates/hir-ty/src/mapping.rs | 36 +++- .../crates/hir-ty/src/mir/monomorphization.rs | 4 +- .../crates/hir-ty/src/next_solver/consts.rs | 3 + .../hir-ty/src/next_solver/generic_arg.rs | 38 ++-- .../crates/hir-ty/src/next_solver/generics.rs | 63 +++--- .../hir-ty/src/next_solver/infer/mod.rs | 13 +- .../crates/hir-ty/src/next_solver/mapping.rs | 191 ++++++++++-------- .../crates/hir-ty/src/next_solver/region.rs | 3 + .../crates/hir-ty/src/next_solver/ty.rs | 12 +- .../crates/hir-ty/src/variance.rs | 4 +- .../rust-analyzer/crates/hir/src/display.rs | 11 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +- 26 files changed, 324 insertions(+), 233 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 8fa1aff0ef636..33ae099c690ea 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -306,7 +306,7 @@ impl TyExt for Ty { predicates.map(|it| it.into_value_and_skipped_binders().0) } TyKind::Placeholder(idx) => { - let id = from_placeholder_idx(db, *idx); + let id = from_placeholder_idx(db, *idx).0; let generic_params = db.generic_params(id.parent); let param_data = &generic_params[id.local_id]; match param_data { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index abf97f3d0e302..0f2cc17f563dd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -107,25 +107,24 @@ pub(crate) fn path_to_const<'g>( match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) { Some(ValueNs::GenericParam(p)) => { let ty = db.const_param_ty(p); + let args = args(); let value = match mode { ParamLoweringMode::Placeholder => { - ConstValue::Placeholder(to_placeholder_idx(db, p.into())) + let idx = args.type_or_const_param_idx(p.into()).unwrap(); + ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32)) } - ParamLoweringMode::Variable => { - let args = args(); - match args.type_or_const_param_idx(p.into()) { - Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), - None => { - never!( - "Generic list doesn't contain this param: {:?}, {:?}, {:?}", - args, - path, - p - ); - return None; - } + ParamLoweringMode::Variable => match args.type_or_const_param_idx(p.into()) { + Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), + None => { + never!( + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", + args, + path, + p + ); + return None; } - } + }, }; Some(ConstData { ty, value }.intern(Interner)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index 00fc4e5610dce..4f95c9a13acdb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -49,7 +49,7 @@ pub(crate) fn path_to_const<'a, 'g>( .and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone()))) { Some((idx, _param)) => { - Some(Const::new_param(interner, ParamConst { index: idx as u32 })) + Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p })) } None => { never!( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 97754f47233b2..0b7213d785c91 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -410,13 +410,15 @@ fn hir_database_is_dyn_compatible() { #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedTypeOrConstParamId { - pub loc: TypeOrConstParamId, + /// This stores the param and its index. + pub loc: (TypeOrConstParamId, u32), } #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedLifetimeParamId { - pub loc: LifetimeParamId, + /// This stores the param and its index. + pub loc: (LifetimeParamId, u32), } #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 0df727a8e5c04..5b8093f6b7246 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -61,9 +61,8 @@ use crate::{ next_solver::{ BoundExistentialPredicate, Ctor, DbInterner, GenericArgs, SolverDefId, mapping::{ - ChalkToNextSolver, bound_var_to_lifetime_idx, bound_var_to_type_or_const_param_idx, - convert_args_for_result, convert_const_for_result, convert_region_for_result, - convert_ty_for_result, + ChalkToNextSolver, convert_args_for_result, convert_const_for_result, + convert_region_for_result, convert_ty_for_result, }, }, primitive, to_assoc_type_id, @@ -641,7 +640,7 @@ impl HirDisplay for ProjectionTy { && !f.bounds_formatting_ctx.contains(self) { let db = f.db; - let id = from_placeholder_idx(db, *idx); + let id = from_placeholder_idx(db, *idx).0; let generics = generics(db, id.parent); let substs = generics.placeholder_subst(db); @@ -736,14 +735,14 @@ impl HirDisplay for Const { impl<'db> HirDisplay for crate::next_solver::Const<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self.kind() { + rustc_type_ir::ConstKind::Placeholder(_) => write!(f, ""), rustc_type_ir::ConstKind::Bound(db, bound_const) => { write!(f, "?{}.{}", db.as_u32(), bound_const.as_u32()) } rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"), - rustc_type_ir::ConstKind::Placeholder(idx) => { - let id = bound_var_to_type_or_const_param_idx(f.db, idx.bound); - let generics = generics(f.db, id.parent); - let param_data = &generics[id.local_id]; + rustc_type_ir::ConstKind::Param(param) => { + let generics = generics(f.db, param.id.parent()); + let param_data = &generics[param.id.local_id()]; write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; Ok(()) } @@ -765,7 +764,6 @@ impl<'db> HirDisplay for crate::next_solver::Const<'db> { } rustc_type_ir::ConstKind::Error(..) => f.write_char('_'), rustc_type_ir::ConstKind::Expr(..) => write!(f, ""), - rustc_type_ir::ConstKind::Param(_) => write!(f, ""), } } } @@ -1178,7 +1176,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { if let TyKind::Ref(l, _, _) = kind { f.write_char('&')?; if f.render_region(l) { - convert_region_for_result(l).hir_fmt(f)?; + convert_region_for_result(interner, l).hir_fmt(f)?; f.write_char(' ')?; } match m { @@ -1611,14 +1609,10 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { write!(f, "{{closure}}")?; } } - TyKind::Placeholder(idx) => { - let placeholder_index = chalk_ir::PlaceholderIndex { - idx: idx.bound.var.as_usize(), - ui: chalk_ir::UniverseIndex { counter: idx.universe.as_usize() }, - }; - let id = from_placeholder_idx(db, placeholder_index); - let generics = generics(db, id.parent); - let param_data = &generics[id.local_id]; + TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?, + TyKind::Param(param) => { + let generics = generics(db, param.id.parent()); + let param_data = &generics[param.id.local_id()]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { @@ -1634,7 +1628,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { TypeParamProvenance::ArgumentImplTrait => { let substs = generics.placeholder_subst(db); let bounds = db - .generic_predicates(id.parent) + .generic_predicates(param.id.parent()) .iter() .map(|pred| pred.clone().substitute(Interner, &substs)) .filter(|wc| match wc.skip_binders() { @@ -1656,7 +1650,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { WhereClause::LifetimeOutlives(_) => false, }) .collect::>(); - let krate = id.parent.module(db).krate(); + let krate = param.id.parent().module(db).krate(); write_bounds_like_dyn_trait_with_prefix( f, "impl", @@ -1671,7 +1665,6 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } } - TyKind::Param(_) => write!(f, "{{param}}")?, TyKind::Bound(debruijn_index, ty) => { let idx = chalk_ir::BoundVar { debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), @@ -2294,7 +2287,7 @@ impl HirDisplay for LifetimeData { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { LifetimeData::Placeholder(idx) => { - let id = lt_from_placeholder_idx(f.db, *idx); + let id = lt_from_placeholder_idx(f.db, *idx).0; let generics = generics(f.db, id.parent); let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name.display(f.db, f.edition()))?; @@ -2319,10 +2312,9 @@ impl HirDisplay for LifetimeData { impl<'db> HirDisplay for crate::next_solver::Region<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self.kind() { - rustc_type_ir::RegionKind::RePlaceholder(idx) => { - let id = bound_var_to_lifetime_idx(f.db, idx.bound.var); - let generics = generics(f.db, id.parent); - let param_data = &generics[id.local_id]; + rustc_type_ir::RegionKind::ReEarlyParam(param) => { + let generics = generics(f.db, param.id.parent); + let param_data = &generics[param.id.local_id]; write!(f, "{}", param_data.name.display(f.db, f.edition()))?; Ok(()) } @@ -2339,7 +2331,7 @@ impl<'db> HirDisplay for crate::next_solver::Region<'db> { } } rustc_type_ir::RegionKind::ReErased => write!(f, "'"), - rustc_type_ir::RegionKind::ReEarlyParam(_) => write!(f, ""), + rustc_type_ir::RegionKind::RePlaceholder(_) => write!(f, ""), rustc_type_ir::RegionKind::ReLateParam(_) => write!(f, ""), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index b0c61c29db0b5..23280b1f3b42b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -2,10 +2,12 @@ use std::ops::ControlFlow; +use hir_def::hir::generics::LocalTypeOrConstParamId; use hir_def::{ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, lang_item::LangItem, signatures::TraitFlags, }; +use hir_def::{TypeOrConstParamId, TypeParamId}; use intern::Symbol; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -384,7 +386,6 @@ where } // Allow `impl AutoTrait` predicates - let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); if let ClauseKind::Trait(TraitPredicate { trait_ref: pred_trait_ref, polarity: PredicatePolarity::Positive, @@ -392,11 +393,8 @@ where && let SolverDefId::TraitId(trait_id) = pred_trait_ref.def_id && let trait_data = db.trait_signature(trait_id) && trait_data.flags.contains(TraitFlags::AUTO) - && pred_trait_ref.self_ty() - == crate::next_solver::Ty::new( - interner, - rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0 }), - ) + && let rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, .. }) = + pred_trait_ref.self_ty().kind() { continue; } @@ -422,9 +420,13 @@ fn receiver_is_dispatchable<'db>( let sig = sig.instantiate_identity(); let interner: DbInterner<'_> = DbInterner::new_with(db, Some(trait_.krate(db)), None); + let self_param_id = TypeParamId::from_unchecked(TypeOrConstParamId { + parent: trait_.into(), + local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), + }); let self_param_ty = crate::next_solver::Ty::new( interner, - rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0 }), + rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, id: self_param_id }), ); // `self: Self` can't be dispatched on, but this is already considered dyn-compatible @@ -452,7 +454,9 @@ fn receiver_is_dispatchable<'db>( }; // Type `U` - let unsized_self_ty = crate::next_solver::Ty::new_param(interner, u32::MAX, Symbol::empty()); + // FIXME: That seems problematic to fake a generic param like that? + let unsized_self_ty = + crate::next_solver::Ty::new_param(interner, self_param_id, u32::MAX, Symbol::empty()); // `Receiver[Self => U]` let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 412b3ac425028..e179e41b1cbe2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -256,15 +256,15 @@ impl Generics { pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { Substitution::from_iter( Interner, - self.iter_id().map(|id| match id { + self.iter_id().enumerate().map(|(index, id)| match id { GenericParamId::TypeParamId(id) => { - to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) + to_placeholder_idx(db, id.into(), index as u32).to_ty(Interner).cast(Interner) } - GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into()) + GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into(), index as u32) .to_const(Interner, db.const_param_ty(id)) .cast(Interner), GenericParamId::LifetimeParamId(id) => { - lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) + lt_to_placeholder_idx(db, id, index as u32).to_lifetime(Interner).cast(Interner) } }), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 38ac2e1170773..9ef046afdb3d3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -866,7 +866,7 @@ impl CapturedItemWithoutTy { idx: chalk_ir::PlaceholderIndex, outer_binder: DebruijnIndex, ) -> Result, Self::Error> { - let x = from_placeholder_idx(self.db, idx); + let x = from_placeholder_idx(self.db, idx).0; let Some(idx) = self.generics.type_or_const_param_idx(x) else { return Err(()); }; @@ -878,7 +878,7 @@ impl CapturedItemWithoutTy { idx: chalk_ir::PlaceholderIndex, outer_binder: DebruijnIndex, ) -> std::result::Result { - let x = from_placeholder_idx(self.db, idx); + let x = from_placeholder_idx(self.db, idx).0; let Some(idx) = self.generics.type_or_const_param_idx(x) else { return Err(()); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index e2ee8935a8855..f8abb3b7f6fef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -19,14 +19,15 @@ use rustc_type_ir::{ }; use triomphe::Arc; +use crate::utils::ClosureSubst; use crate::{ - TraitEnvironment, + Interner, TraitEnvironment, consteval_nextsolver::try_const_usize, db::HirDatabase, next_solver::{ DbInterner, GenericArgs, ParamEnv, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, - mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, + mapping::{ChalkToNextSolver, convert_args_for_result}, project::solve_normalize::deeply_normalize, }, }; @@ -333,9 +334,15 @@ pub fn layout_of_ty_query<'db>( let fields = captures .iter() .map(|it| { - let ty = - convert_binder_to_early_binder(interner, it.ty.to_nextsolver(interner)) - .instantiate(interner, args); + let ty = it + .ty + .clone() + .substitute( + Interner, + ClosureSubst(&convert_args_for_result(interner, args.inner())) + .parent_subst(), + ) + .to_nextsolver(interner); db.layout_of_ty(ty, trait_env.clone()) }) .collect::, _>>()?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 7fdfb205721ec..c16bbb7b99221 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -124,7 +124,7 @@ pub use lower_nextsolver::associated_type_shorthand_candidates; pub use mapping::{ ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, - to_foreign_def_id, to_placeholder_idx, + to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index, }; pub use method_resolution::check_orphan_rules; pub use target_feature::TargetFeatures; @@ -1007,7 +1007,7 @@ struct PlaceholderCollector<'db> { impl PlaceholderCollector<'_> { fn collect(&mut self, idx: PlaceholderIndex) { - let id = from_placeholder_idx(self.db, idx); + let id = from_placeholder_idx(self.db, idx).0; self.placeholders.insert(id); } } 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 098c62ba97a29..79f78c545e595 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -340,7 +340,13 @@ impl<'a> TyLoweringContext<'a> { res = Some(TypeNs::GenericParam(type_param_id)); match self.type_param_mode { ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, type_param_id.into())) + let generics = self.generics(); + let idx = generics.type_or_const_param_idx(type_param_id.into()).unwrap(); + TyKind::Placeholder(to_placeholder_idx( + self.db, + type_param_id.into(), + idx as u32, + )) } ParamLoweringMode::Variable => { let idx = @@ -777,7 +783,9 @@ impl<'a> TyLoweringContext<'a> { LifetimeNs::Static => static_lifetime(), LifetimeNs::LifetimeParam(id) => match self.type_param_mode { ParamLoweringMode::Placeholder => { - LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id)) + let generics = self.generics(); + let idx = generics.lifetime_idx(id).unwrap(); + LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id, idx as u32)) } ParamLoweringMode::Variable => { let idx = match self.generics().lifetime_idx(id) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index fb85909d7f41e..b0132e4dcbc46 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -222,7 +222,13 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode { ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.ctx.db, param_id.into())) + let generics = self.ctx.generics(); + let idx = generics.type_or_const_param_idx(param_id.into()).unwrap(); + TyKind::Placeholder(to_placeholder_idx( + self.ctx.db, + param_id.into(), + idx as u32, + )) } ParamLoweringMode::Variable => { let idx = match self.ctx.generics().type_or_const_param_idx(param_id.into()) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index d87181f545d88..4578922ce3219 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -64,8 +64,7 @@ use crate::{ AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, - TraitPredicate, TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind, - mapping::ChalkToNextSolver, + TraitPredicate, TraitRef, Ty, Tys, abi::Safety, mapping::ChalkToNextSolver, }, }; @@ -322,6 +321,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }; Ty::new_param( self.interner, + type_param_id, idx as u32, type_data .name @@ -866,7 +866,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { None => return Region::error(self.interner), Some(idx) => idx, }; - Region::new_early_param(self.interner, EarlyParamRegion { index: idx as u32 }) + Region::new_early_param( + self.interner, + EarlyParamRegion { index: idx as u32, id }, + ) } }, None => Region::error(self.interner), @@ -1344,11 +1347,11 @@ where { continue; } - let GenericParamDefKind::Type = p.kind else { + let GenericParamId::TypeParamId(param_id) = p.id else { continue; }; let idx = idx as u32 + generics.parent_count as u32; - let param_ty = Ty::new_param(interner, idx, p.name.clone()); + let param_ty = Ty::new_param(interner, param_id, idx, p.name.clone()); if explicitly_unsized_tys.contains(¶m_ty) { continue; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index e3efb38306408..ccdb5a0bdb4a9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -281,6 +281,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }; Ty::new_param( self.ctx.interner, + param_id, idx as u32, p.name .as_ref() @@ -758,6 +759,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| { convert_binder_to_early_binder( self.ctx.ctx.interner, + def, default.to_nextsolver(self.ctx.ctx.interner), ) .instantiate(self.ctx.ctx.interner, preceding_args) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs index 448fbdf673655..5125a38825cb8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs @@ -104,7 +104,10 @@ pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId { FromId::from_id(id.0) } -pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeOrConstParamId { +pub fn from_placeholder_idx( + db: &dyn HirDatabase, + idx: PlaceholderIndex, +) -> (TypeOrConstParamId, u32) { assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. let interned_id = @@ -112,15 +115,32 @@ pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> Type interned_id.loc(db) } -pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> PlaceholderIndex { - let interned_id = InternedTypeOrConstParamId::new(db, id); +pub fn to_placeholder_idx( + db: &dyn HirDatabase, + id: TypeOrConstParamId, + idx: u32, +) -> PlaceholderIndex { + let interned_id = InternedTypeOrConstParamId::new(db, (id, idx)); PlaceholderIndex { ui: chalk_ir::UniverseIndex::ROOT, idx: interned_id.as_id().index() as usize, } } -pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId { +pub fn to_placeholder_idx_no_index( + db: &dyn HirDatabase, + id: TypeOrConstParamId, +) -> PlaceholderIndex { + let index = crate::generics::generics(db, id.parent) + .type_or_const_param_idx(id) + .expect("param not found"); + to_placeholder_idx(db, id, index as u32) +} + +pub fn lt_from_placeholder_idx( + db: &dyn HirDatabase, + idx: PlaceholderIndex, +) -> (LifetimeParamId, u32) { assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. let interned_id = @@ -128,8 +148,12 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L interned_id.loc(db) } -pub fn lt_to_placeholder_idx(db: &dyn HirDatabase, id: LifetimeParamId) -> PlaceholderIndex { - let interned_id = InternedLifetimeParamId::new(db, id); +pub fn lt_to_placeholder_idx( + db: &dyn HirDatabase, + id: LifetimeParamId, + idx: u32, +) -> PlaceholderIndex { + let interned_id = InternedLifetimeParamId::new(db, (id, idx)); PlaceholderIndex { ui: chalk_ir::UniverseIndex::ROOT, idx: interned_id.as_id().index() as usize, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index d8f443145ca06..b0b922316914b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -99,7 +99,7 @@ impl FallibleTypeFolder for Filler<'_> { idx: chalk_ir::PlaceholderIndex, _outer_binder: DebruijnIndex, ) -> std::result::Result, Self::Error> { - let it = from_placeholder_idx(self.db, idx); + let it = from_placeholder_idx(self.db, idx).0; let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else { not_supported!("missing idx in generics"); }; @@ -117,7 +117,7 @@ impl FallibleTypeFolder for Filler<'_> { idx: chalk_ir::PlaceholderIndex, _outer_binder: DebruijnIndex, ) -> std::result::Result { - let it = from_placeholder_idx(self.db, idx); + let it = from_placeholder_idx(self.db, idx).0; let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else { not_supported!("missing idx in generics"); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index ce581cfad4b26..cfafc65d18443 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -2,6 +2,7 @@ use std::hash::Hash; +use hir_def::{ConstParamId, TypeOrConstParamId}; use intern::{Interned, Symbol}; use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; @@ -84,6 +85,8 @@ pub type PlaceholderConst = Placeholder; #[derive(Copy, Clone, Hash, Eq, PartialEq)] pub struct ParamConst { + // FIXME: See `ParamTy`. + pub id: ConstParamId, pub index: u32, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 76186e374608e..d284eb9c6b419 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -1,5 +1,6 @@ //! Things related to generic args in the next-trait-solver. +use hir_def::GenericParamId; use intern::{Interned, Symbol}; use rustc_type_ir::{ ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, @@ -14,7 +15,7 @@ use crate::db::HirDatabase; use super::{ Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys, - generics::{GenericParamDef, GenericParamDefKind, Generics}, + generics::{GenericParamDef, Generics}, interned_vec_db, }; @@ -203,7 +204,7 @@ impl<'db> GenericArgs<'db> { mut mk_kind: F, ) -> GenericArgs<'db> where - F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let defs = interner.generics_of(def_id); let count = defs.count(); @@ -218,7 +219,7 @@ impl<'db> GenericArgs<'db> { defs: Generics, mk_kind: &mut F, ) where - F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let self_len = defs.own_params.len() as u32; if let Some(def_id) = defs.parent { @@ -230,12 +231,12 @@ impl<'db> GenericArgs<'db> { fn fill_single(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F) where - F: FnMut(&Symbol, u32, GenericParamDefKind, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let start_len = args.len(); args.reserve(defs.own_params.len()); for param in &defs.own_params { - let kind = mk_kind(¶m.name, args.len() as u32, param.kind, args); + let kind = mk_kind(¶m.name, args.len() as u32, param.id, args); args.push(kind); } } @@ -412,26 +413,25 @@ pub fn mk_param<'db>( interner: DbInterner<'db>, index: u32, name: &Symbol, - kind: GenericParamDefKind, + id: GenericParamId, ) -> GenericArg<'db> { let name = name.clone(); - match kind { - GenericParamDefKind::Lifetime => { - Region::new_early_param(interner, EarlyParamRegion { index }).into() + match id { + GenericParamId::LifetimeParamId(id) => { + Region::new_early_param(interner, EarlyParamRegion { index, id }).into() + } + GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index, name).into(), + GenericParamId::ConstParamId(id) => { + Const::new_param(interner, ParamConst { index, id }).into() } - GenericParamDefKind::Type => Ty::new_param(interner, index, name).into(), - GenericParamDefKind::Const => Const::new_param(interner, ParamConst { index }).into(), } } -pub fn error_for_param_kind<'db>( - kind: GenericParamDefKind, - interner: DbInterner<'db>, -) -> GenericArg<'db> { - match kind { - GenericParamDefKind::Lifetime => Region::error(interner).into(), - GenericParamDefKind::Type => Ty::new_error(interner, ErrorGuaranteed).into(), - GenericParamDefKind::Const => Const::error(interner).into(), +pub fn error_for_param_kind<'db>(id: GenericParamId, interner: DbInterner<'db>) -> GenericArg<'db> { + match id { + GenericParamId::LifetimeParamId(_) => Region::error(interner).into(), + GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(), + GenericParamId::ConstParamId(_) => Const::error(interner).into(), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index a3ba8eb83453e..5ec9a18a6c20e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -24,35 +24,40 @@ use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, Solver use super::{DbInterner, GenericArg}; pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { - let mk_lt = |index, lt: &LifetimeParamData| { + let mk_lt = |parent, index, local_id, lt: &LifetimeParamData| { let name = lt.name.symbol().clone(); - let kind = GenericParamDefKind::Lifetime; - GenericParamDef { name, index, kind } + let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }); + GenericParamDef { name, index, id } }; - let mk_ty = |index, p: &TypeOrConstParamData| { + let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| { let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME); - let kind = match p { - TypeOrConstParamData::TypeParamData(_) => GenericParamDefKind::Type, - TypeOrConstParamData::ConstParamData(_) => GenericParamDefKind::Const, + let id = TypeOrConstParamId { parent, local_id }; + let id = match p { + TypeOrConstParamData::TypeParamData(_) => { + GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)) + } + TypeOrConstParamData::ConstParamData(_) => { + GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)) + } }; - GenericParamDef { name, index, kind } + GenericParamDef { name, index, id } }; - let own_params_for_generic_params = |params: &GenericParams| { + let own_params_for_generic_params = |parent, params: &GenericParams| { let mut result = Vec::with_capacity(params.len()); let mut type_and_consts = params.iter_type_or_consts(); let mut index = 0; if let Some(self_param) = params.trait_self_param() { - result.push(mk_ty(0, ¶ms[self_param])); + result.push(mk_ty(parent, 0, self_param, ¶ms[self_param])); type_and_consts.next(); index += 1; } - result.extend(params.iter_lt().map(|(_, data)| { - let lt = mk_lt(index, data); + result.extend(params.iter_lt().map(|(local_id, data)| { + let lt = mk_lt(parent, index, local_id, data); index += 1; lt })); - result.extend(type_and_consts.map(|(_, data)| { - let ty = mk_ty(index, data); + result.extend(type_and_consts.map(|(local_id, data)| { + let ty = mk_ty(parent, index, local_id, data); index += 1; ty })); @@ -60,9 +65,10 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { }; let (parent, own_params) = match (def.try_into(), def) { - (Ok(def), _) => { - (parent_generic_def(db, def), own_params_for_generic_params(&db.generic_params(def))) - } + (Ok(def), _) => ( + parent_generic_def(db, def), + own_params_for_generic_params(def, &db.generic_params(def)), + ), (_, SolverDefId::InternedOpaqueTyId(id)) => { match db.lookup_intern_impl_trait_id(id) { crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => { @@ -79,7 +85,19 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { provenance: TypeParamProvenance::TypeParamList, }); // Yes, there is a parent but we don't include it in the generics - (None, vec![mk_ty(0, ¶m)]) + // FIXME: It seems utterly sensitive to fake a generic param here. + // Also, what a horrible mess! + ( + None, + vec![mk_ty( + GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe { + salsa::Id::from_index(salsa::Id::MAX_U32 - 1) + })), + 0, + LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), + ¶m, + )], + ) } } } @@ -106,7 +124,7 @@ pub struct GenericParamDef { pub(crate) name: Symbol, //def_id: GenericDefId, index: u32, - pub(crate) kind: GenericParamDefKind, + pub(crate) id: GenericParamId, } impl GenericParamDef { @@ -117,13 +135,6 @@ impl GenericParamDef { } } -#[derive(Copy, Clone, Debug)] -pub enum GenericParamDefKind { - Lifetime, - Type, - Const, -} - impl<'db> rustc_type_ir::inherent::GenericsOf> for Generics { fn count(&self) -> usize { self.parent_count + self.own_params.len() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 19ae76f7e358f..58832aef89529 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -8,6 +8,7 @@ pub use BoundRegionConversionTime::*; pub use at::DefineOpaqueTypes; use ena::undo_log::UndoLogs; use ena::unify as ut; +use hir_def::GenericParamId; use intern::Symbol; use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage}; use region_constraints::{ @@ -38,7 +39,7 @@ use crate::next_solver::fold::BoundVarReplacerDelegate; use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries; use crate::next_solver::{BoundRegion, BoundTy, BoundVarKind}; -use super::generics::{GenericParamDef, GenericParamDefKind}; +use super::generics::GenericParamDef; use super::{ AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, @@ -600,14 +601,14 @@ impl<'db> InferCtxt<'db> { self.next_region_var_in_universe(universe) } - fn var_for_def(&self, kind: GenericParamDefKind, name: &Symbol) -> GenericArg<'db> { - match kind { - GenericParamDefKind::Lifetime => { + fn var_for_def(&self, id: GenericParamId, name: &Symbol) -> GenericArg<'db> { + match id { + GenericParamId::LifetimeParamId(_) => { // Create a region inference variable for the given // region parameter definition. self.next_region_var().into() } - GenericParamDefKind::Type => { + GenericParamId::TypeParamId(_) => { // Create a type inference variable for the given // type parameter definition. The generic parameters are // for actual parameters that may be referred to by @@ -624,7 +625,7 @@ impl<'db> InferCtxt<'db> { Ty::new_var(self.interner, ty_var_id).into() } - GenericParamDefKind::Const => { + GenericParamId::ConstParamId(_) => { let origin = ConstVariableOrigin { param_def_id: None }; let const_var_id = self .inner diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 203f030dfd614..6755d065e10d3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -9,6 +9,7 @@ use hir_def::{ CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId, TypeOrConstParamId, TypeParamId, signatures::TraitFlags, }; +use hir_def::{GenericDefId, GenericParamId}; use intern::sym; use rustc_type_ir::{ AliasTerm, BoundVar, DebruijnIndex, ExistentialProjection, ExistentialTraitRef, Interner as _, @@ -35,6 +36,9 @@ use crate::{ }, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, }; +use crate::{ + from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_placeholder_idx, +}; use super::{ BoundExistentialPredicate, BoundExistentialPredicates, BoundRegion, BoundRegionKind, BoundTy, @@ -44,47 +48,24 @@ use super::{ Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, Tys, ValueConst, VariancesOf, }; -pub fn to_placeholder_idx( - db: &dyn HirDatabase, - id: TypeOrConstParamId, - map: impl Fn(BoundVar) -> T, -) -> Placeholder { - let interned_id = InternedTypeOrConstParamId::new(db, id); - Placeholder { - universe: UniverseIndex::ZERO, - bound: map(BoundVar::from_usize(interned_id.as_id().index() as usize)), - } -} - -pub fn bound_var_to_type_or_const_param_idx( - db: &dyn HirDatabase, - var: rustc_type_ir::BoundVar, -) -> TypeOrConstParamId { - // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. - let interned_id = InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(var.as_u32()) }); - interned_id.loc(db) -} - -pub fn bound_var_to_lifetime_idx( - db: &dyn HirDatabase, - var: rustc_type_ir::BoundVar, -) -> LifetimeParamId { - // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. - let interned_id = InternedLifetimeParamId::from_id(unsafe { Id::from_index(var.as_u32()) }); - interned_id.loc(db) -} - +// FIXME: This should urgently go (as soon as we finish the migration off Chalk, that is). pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable>>( interner: DbInterner<'db>, + def: GenericDefId, binder: rustc_type_ir::Binder, T>, ) -> rustc_type_ir::EarlyBinder, T> { - let mut folder = BinderToEarlyBinder { interner, debruijn: rustc_type_ir::DebruijnIndex::ZERO }; + let mut folder = BinderToEarlyBinder { + interner, + debruijn: rustc_type_ir::DebruijnIndex::ZERO, + params: crate::generics::generics(interner.db, def).iter_id().collect(), + }; rustc_type_ir::EarlyBinder::bind(binder.skip_binder().fold_with(&mut folder)) } struct BinderToEarlyBinder<'db> { interner: DbInterner<'db>, debruijn: rustc_type_ir::DebruijnIndex, + params: Vec, } impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db> { @@ -109,7 +90,13 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db match t.kind() { rustc_type_ir::TyKind::Bound(debruijn, bound_ty) if self.debruijn == debruijn => { let var: rustc_type_ir::BoundVar = bound_ty.var(); - Ty::new(self.cx(), rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32() })) + let GenericParamId::TypeParamId(id) = self.params[bound_ty.var.as_usize()] else { + unreachable!() + }; + Ty::new( + self.cx(), + rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32(), id }), + ) } _ => t.super_fold_with(self), } @@ -119,10 +106,15 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db match r.kind() { rustc_type_ir::ReBound(debruijn, bound_region) if self.debruijn == debruijn => { let var: rustc_type_ir::BoundVar = bound_region.var(); + let GenericParamId::LifetimeParamId(id) = self.params[bound_region.var.as_usize()] + else { + unreachable!() + }; Region::new( self.cx(), rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { index: var.as_u32(), + id, }), ) } @@ -133,9 +125,12 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { match c.kind() { rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => { + let GenericParamId::ConstParamId(id) = self.params[var.as_usize()] else { + unreachable!() + }; Const::new( self.cx(), - rustc_type_ir::ConstKind::Param(ParamConst { index: var.as_u32() }), + rustc_type_ir::ConstKind::Param(ParamConst { index: var.as_u32(), id }), ) } _ => c.super_fold_with(self), @@ -274,12 +269,6 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { SolverDefId::TypeAliasId(crate::from_foreign_def_id(*foreign_def_id)), ), chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed), - chalk_ir::TyKind::Placeholder(placeholder_index) => { - rustc_type_ir::TyKind::Placeholder(PlaceholderTy::new_anon( - placeholder_index.ui.to_nextsolver(interner), - rustc_type_ir::BoundVar::from_usize(placeholder_index.idx), - )) - } chalk_ir::TyKind::Dyn(dyn_ty) => { // exists { for<...> ^1.0: ... } let bounds = BoundExistentialPredicates::new_from_iter( @@ -405,6 +394,26 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { rustc_type_ir::TyKind::FnPtr(sig_tys, header) } + // The schema here is quite confusing. + // The new solver, like rustc, uses `Param` and `EarlyBinder` for generic params. It uses `BoundVar` + // and `Placeholder` together with `Binder` for HRTB, which we mostly don't handle. + // Chalk uses `Placeholder` for generic params and `BoundVar` quite liberally, and this is quite a + // problem. `chalk_ir::TyKind::BoundVar` can represent either HRTB or generic params, depending on the + // context. When returned from signature queries, the outer `Binders` represent the generic params. + // But there are also inner `Binders` for HRTB. + // AFAIK there is no way to tell which of the meanings is relevant, so we just use `rustc_type_ir::Bound` + // here, and hope for the best. If you are working with new solver types, therefore, use the new solver + // lower queries. + // Hopefully sooner than later Chalk will be ripped from the codebase and we can avoid that problem. + // For details about the rustc setup, read: https://rustc-dev-guide.rust-lang.org/generic_parameters_summary.html + // and the following chapters. + chalk_ir::TyKind::Placeholder(placeholder_index) => { + let (id, index) = from_placeholder_idx(interner.db, *placeholder_index); + rustc_type_ir::TyKind::Param(ParamTy { + id: TypeParamId::from_unchecked(id), + index, + }) + } chalk_ir::TyKind::BoundVar(bound_var) => rustc_type_ir::TyKind::Bound( bound_var.debruijn.to_nextsolver(interner), BoundTy { @@ -440,10 +449,8 @@ impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { )) } chalk_ir::LifetimeData::Placeholder(placeholder_index) => { - rustc_type_ir::RegionKind::RePlaceholder(PlaceholderRegion::new_anon( - rustc_type_ir::UniverseIndex::from_u32(placeholder_index.ui.counter as u32), - rustc_type_ir::BoundVar::from_u32(placeholder_index.idx as u32), - )) + let (id, index) = lt_from_placeholder_idx(interner.db, *placeholder_index); + rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { id, index }) } chalk_ir::LifetimeData::Static => rustc_type_ir::RegionKind::ReStatic, chalk_ir::LifetimeData::Erased => rustc_type_ir::RegionKind::ReErased, @@ -474,10 +481,11 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { )) } chalk_ir::ConstValue::Placeholder(placeholder_index) => { - rustc_type_ir::ConstKind::Placeholder(PlaceholderConst::new( - placeholder_index.ui.to_nextsolver(interner), - rustc_type_ir::BoundVar::from_usize(placeholder_index.idx), - )) + let (id, index) = from_placeholder_idx(interner.db, *placeholder_index); + rustc_type_ir::ConstKind::Param(ParamConst { + id: ConstParamId::from_unchecked(id), + index, + }) } chalk_ir::ConstValue::Concrete(concrete_const) => match &concrete_const.interned { ConstScalar::Bytes(bytes, memory) => { @@ -971,7 +979,7 @@ pub fn convert_args_for_result<'db>( substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner)); } rustc_type_ir::GenericArgKind::Lifetime(region) => { - let lifetime = convert_region_for_result(region); + let lifetime = convert_region_for_result(interner, region); substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner)); } rustc_type_ir::GenericArgKind::Const(const_) => { @@ -1074,7 +1082,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, }; - let r = convert_region_for_result(r); + let r = convert_region_for_result(interner, r); let ty = convert_ty_for_result(interner, ty); TyKind::Ref(mutability, r, ty) } @@ -1122,17 +1130,23 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::AliasTyKind::Free => unimplemented!(), }, + // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion. rustc_type_ir::TyKind::Placeholder(placeholder) => { - let ui = chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }; - let placeholder_index = - chalk_ir::PlaceholderIndex { idx: placeholder.bound.var.as_usize(), ui }; - TyKind::Placeholder(placeholder_index) + unimplemented!( + "A `rustc_type_ir::TyKind::Placeholder` doesn't have a direct \ + correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ + It therefore feels safer to leave it panicking, but if you hit this panic \ + feel free to do the same as in `rustc_type_ir::TyKind::Bound` here." + ) } - rustc_type_ir::TyKind::Bound(debruijn_index, ty) => TyKind::BoundVar(chalk_ir::BoundVar { debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), index: ty.var.as_usize(), }), + rustc_type_ir::TyKind::Param(param) => { + let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index); + TyKind::Placeholder(placeholder) + } rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => { let num_binders = bound_sig.bound_vars().len(); @@ -1254,7 +1268,8 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), ); let bounds = chalk_ir::Binders::new(binders, bounds); - let dyn_ty = chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(region) }; + let dyn_ty = + chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(interner, region) }; TyKind::Dyn(dyn_ty) } @@ -1316,7 +1331,6 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) TyKind::CoroutineWitness(id.into(), subst) } - rustc_type_ir::TyKind::Param(_) => unimplemented!(), rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(), } .intern(Interner) @@ -1327,13 +1341,16 @@ pub fn convert_const_for_result<'db>( const_: Const<'db>, ) -> crate::Const { let value: chalk_ir::ConstValue = match const_.kind() { - rustc_type_ir::ConstKind::Param(_) => unimplemented!(), rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32())) } rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => { panic!("Vars should not be freshened.") } + rustc_type_ir::ConstKind::Param(param) => { + let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index); + chalk_ir::ConstValue::Placeholder(placeholder) + } rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), @@ -1341,10 +1358,12 @@ pub fn convert_const_for_result<'db>( )) } rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { - chalk_ir::ConstValue::Placeholder(chalk_ir::PlaceholderIndex { - ui: chalk_ir::UniverseIndex { counter: placeholder_const.universe.as_usize() }, - idx: placeholder_const.bound.as_usize(), - }) + unimplemented!( + "A `rustc_type_ir::ConstKind::Placeholder` doesn't have a direct \ + correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ + It therefore feels safer to leave it panicking, but if you hit this panic \ + feel free to do the same as in `rustc_type_ir::ConstKind::Bound` here." + ) } rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => { let id = match unevaluated_const.def { @@ -1381,36 +1400,34 @@ pub fn convert_const_for_result<'db>( chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) } -pub fn convert_region_for_result<'db>(region: Region<'db>) -> crate::Lifetime { - match region.kind() { - rustc_type_ir::RegionKind::ReEarlyParam(early) => unimplemented!(), - rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new( - Interner, +pub fn convert_region_for_result<'db>( + interner: DbInterner<'db>, + region: Region<'db>, +) -> crate::Lifetime { + let lifetime = match region.kind() { + rustc_type_ir::RegionKind::ReEarlyParam(early) => { + let placeholder = lt_to_placeholder_idx(interner.db, early.id, early.index); + chalk_ir::LifetimeData::Placeholder(placeholder) + } + rustc_type_ir::RegionKind::ReBound(db, bound) => { chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(db.as_u32()), bound.var.as_usize(), - )), - ), - rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(), - rustc_type_ir::RegionKind::ReStatic => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Static) + )) } - rustc_type_ir::RegionKind::ReVar(vid) => chalk_ir::Lifetime::new( - Interner, - chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())), - ), - rustc_type_ir::RegionKind::RePlaceholder(placeholder) => chalk_ir::Lifetime::new( - Interner, - chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { - idx: placeholder.bound.var.as_usize(), - ui: chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }, - }), + rustc_type_ir::RegionKind::RePlaceholder(placeholder) => unimplemented!( + "A `rustc_type_ir::RegionKind::RePlaceholder` doesn't have a direct \ + correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ + It therefore feels safer to leave it panicking, but if you hit this panic \ + feel free to do the same as in `rustc_type_ir::RegionKind::ReBound` here." ), - rustc_type_ir::RegionKind::ReErased => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Erased) - } - rustc_type_ir::RegionKind::ReError(_) => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Error) + rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(), + rustc_type_ir::RegionKind::ReStatic => chalk_ir::LifetimeData::Static, + rustc_type_ir::RegionKind::ReVar(vid) => { + chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())) } - } + rustc_type_ir::RegionKind::ReErased => chalk_ir::LifetimeData::Erased, + rustc_type_ir::RegionKind::ReError(_) => chalk_ir::LifetimeData::Error, + }; + chalk_ir::Lifetime::new(Interner, lifetime) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index c59cdac5f99f6..d6214d991560a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -1,5 +1,6 @@ //! Things related to regions. +use hir_def::LifetimeParamId; use intern::{Interned, Symbol}; use rustc_type_ir::{ BoundVar, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable, VisitorResult, @@ -110,6 +111,8 @@ pub type PlaceholderRegion = Placeholder; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct EarlyParamRegion { + // FIXME: See `ParamTy`. + pub id: LifetimeParamId, pub index: u32, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 5ffae981a6094..92f1076e75eca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -1,5 +1,6 @@ //! Things related to tys in the next-trait-solver. +use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId}; use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; @@ -64,8 +65,8 @@ impl<'db> Ty<'db> { .unwrap() } - pub fn new_param(interner: DbInterner<'db>, index: u32, name: Symbol) -> Self { - Ty::new(interner, TyKind::Param(ParamTy { index })) + pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> Self { + Ty::new(interner, TyKind::Param(ParamTy { id, index })) } pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderTy) -> Self { @@ -847,12 +848,16 @@ pub type PlaceholderTy = Placeholder; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct ParamTy { + // FIXME: I'm not pleased with this. Ideally a `Param` should only know its index - the defining item + // is known from the `EarlyBinder`. This should also be beneficial for memory usage. But code currently + // assumes it can get the definition from `Param` alone - so that's what we got. + pub id: TypeParamId, pub index: u32, } impl ParamTy { pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> { - Ty::new_param(interner, self.index, sym::MISSING_NAME.clone()) + Ty::new_param(interner, self.id, self.index, sym::MISSING_NAME.clone()) } } @@ -865,6 +870,7 @@ impl std::fmt::Debug for ParamTy { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct BoundTy { pub var: BoundVar, + // FIXME: This is for diagnostics in rustc, do we really need it? pub kind: BoundTyKind, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index d8a058533f761..a1ebff04bbd47 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -344,7 +344,7 @@ impl Context<'_> { // Chalk has no params, so use placeholders for now? TyKind::Placeholder(index) => { - let idx = crate::from_placeholder_idx(self.db, *index); + let idx = crate::from_placeholder_idx(self.db, *index).0; let index = self.generics.type_or_const_param_idx(idx).unwrap(); self.constrain(index, variance); } @@ -445,7 +445,7 @@ impl Context<'_> { ); match region.data(Interner) { LifetimeData::Placeholder(index) => { - let idx = crate::lt_from_placeholder_idx(self.db, *index); + let idx = crate::lt_from_placeholder_idx(self.db, *index).0; let inferred = self.generics.lifetime_idx(idx).unwrap(); self.constrain(inferred, variance); } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index b9c5131ffbb55..833a9ef03065d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -474,8 +474,8 @@ impl HirDisplay for TypeParam { let param_data = ¶ms[self.id.local_id()]; let substs = TyBuilder::placeholder_subst(f.db, self.id.parent()); let krate = self.id.parent().krate(f.db).id; - let ty = - TyKind::Placeholder(hir_ty::to_placeholder_idx(f.db, self.id.into())).intern(Interner); + let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(f.db, self.id.into())) + .intern(Interner); let predicates = f.db.generic_predicates(self.id.parent()); let predicates = predicates .iter() @@ -528,8 +528,11 @@ impl HirDisplay for TypeParam { f, ":", Either::Left( - &hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx(f.db, self.id.into())) - .intern(Interner), + &hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index( + f.db, + self.id.into(), + )) + .intern(Interner), ), &predicates, default_sized, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f03f542e5bce3..46d3a2bcd67ce 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4239,8 +4239,8 @@ impl TypeParam { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.parent().resolver(db); - let ty = - TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner); + let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(db, self.id.into())) + .intern(Interner); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -5933,7 +5933,7 @@ impl<'db> Type<'db> { pub fn as_type_param(&self, db: &'db dyn HirDatabase) -> Option { match self.ty.kind(Interner) { TyKind::Placeholder(p) => Some(TypeParam { - id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)), + id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p).0), }), _ => None, } From dd75ad436927ac30bf204953d24b07bff09225bd Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 2 Sep 2025 08:15:17 +0300 Subject: [PATCH 127/251] Deduplicate methods in completion by function ID and not by name Because duplicates can be found with traits. Worse, the inherent methods could be private, and we'll discover that only later. But even if they're not they're different methods, and its seems worthy to present them all to the user. --- .../ide-completion/src/completions/dot.rs | 15 ++++--- .../ide-completion/src/tests/expression.rs | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 129964f8387a3..b9ef68cc2d2a3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; -use hir::{Complete, HasContainer, ItemContainer, MethodCandidateCallback, Name}; +use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback}; use ide_db::FxHashSet; use syntax::SmolStr; @@ -237,7 +237,10 @@ fn complete_methods( struct Callback<'a, F> { ctx: &'a CompletionContext<'a>, f: F, - seen_methods: FxHashSet, + // We deliberately deduplicate by function ID and not name, because while inherent methods cannot be + // duplicated, trait methods can. And it is still useful to show all of them (even when there + // is also an inherent method, especially considering that it may be private, and filtered later). + seen_methods: FxHashSet, } impl MethodCandidateCallback for Callback<'_, F> @@ -247,9 +250,7 @@ fn complete_methods( // We don't want to exclude inherent trait methods - that is, methods of traits available from // `where` clauses or `dyn Trait`. fn on_inherent_method(&mut self, func: hir::Function) -> ControlFlow<()> { - if func.self_param(self.ctx.db).is_some() - && self.seen_methods.insert(func.name(self.ctx.db)) - { + if func.self_param(self.ctx.db).is_some() && self.seen_methods.insert(func) { (self.f)(func); } ControlFlow::Continue(()) @@ -265,9 +266,7 @@ fn complete_methods( return ControlFlow::Continue(()); } - if func.self_param(self.ctx.db).is_some() - && self.seen_methods.insert(func.name(self.ctx.db)) - { + if func.self_param(self.ctx.db).is_some() && self.seen_methods.insert(func) { (self.f)(func); } 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 7a0d00444129f..af6ef34761ed1 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 @@ -2632,3 +2632,43 @@ fn let_in_condition() { fn let_in_let_chain() { check_edit("let", r#"fn f() { if true && $0 {} }"#, r#"fn f() { if true && let $1 = $0 {} }"#); } + +#[test] +fn private_inherent_and_public_trait() { + check( + r#" +struct Foo; + +mod private { + impl super::Foo { + fn method(&self) {} + } +} + +trait Trait { + fn method(&self) {} +} +impl Trait for Foo {} + +fn main() { + Foo.$0 +} + "#, + expect![[r#" + me method() (as Trait) 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 let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} From 18fa6d917cb39758429d47015fc83e72445e2199 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 2 Sep 2025 10:48:42 +0200 Subject: [PATCH 128/251] Remove some llvm workarounds --- library/stdarch/crates/core_arch/src/x86/avx512f.rs | 8 ++------ library/stdarch/crates/core_arch/src/x86_64/avx512f.rs | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index 0803f2f81b215..52c6a11a43f0e 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -49621,9 +49621,7 @@ mod tests { assert_eq_m512i(r, e); } - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 - //#[simd_test(enable = "avx512f")] - #[simd_test(enable = "avx512f,avx512vl")] + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_mask_cvttps_epu32() { let a = _mm512_setr_ps( 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, @@ -49636,9 +49634,7 @@ mod tests { assert_eq_m512i(r, e); } - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 - //#[simd_test(enable = "avx512f")] - #[simd_test(enable = "avx512f,avx512vl")] + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_maskz_cvttps_epu32() { let a = _mm512_setr_ps( 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, diff --git a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs index a8dd340bd6605..934c9e2812c42 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs @@ -5311,9 +5311,7 @@ mod tests { assert_eq_m256i(r, e); } - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 - //#[simd_test(enable = "avx512f")] - #[simd_test(enable = "avx512f,avx512vl")] + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_mask_cvttpd_epu32() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); let src = _mm256_set1_epi32(0); @@ -5324,9 +5322,7 @@ mod tests { assert_eq_m256i(r, e); } - // FIXME(llvm): https://github.com/llvm/llvm-project/issues/154492 - //#[simd_test(enable = "avx512f")] - #[simd_test(enable = "avx512f,avx512vl")] + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_maskz_cvttpd_epu32() { let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); let r = _mm512_maskz_cvttpd_epu32(0, a); From bb3598e481a752b85872fcbea9dab805907c2d81 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 2 Sep 2025 10:52:49 +0200 Subject: [PATCH 129/251] use `qemu-user` instead of `qemu-user-static` for loongarch CI --- .../ci/docker/loongarch64-unknown-linux-gnu/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/stdarch/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile index b5c6874ca52ed..e803dae1006a0 100644 --- a/library/stdarch/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -2,11 +2,11 @@ FROM ubuntu:25.10 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ + gcc libc6-dev qemu-user ca-certificates \ gcc-loongarch64-linux-gnu libc6-dev-loong64-cross ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc \ - CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-loongarch64-static -cpu max -L /usr/loongarch64-linux-gnu" \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-loongarch64 -cpu max -L /usr/loongarch64-linux-gnu" \ OBJDUMP=loongarch64-linux-gnu-objdump \ STDARCH_TEST_SKIP_FEATURE=frecipe From 46795337322b5852438417549a5fe9dce3f75479 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 30 Aug 2025 05:05:12 +0000 Subject: [PATCH 130/251] RISC-V: Lower requirements of `clmul` and `clmulh` They don't need full "Zbc" extension but only its subset: the "Zbkc" extension. Since the compiler implies `zbkc` from `zbc`, it's safe to use `#[target_feature(enable = "zbkc")]`. --- library/stdarch/crates/core_arch/src/riscv_shared/zb.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/riscv_shared/zb.rs b/library/stdarch/crates/core_arch/src/riscv_shared/zb.rs index 9472e3c8be9f6..514afd9080920 100644 --- a/library/stdarch/crates/core_arch/src/riscv_shared/zb.rs +++ b/library/stdarch/crates/core_arch/src/riscv_shared/zb.rs @@ -68,7 +68,7 @@ pub fn orc_b(rs: usize) -> usize { /// /// Section: 2.11 #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] -#[target_feature(enable = "zbc")] +#[target_feature(enable = "zbkc")] #[cfg_attr(test, assert_instr(clmul))] #[inline] pub fn clmul(rs1: usize, rs2: usize) -> usize { @@ -93,7 +93,7 @@ pub fn clmul(rs1: usize, rs2: usize) -> usize { /// /// Section: 2.12 #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] -#[target_feature(enable = "zbc")] +#[target_feature(enable = "zbkc")] #[cfg_attr(test, assert_instr(clmulh))] #[inline] pub fn clmulh(rs1: usize, rs2: usize) -> usize { From 5b71113a64d576abd6a14c8d7201ff1164a6c44e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Sep 2025 11:40:46 +0200 Subject: [PATCH 131/251] re-balance CI --- src/tools/miri/ci/ci.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index b66530e77b8a8..224ca0ae29948 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -164,12 +164,15 @@ case $HOST_TARGET in MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice - # Custom target JSON file - TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std + # Not officially supported tier 2 + MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests + MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests ;; armv7-unknown-linux-gnueabihf) # Host GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + # Custom target JSON file + TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std ;; aarch64-apple-darwin) # Host @@ -181,8 +184,6 @@ case $HOST_TARGET in MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests - MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests - MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests ;; i686-pc-windows-msvc) # Host From a880c46f198e9601e70cac9286154286906699ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Sep 2025 11:47:30 +0200 Subject: [PATCH 132/251] no need to run GC_STRESS more than once for each OS --- src/tools/miri/ci/ci.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 224ca0ae29948..6356e33f61e84 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -137,6 +137,7 @@ function run_tests_minimal { # In particular, fully cover all tier 1 targets. # We also want to run the many-seeds tests on all tier 1 targets. +# We run GC_STRESS only once for each tier 1 OS. case $HOST_TARGET in x86_64-unknown-linux-gnu) # Host @@ -147,7 +148,6 @@ case $HOST_TARGET in ;; i686-unknown-linux-gnu) # Host - # Without GC_STRESS as this is a slow runner. MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator @@ -159,7 +159,7 @@ case $HOST_TARGET in ;; aarch64-unknown-linux-gnu) # Host - GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 2 MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI @@ -170,7 +170,7 @@ case $HOST_TARGET in ;; armv7-unknown-linux-gnueabihf) # Host - GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Custom target JSON file TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std ;; @@ -187,7 +187,6 @@ case $HOST_TARGET in ;; i686-pc-windows-msvc) # Host - # Without GC_STRESS as this is a very slow runner. MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, @@ -196,8 +195,7 @@ case $HOST_TARGET in ;; aarch64-pc-windows-msvc) # Host - # Without GC_STRESS as this is a very slow runner. - MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests ;; From d366f26421125e11bfcec5e4a9f202813cbd3229 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Apr 2025 08:53:50 +0200 Subject: [PATCH 133/251] Extract address generator struct from memory allocator. --- .../src/alloc_addresses/address_generator.rs | 78 +++++++++++++++++++ src/tools/miri/src/alloc_addresses/mod.rs | 65 ++++------------ src/tools/miri/src/machine.rs | 4 +- 3 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 src/tools/miri/src/alloc_addresses/address_generator.rs diff --git a/src/tools/miri/src/alloc_addresses/address_generator.rs b/src/tools/miri/src/alloc_addresses/address_generator.rs new file mode 100644 index 0000000000000..3764f5dcb8244 --- /dev/null +++ b/src/tools/miri/src/alloc_addresses/address_generator.rs @@ -0,0 +1,78 @@ +use std::ops::Range; + +use rand::Rng; +use rustc_abi::{Align, Size}; +use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_middle::{err_exhaust, throw_exhaust}; + +/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple +/// of `align` that is larger or equal to `addr` +fn align_addr(addr: u64, align: u64) -> u64 { + match addr % align { + 0 => addr, + rem => addr.strict_add(align) - rem, + } +} + +/// This provides the logic to generate addresses for memory allocations in a given address range. +#[derive(Debug)] +pub struct AddressGenerator { + /// This is used as a memory address when a new pointer is casted to an integer. It + /// is always larger than any address that was previously made part of a block. + next_base_addr: u64, + /// This is the last address that can be allocated. + end: u64, +} + +impl AddressGenerator { + pub fn new(addr_range: Range) -> Self { + Self { next_base_addr: addr_range.start, end: addr_range.end } + } + + /// Get the remaining range where this `AddressGenerator` can still allocate addresses. + pub fn get_remaining(&self) -> Range { + self.next_base_addr..self.end + } + + /// Generate a new address with the specified size and alignment, using the given Rng to add some randomness. + /// The returned allocation is guaranteed not to overlap with any address ranges given out by the generator before. + /// Returns an error if the allocation request cannot be fulfilled. + pub fn generate<'tcx, R: Rng>( + &mut self, + size: Size, + align: Align, + rng: &mut R, + ) -> InterpResult<'tcx, u64> { + // Leave some space to the previous allocation, to give it some chance to be less aligned. + // We ensure that `(self.next_base_addr + slack) % 16` is uniformly distributed. + let slack = rng.random_range(0..16); + // From next_base_addr + slack, round up to adjust for alignment. + let base_addr = + self.next_base_addr.checked_add(slack).ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + let base_addr = align_addr(base_addr, align.bytes()); + + // Remember next base address. If this allocation is zero-sized, leave a gap of at + // least 1 to avoid two allocations having the same base address. (The logic in + // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers + // need to be distinguishable!) + self.next_base_addr = base_addr + .checked_add(size.bytes().max(1)) + .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + // Even if `Size` didn't overflow, we might still have filled up the address space. + if self.next_base_addr > self.end { + throw_exhaust!(AddressSpaceFull); + } + interp_ok(base_addr) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_align_addr() { + assert_eq!(align_addr(37, 4), 40); + assert_eq!(align_addr(44, 4), 44); + } +} diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 334503d2994b1..afd8afbaeab07 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -1,15 +1,16 @@ //! This module is responsible for managing the absolute addresses that allocations are located at, //! and for casting between pointers and integers based on those addresses. +mod address_generator; mod reuse_pool; use std::cell::RefCell; -use std::cmp::max; -use rand::Rng; use rustc_abi::{Align, Size}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::ty::TyCtxt; +pub use self::address_generator::AddressGenerator; use self::reuse_pool::ReusePool; use crate::concurrency::VClock; use crate::*; @@ -49,9 +50,8 @@ pub struct GlobalStateInner { /// Whether an allocation has been exposed or not. This cannot be put /// into `AllocExtra` for the same reason as `base_addr`. exposed: FxHashSet, - /// This is used as a memory address when a new pointer is casted to an integer. It - /// is always larger than any address that was previously made part of a block. - next_base_addr: u64, + /// The generator for new addresses in a given range. + address_generator: AddressGenerator, /// The provenance to use for int2ptr casts provenance_mode: ProvenanceMode, } @@ -64,7 +64,7 @@ impl VisitProvenance for GlobalStateInner { prepared_alloc_bytes: _, reuse: _, exposed: _, - next_base_addr: _, + address_generator: _, provenance_mode: _, } = self; // Though base_addr, int_to_ptr_map, and exposed contain AllocIds, we do not want to visit them. @@ -77,14 +77,14 @@ impl VisitProvenance for GlobalStateInner { } impl GlobalStateInner { - pub fn new(config: &MiriConfig, stack_addr: u64) -> Self { + pub fn new<'tcx>(config: &MiriConfig, stack_addr: u64, tcx: TyCtxt<'tcx>) -> Self { GlobalStateInner { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), prepared_alloc_bytes: FxHashMap::default(), reuse: ReusePool::new(config), exposed: FxHashSet::default(), - next_base_addr: stack_addr, + address_generator: AddressGenerator::new(stack_addr..tcx.target_usize_max()), provenance_mode: config.provenance_mode, } } @@ -96,15 +96,6 @@ impl GlobalStateInner { } } -/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple -/// of `align` that is larger or equal to `addr` -fn align_addr(addr: u64, align: u64) -> u64 { - match addr % align { - 0 => addr, - rem => addr.strict_add(align) - rem, - } -} - impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn addr_from_alloc_id_uncached( @@ -194,34 +185,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(reuse_addr) } else { // We have to pick a fresh address. - // Leave some space to the previous allocation, to give it some chance to be less aligned. - // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - let slack = rng.random_range(0..16); - // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = global_state - .next_base_addr - .checked_add(slack) - .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = align_addr(base_addr, info.align.bytes()); - - // Remember next base address. If this allocation is zero-sized, leave a gap of at - // least 1 to avoid two allocations having the same base address. (The logic in - // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers - // need to be distinguishable!) - global_state.next_base_addr = base_addr - .checked_add(max(info.size.bytes(), 1)) - .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - // Even if `Size` didn't overflow, we might still have filled up the address space. - if global_state.next_base_addr > this.target_usize_max() { - throw_exhaust!(AddressSpaceFull); - } + let new_addr = + global_state.address_generator.generate(info.size, info.align, &mut rng)?; + // If we filled up more than half the address space, start aggressively reusing // addresses to avoid running out. - if global_state.next_base_addr > u64::try_from(this.target_isize_max()).unwrap() { + let remaining_range = global_state.address_generator.get_remaining(); + if remaining_range.start > remaining_range.end / 2 { global_state.reuse.address_space_shortage(); } - interp_ok(base_addr) + interp_ok(new_addr) } } } @@ -519,14 +493,3 @@ impl<'tcx> MiriMachine<'tcx> { }) } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_align_addr() { - assert_eq!(align_addr(37, 4), 40); - assert_eq!(align_addr(44, 4), 44); - } -} diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 8f0814a070cbf..9482769a2fc79 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -674,11 +674,13 @@ impl<'tcx> MiriMachine<'tcx> { thread_cpu_affinity .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus)); } + let alloc_addresses = + RefCell::new(alloc_addresses::GlobalStateInner::new(config, stack_addr, tcx)); MiriMachine { tcx, borrow_tracker, data_race, - alloc_addresses: RefCell::new(alloc_addresses::GlobalStateInner::new(config, stack_addr)), + alloc_addresses, // `env_vars` depends on a full interpreter so we cannot properly initialize it yet. env_vars: EnvVars::default(), main_fn_ret_place: None, From c1be740564dd4a3aaafca93539ca428223226278 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Apr 2025 08:53:50 +0200 Subject: [PATCH 134/251] Implement basic support for running Miri with GenMC. - Implement memory allocation compatible with GenMC. - Extract address generator struct from Miri's allocator. - Support thread creation and joining. - Support atomic load and store. - Support scheduling through GenMC. - Add tests for GenMC mode. - Add clang-format file for C++ code in Miri. - Update genmc-sys crate license to MIT/Apache to match GenMC dependency. - Add documentation for GenMC mode. Note: this commit depends on changes to GenMC not yet upstreamed to its official repository. Co-authored-by: Ralf Jung --- src/tools/miri/Cargo.lock | 24 +- src/tools/miri/Cargo.toml | 2 +- src/tools/miri/doc/genmc.md | 28 +- src/tools/miri/genmc-sys/.clang-format | 52 ++ src/tools/miri/genmc-sys/Cargo.toml | 8 +- src/tools/miri/genmc-sys/build.rs | 42 +- .../genmc-sys/cpp/include/MiriInterface.hpp | 274 +++++++ .../genmc-sys/cpp/include/ResultHandling.hpp | 21 + .../cpp/src/MiriInterface/EventHandling.cpp | 120 +++ .../cpp/src/MiriInterface/Exploration.cpp | 42 + .../genmc-sys/cpp/src/MiriInterface/Setup.cpp | 185 +++++ .../src/MiriInterface/ThreadManagement.cpp | 54 ++ src/tools/miri/genmc-sys/src/lib.rs | 297 ++++++- .../miri/genmc-sys/src_cpp/MiriInterface.cpp | 50 -- .../miri/genmc-sys/src_cpp/MiriInterface.hpp | 44 - src/tools/miri/src/alloc_addresses/mod.rs | 19 +- src/tools/miri/src/bin/miri.rs | 22 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 1 + src/tools/miri/src/concurrency/data_race.rs | 69 +- .../miri/src/concurrency/genmc/config.rs | 19 +- src/tools/miri/src/concurrency/genmc/dummy.rs | 120 +-- .../concurrency/genmc/global_allocations.rs | 118 +++ .../miri/src/concurrency/genmc/helper.rs | 97 +++ src/tools/miri/src/concurrency/genmc/mod.rs | 762 ++++++++++++++---- src/tools/miri/src/concurrency/genmc/run.rs | 71 ++ .../miri/src/concurrency/genmc/scheduling.rs | 69 ++ .../src/concurrency/genmc/thread_id_map.rs | 63 ++ src/tools/miri/src/concurrency/init_once.rs | 4 +- src/tools/miri/src/concurrency/mod.rs | 2 +- src/tools/miri/src/concurrency/thread.rs | 53 +- src/tools/miri/src/diagnostics.rs | 17 +- src/tools/miri/src/eval.rs | 30 +- src/tools/miri/src/lib.rs | 2 +- src/tools/miri/src/machine.rs | 7 +- src/tools/miri/src/shims/foreign_items.rs | 11 +- .../miri/src/shims/unix/linux_like/epoll.rs | 2 +- .../miri/src/shims/unix/linux_like/eventfd.rs | 2 +- .../miri/src/shims/unix/unnamed_socket.rs | 2 +- src/tools/miri/src/shims/windows/sync.rs | 2 +- .../data_race/weak_orderings.rel_rlx.stderr | 19 + .../data_race/weak_orderings.rlx_acq.stderr | 19 + .../data_race/weak_orderings.rlx_rlx.stderr | 19 + .../genmc/fail/data_race/weak_orderings.rs | 40 + .../fail/simple/2w2w_weak.relaxed4.stderr | 15 + .../fail/simple/2w2w_weak.release4.stderr | 15 + .../miri/tests/genmc/fail/simple/2w2w_weak.rs | 73 ++ .../fail/simple/2w2w_weak.sc3_rel1.stderr | 15 + .../miri/tests/genmc/pass/litmus/2cowr.rs | 51 ++ .../miri/tests/genmc/pass/litmus/2cowr.stderr | 2 + .../pass/litmus/2w2w_3sc_1rel.release1.stderr | 2 + .../pass/litmus/2w2w_3sc_1rel.release2.stderr | 2 + .../tests/genmc/pass/litmus/2w2w_3sc_1rel.rs | 54 ++ .../miri/tests/genmc/pass/litmus/2w2w_4rel.rs | 45 ++ .../tests/genmc/pass/litmus/2w2w_4rel.stderr | 2 + .../miri/tests/genmc/pass/litmus/2w2w_4sc.rs | 45 ++ .../tests/genmc/pass/litmus/2w2w_4sc.stderr | 2 + .../tests/genmc/pass/litmus/IRIW-acq-sc.rs | 64 ++ .../genmc/pass/litmus/IRIW-acq-sc.stderr | 2 + src/tools/miri/tests/genmc/pass/litmus/LB.rs | 47 ++ .../miri/tests/genmc/pass/litmus/LB.stderr | 2 + src/tools/miri/tests/genmc/pass/litmus/MP.rs | 47 ++ .../miri/tests/genmc/pass/litmus/MP.stderr | 2 + src/tools/miri/tests/genmc/pass/litmus/SB.rs | 47 ++ .../miri/tests/genmc/pass/litmus/SB.stderr | 2 + .../miri/tests/genmc/pass/litmus/corr.rs | 45 ++ .../miri/tests/genmc/pass/litmus/corr.stderr | 2 + .../miri/tests/genmc/pass/litmus/corr0.rs | 46 ++ .../miri/tests/genmc/pass/litmus/corr0.stderr | 2 + .../miri/tests/genmc/pass/litmus/corr1.rs | 58 ++ .../miri/tests/genmc/pass/litmus/corr1.stderr | 2 + .../miri/tests/genmc/pass/litmus/corr2.rs | 70 ++ .../miri/tests/genmc/pass/litmus/corr2.stderr | 2 + .../miri/tests/genmc/pass/litmus/corw.rs | 43 + .../miri/tests/genmc/pass/litmus/corw.stderr | 2 + .../miri/tests/genmc/pass/litmus/cowr.rs | 40 + .../miri/tests/genmc/pass/litmus/cowr.stderr | 2 + .../miri/tests/genmc/pass/litmus/default.rs | 47 ++ .../tests/genmc/pass/litmus/default.stderr | 2 + .../genmc/pass/litmus/detour.join.stderr | 2 + .../genmc/pass/litmus/detour.no_join.stderr | 2 + .../miri/tests/genmc/pass/litmus/detour.rs | 68 ++ .../tests/genmc/pass/litmus/fr_w_w_w_reads.rs | 54 ++ .../genmc/pass/litmus/fr_w_w_w_reads.stderr | 2 + .../miri/tests/genmc/pass/test_cxx_build.rs | 8 - .../tests/genmc/pass/test_cxx_build.stderr | 5 - src/tools/miri/tests/utils/genmc.rs | 57 ++ 86 files changed, 3572 insertions(+), 429 deletions(-) create mode 100644 src/tools/miri/genmc-sys/.clang-format create mode 100644 src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp create mode 100644 src/tools/miri/genmc-sys/cpp/include/ResultHandling.hpp create mode 100644 src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp create mode 100644 src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp create mode 100644 src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp create mode 100644 src/tools/miri/genmc-sys/cpp/src/MiriInterface/ThreadManagement.cpp delete mode 100644 src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp delete mode 100644 src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp create mode 100644 src/tools/miri/src/concurrency/genmc/global_allocations.rs create mode 100644 src/tools/miri/src/concurrency/genmc/helper.rs create mode 100644 src/tools/miri/src/concurrency/genmc/run.rs create mode 100644 src/tools/miri/src/concurrency/genmc/scheduling.rs create mode 100644 src/tools/miri/src/concurrency/genmc/thread_id_map.rs create mode 100644 src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr create mode 100644 src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr create mode 100644 src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr create mode 100644 src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rs create mode 100644 src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr create mode 100644 src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr create mode 100644 src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs create mode 100644 src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2cowr.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/LB.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/LB.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/SB.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/SB.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr0.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr0.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr1.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr1.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr2.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corr2.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corw.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/corw.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cowr.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cowr.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/default.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/default.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/detour.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr delete mode 100644 src/tools/miri/tests/genmc/pass/test_cxx_build.rs delete mode 100644 src/tools/miri/tests/genmc/pass/test_cxx_build.stderr create mode 100644 src/tools/miri/tests/utils/genmc.rs diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index ece51f2ba74af..c4280f5e87a6d 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -363,9 +363,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.161" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df" +checksum = "6c64ed3da1c337cbaae7223cdcff8b4dddf698d188cd3eaddd1116f6b0295950" dependencies = [ "cc", "cxxbridge-cmd", @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.161" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909" +checksum = "ae0a26a75a05551f5ae3d75b3557543d06682284eaa7419113162d602cb45766" dependencies = [ "cc", "codespan-reporting", @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.161" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a" +checksum = "952d408b6002b7db4b36da07c682a9cbb34f2db0efa03e976ae50a388414e16c" dependencies = [ "clap", "codespan-reporting", @@ -406,15 +406,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.161" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d" +checksum = "ccbd201b471c75c6abb6321cace706d1982d270e308b891c11a3262d320f5265" [[package]] name = "cxxbridge-macro" -version = "1.0.161" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4" +checksum = "2bea8b915bbc4cb4288f242aa7ca18b23ecc6965e4d6e7c1b07905e3fe2e0c41" dependencies = [ "indexmap", "proc-macro2", @@ -501,9 +501,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "form_urlencoded" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 91dadf78a2f72..5afde9b23d5cf 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -70,7 +70,7 @@ harness = false [features] default = ["stack-cache", "native-lib"] -genmc = ["dep:genmc-sys"] # this enables a GPL dependency! +genmc = ["dep:genmc-sys"] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] tracing = ["serde_json"] diff --git a/src/tools/miri/doc/genmc.md b/src/tools/miri/doc/genmc.md index 5aabe90b5dab2..fdbf2defe42dc 100644 --- a/src/tools/miri/doc/genmc.md +++ b/src/tools/miri/doc/genmc.md @@ -9,9 +9,7 @@ Miri-GenMC integrates that model checker into Miri. ## Usage -**IMPORTANT: The license of GenMC and thus the `genmc-sys` crate in the Miri repo is currently "GPL-3.0-or-later", so a binary produced with the `genmc` feature is subject to the requirements of the GPL. As long as that remains the case, the `genmc` feature of Miri is OFF-BY-DEFAULT and must be OFF for all Miri releases.** - -For testing/developing Miri-GenMC (while keeping in mind the licensing issues): +For testing/developing Miri-GenMC: - clone the Miri repo. - build Miri-GenMC with `./miri build --features=genmc`. - OR: install Miri-GenMC in the current system with `./miri install --features=genmc` @@ -21,6 +19,21 @@ Basic usage: MIRIFLAGS="-Zmiri-genmc" cargo miri run ``` +Note that `cargo miri test` in GenMC mode is currently not supported. + +### Supported Parameters + +- `-Zmiri-genmc`: Enable GenMC mode (not required if any other GenMC options are used). +- `-Zmiri-genmc-log=LOG_LEVEL`: Change the log level for GenMC. Default: `warning`. + - `quiet`: Disable logging. + - `error`: Print errors. + - `warning`: Print errors and warnings. + - `tip`: Print errors, warnings and tips. + - If Miri is built with debug assertions, there are additional log levels available (downgraded to `tip` without debug assertions): + - `debug1`: Print revisits considered by GenMC. + - `debug2`: Print the execution graph after every memory access. + - `debug3`: Print reads-from values considered by GenMC. + @@ -57,6 +70,15 @@ The process for obtaining them is as follows: If you place this directory inside the Miri folder, it is recommended to call it `genmc-src` as that tells `./miri fmt` to avoid formatting the Rust files inside that folder. +### Formatting the C++ code + +For formatting the C++ code we provide a `.clang-format` file in the `genmc-sys` directory. +With `clang-format` installed, run this command to format the c++ files (replace the `-i` with `--dry-run` to just see the changes.): +``` +find ./genmc-sys/cpp/ -name "*.cpp" -o -name "*.hpp" | xargs clang-format --style=file:"./genmc-sys/.clang-format" -i +``` +NOTE: this is currently not done automatically on pull requests to Miri. + diff --git a/src/tools/miri/genmc-sys/.clang-format b/src/tools/miri/genmc-sys/.clang-format new file mode 100644 index 0000000000000..669d76ea6c9bc --- /dev/null +++ b/src/tools/miri/genmc-sys/.clang-format @@ -0,0 +1,52 @@ +# .clang-format + +BasedOnStyle: LLVM +Standard: c++20 + +ColumnLimit: 100 +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortBlocksOnASingleLine: Empty +BreakBeforeBraces: Attach + +BinPackArguments: false +BinPackParameters: false +AllowAllParametersOfDeclarationOnNextLine: false +AlwaysBreakAfterReturnType: None + +# Force parameters to break and align +AlignAfterOpenBracket: BlockIndent +AllowAllArgumentsOnNextLine: false + +# Spacing around braces and parentheses +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceInEmptyBlock: false +SpacesInContainerLiterals: true +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false + +# Brace spacing for initializers +Cpp11BracedListStyle: false +SpaceBeforeCpp11BracedList: true + +# Import grouping: group standard, external, and project includes. +IncludeBlocks: Regroup +SortIncludes: true + +# Granularity: sort includes per module/file. +IncludeIsMainRegex: '([-_](test|unittest))?$' + +# Miscellaneous +SpaceAfterCStyleCast: true +SpaceBeforeParens: ControlStatements +PointerAlignment: Left +IndentCaseLabels: true +IndentWidth: 4 +TabWidth: 4 +UseTab: Never \ No newline at end of file diff --git a/src/tools/miri/genmc-sys/Cargo.toml b/src/tools/miri/genmc-sys/Cargo.toml index 95aef75afc4f5..aa6374b7b373f 100644 --- a/src/tools/miri/genmc-sys/Cargo.toml +++ b/src/tools/miri/genmc-sys/Cargo.toml @@ -1,17 +1,15 @@ [package] authors = ["Miri Team"] -# The parts in this repo are MIT OR Apache-2.0, but we are linking in -# code from https://github.com/MPI-SWS/genmc which is GPL-3.0-or-later. -license = "(MIT OR Apache-2.0) AND GPL-3.0-or-later" +license = "MIT OR Apache-2.0" name = "genmc-sys" version = "0.1.0" edition = "2024" [dependencies] -cxx = { version = "1.0.160", features = ["c++20"] } +cxx = { version = "1.0.173", features = ["c++20"] } [build-dependencies] cc = "1.2.30" cmake = "0.1.54" git2 = { version = "0.20.2", default-features = false, features = ["https"] } -cxx-build = { version = "1.0.160", features = ["parallel"] } +cxx-build = { version = "1.0.173", features = ["parallel"] } diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs index f20e0e8d525fc..af42c70431bf0 100644 --- a/src/tools/miri/genmc-sys/build.rs +++ b/src/tools/miri/genmc-sys/build.rs @@ -26,9 +26,9 @@ mod downloading { use super::GENMC_DOWNLOAD_PATH; /// The GenMC repository the we get our commit from. - pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/MPI-SWS/genmc.git"; + pub(crate) const GENMC_GITHUB_URL: &str = "https://gitlab.inf.ethz.ch/public-plf/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "3438dd2c1202cd4a47ed7881d099abf23e4167ab"; + pub(crate) const GENMC_COMMIT: &str = "af9cc9ccd5d412b16defc35dbf36571c63a19c76"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); @@ -176,6 +176,11 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { /// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs fn compile_cpp_dependencies(genmc_path: &Path) { + // Give each step a separate build directory to prevent interference. + let out_dir = PathBuf::from(std::env::var("OUT_DIR").as_deref().unwrap()); + let genmc_build_dir = out_dir.join("genmc"); + let interface_build_dir = out_dir.join("miri_genmc"); + // Part 1: // Compile the GenMC library using cmake. @@ -186,8 +191,11 @@ fn compile_cpp_dependencies(genmc_path: &Path) { let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); let mut config = cmake::Config::new(cmakelists_path); - config.profile(GENMC_CMAKE_PROFILE); - config.define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); + config + .always_configure(false) // We don't need to reconfigure on subsequent compilation runs. + .out_dir(genmc_build_dir) + .profile(GENMC_CMAKE_PROFILE) + .define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); // The actual compilation happens here: let genmc_install_dir = config.build(); @@ -210,6 +218,13 @@ fn compile_cpp_dependencies(genmc_path: &Path) { // These definitions are parsed into a cmake list and then printed to the config.h file, so they are ';' separated. let definitions = llvm_definitions.split(";"); + let cpp_files = [ + "./cpp/src/MiriInterface/EventHandling.cpp", + "./cpp/src/MiriInterface/Exploration.cpp", + "./cpp/src/MiriInterface/Setup.cpp", + "./cpp/src/MiriInterface/ThreadManagement.cpp", + ]; + let mut bridge = cxx_build::bridge("src/lib.rs"); // FIXME(genmc,cmake): Remove once the GenMC debug setting is available in the config.h file. if enable_genmc_debug { @@ -223,9 +238,9 @@ fn compile_cpp_dependencies(genmc_path: &Path) { .std("c++23") .include(genmc_include_dir) .include(llvm_include_dirs) - .include("./src_cpp") - .file("./src_cpp/MiriInterface.hpp") - .file("./src_cpp/MiriInterface.cpp") + .include("./cpp/include") + .files(&cpp_files) + .out_dir(interface_build_dir) .compile("genmc_interop"); // Link the Rust-C++ interface library generated by cxx_build: @@ -233,15 +248,8 @@ fn compile_cpp_dependencies(genmc_path: &Path) { } fn main() { - // Make sure we don't accidentally distribute a binary with GPL code. - if option_env!("RUSTC_STAGE").is_some() { - panic!( - "genmc should not be enabled in the rustc workspace since it includes a GPL dependency" - ); - } - // Select which path to use for the GenMC repo: - let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") { + let genmc_path = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") { let genmc_src_path = PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path"); assert!( @@ -249,6 +257,8 @@ fn main() { "GENMC_SRC_PATH={} does not exist!", genmc_src_path.display() ); + // Rebuild files in the given path change. + println!("cargo::rerun-if-changed={}", genmc_src_path.display()); genmc_src_path } else { downloading::download_genmc() @@ -263,5 +273,5 @@ fn main() { // cloned (since cargo detects that as a file modification). println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); println!("cargo::rerun-if-changed=./src"); - println!("cargo::rerun-if-changed=./src_cpp"); + println!("cargo::rerun-if-changed=./cpp"); } diff --git a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp new file mode 100644 index 0000000000000..4484f0b73caec --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp @@ -0,0 +1,274 @@ +#ifndef GENMC_MIRI_INTERFACE_HPP +#define GENMC_MIRI_INTERFACE_HPP + +// CXX.rs generated headers: +#include "rust/cxx.h" + +// GenMC generated headers: +#include "config.h" + +// Miri `genmc-sys/src_cpp` headers: +#include "ResultHandling.hpp" + +// GenMC headers: +#include "ExecutionGraph/EventLabel.hpp" +#include "Static/ModuleID.hpp" +#include "Support/MemOrdering.hpp" +#include "Support/RMWOps.hpp" +#include "Verification/Config.hpp" +#include "Verification/GenMCDriver.hpp" + +// C++ headers: +#include +#include +#include +#include + +/**** Types available to both Rust and C++ ****/ + +struct GenmcParams; +enum class LogLevel : std::uint8_t; + +struct GenmcScalar; +struct SchedulingResult; +struct LoadResult; +struct StoreResult; + +// GenMC uses `int` for its thread IDs. +using ThreadId = int; + +/// Set the log level for GenMC. +/// +/// # Safety +/// +/// This function is not thread safe, since it writes to the global, mutable, non-atomic `logLevel` +/// variable. Any GenMC function may read from `logLevel` unsynchronized. +/// The safest way to use this function is to set the log level exactly once before first calling +/// `create_handle`. +/// Never calling this function is safe, GenMC will fall back to its default log level. +/* unsafe */ void set_log_level_raw(LogLevel log_level); + +struct MiriGenmcShim : private GenMCDriver { + + public: + MiriGenmcShim(std::shared_ptr conf, Mode mode /* = VerificationMode{} */) + : GenMCDriver(std::move(conf), nullptr, mode) {} + + /// Create a new `MiriGenmcShim`, which wraps a `GenMCDriver`. + /// + /// # Safety + /// + /// This function is marked as unsafe since the `logLevel` global variable is non-atomic. + /// This function should not be called in an unsynchronized way with `set_log_level_raw`, + /// since this function and any methods on the returned `MiriGenmcShim` may read the + /// `logLevel`, causing a data race. The safest way to use these functions is to call + /// `set_log_level_raw` once, and only then start creating handles. There should not be any + /// other (safe) way to create a `MiriGenmcShim`. + /* unsafe */ static auto create_handle(const GenmcParams& params) + -> std::unique_ptr; + + virtual ~MiriGenmcShim() {} + + /**** Execution start/end handling ****/ + + // This function must be called at the start of any execution, before any events are + // reported to GenMC. + void handle_execution_start(); + // This function must be called at the end of any execution, even if an error was found + // during the execution. + // Returns `null`, or a string containing an error message if an error occured. + std::unique_ptr handle_execution_end(); + + /***** Functions for handling events encountered during program execution. *****/ + + /**** Memory access handling ****/ + + [[nodiscard]] LoadResult handle_load( + ThreadId thread_id, + uint64_t address, + uint64_t size, + MemOrdering ord, + GenmcScalar old_val + ); + [[nodiscard]] StoreResult handle_store( + ThreadId thread_id, + uint64_t address, + uint64_t size, + GenmcScalar value, + GenmcScalar old_val, + MemOrdering ord + ); + + /**** Memory (de)allocation ****/ + auto handle_malloc(ThreadId thread_id, uint64_t size, uint64_t alignment) -> uint64_t; + void handle_free(ThreadId thread_id, uint64_t address); + + /**** Thread management ****/ + void handle_thread_create(ThreadId thread_id, ThreadId parent_id); + void handle_thread_join(ThreadId thread_id, ThreadId child_id); + void handle_thread_finish(ThreadId thread_id, uint64_t ret_val); + void handle_thread_kill(ThreadId thread_id); + + /***** Exploration related functionality *****/ + + /** Ask the GenMC scheduler for a new thread to schedule and return whether the execution is + * finished, blocked, or can continue. + * Updates the next instruction kind for the given thread id. */ + auto schedule_next(const int curr_thread_id, const ActionKind curr_thread_next_instr_kind) + -> SchedulingResult; + + /** + * Check whether there are more executions to explore. + * If there are more executions, this method prepares for the next execution and returns + * `true`. Returns true if there are no more executions to explore. */ + auto is_exploration_done() -> bool { + return GenMCDriver::done(); + } + + /**** Result querying functionality. ****/ + + // NOTE: We don't want to share the `VerificationResult` type with the Rust side, since it + // is very large, uses features that CXX.rs doesn't support and may change as GenMC changes. + // Instead, we only use the result on the C++ side, and only expose these getter function to + // the Rust side. + + // Note that CXX.rs doesn't support returning a C++ string to Rust by value, + // it must be behind an indirection like a `unique_ptr` (tested with CXX 1.0.170). + + /// Get the number of blocked executions encountered by GenMC (cast into a fixed with + /// integer) + auto get_blocked_execution_count() const -> uint64_t { + return static_cast(getResult().exploredBlocked); + } + + /// Get the number of executions explored by GenMC (cast into a fixed with integer) + auto get_explored_execution_count() const -> uint64_t { + return static_cast(getResult().explored); + } + + /// Get all messages that GenMC produced (errors, warnings), combined into one string. + auto get_result_message() const -> std::unique_ptr { + return std::make_unique(getResult().message); + } + + /// If an error occurred, return a string describing the error, otherwise, return `nullptr`. + auto get_error_string() const -> std::unique_ptr { + const auto& result = GenMCDriver::getResult(); + if (result.status.has_value()) + return format_error(result.status.value()); + return nullptr; + } + + private: + /** Increment the event index in the given thread by 1 and return the new event. */ + [[nodiscard]] inline auto inc_pos(ThreadId tid) -> Event { + ERROR_ON(tid >= threads_action_.size(), "ThreadId out of bounds"); + return ++threads_action_[tid].event; + } + /** Decrement the event index in the given thread by 1 and return the new event. */ + inline auto dec_pos(ThreadId tid) -> Event { + ERROR_ON(tid >= threads_action_.size(), "ThreadId out of bounds"); + return --threads_action_[tid].event; + } + + /** + * Helper function for loads that need to reset the event counter when no value is returned. + * Same syntax as `GenMCDriver::handleLoad`, but this takes a thread id instead of an Event. + * Automatically calls `inc_pos` and `dec_pos` where needed for the given thread. + */ + template + auto handle_load_reset_if_none(ThreadId tid, Ts&&... params) -> HandleResult { + const auto pos = inc_pos(tid); + const auto ret = GenMCDriver::handleLoad(pos, std::forward(params)...); + // If we didn't get a value, we have to reset the index of the current thread. + if (!std::holds_alternative(ret)) { + dec_pos(tid); + } + return ret; + } + + /** + * GenMC uses the term `Action` to refer to a struct of: + * - `ActionKind`, storing whether the next instruction in a thread may be a load + * - `Event`, storing the most recent event index added for a thread + * + * Here we store the "action" for each thread. In particular we use this to assign event + * indices, since GenMC expects us to do that. + */ + std::vector threads_action_; +}; + +/// Get the bit mask that GenMC expects for global memory allocations. +/// FIXME(genmc): currently we use `get_global_alloc_static_mask()` to ensure the +/// `SAddr::staticMask` constant is consistent between Miri and GenMC, but if +/// https://github.com/dtolnay/cxx/issues/1051 is fixed we could share the constant +/// directly. +constexpr auto get_global_alloc_static_mask() -> uint64_t { + return SAddr::staticMask; +} + +// CXX.rs generated headers: +// NOTE: this must be included *after* `MiriGenmcShim` and all the other types we use are defined, +// otherwise there will be compilation errors due to missing definitions. +#include "genmc-sys/src/lib.rs.h" + +/**** Result handling ****/ +// NOTE: these must come after the cxx_bridge generated code, since that contains the actual +// definitions of these types. + +namespace GenmcScalarExt { +inline GenmcScalar uninit() { + return GenmcScalar { + /* value: */ 0, + /* is_init: */ false, + }; +} + +inline GenmcScalar from_sval(SVal sval) { + return GenmcScalar { + /* value: */ sval.get(), + /* is_init: */ true, + }; +} + +inline SVal to_sval(GenmcScalar scalar) { + ERROR_ON(!scalar.is_init, "Cannot convert an uninitialized `GenmcScalar` into an `SVal`\n"); + return SVal(scalar.value); +} +} // namespace GenmcScalarExt + +namespace LoadResultExt { +inline LoadResult no_value() { + return LoadResult { + /* error: */ std::unique_ptr(nullptr), + /* has_value: */ false, + /* read_value: */ GenmcScalarExt::uninit(), + }; +} + +inline LoadResult from_value(SVal read_value) { + return LoadResult { /* error: */ std::unique_ptr(nullptr), + /* has_value: */ true, + /* read_value: */ GenmcScalarExt::from_sval(read_value) }; +} + +inline LoadResult from_error(std::unique_ptr error) { + return LoadResult { /* error: */ std::move(error), + /* has_value: */ false, + /* read_value: */ GenmcScalarExt::uninit() }; +} +} // namespace LoadResultExt + +namespace StoreResultExt { +inline StoreResult ok(bool is_coherence_order_maximal_write) { + return StoreResult { /* error: */ std::unique_ptr(nullptr), + is_coherence_order_maximal_write }; +} + +inline StoreResult from_error(std::unique_ptr error) { + return StoreResult { /* error: */ std::move(error), + /* is_coherence_order_maximal_write: */ false }; +} +} // namespace StoreResultExt + +#endif /* GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/tools/miri/genmc-sys/cpp/include/ResultHandling.hpp b/src/tools/miri/genmc-sys/cpp/include/ResultHandling.hpp new file mode 100644 index 0000000000000..189f32e6f513d --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/include/ResultHandling.hpp @@ -0,0 +1,21 @@ +#ifndef GENMC_RESULT_HANDLING_HPP +#define GENMC_RESULT_HANDLING_HPP + +// CXX.rs generated headers: +#include "rust/cxx.h" + +// GenMC headers: +#include "Verification/VerificationError.hpp" + +#include + +/** Information about an error, formatted as a string to avoid having to share an error enum and + * printing functionality with the Rust side. */ +static auto format_error(VerificationError err) -> std::unique_ptr { + auto buf = std::string(); + auto s = llvm::raw_string_ostream(buf); + s << err; + return std::make_unique(s.str()); +} + +#endif /* GENMC_RESULT_HANDLING_HPP */ diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp new file mode 100644 index 0000000000000..7d8f0b16b49ab --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp @@ -0,0 +1,120 @@ +/** This file contains functionality related to handling events encountered + * during an execution, such as loads, stores or memory (de)allocation. */ + +#include "MiriInterface.hpp" + +// CXX.rs generated headers: +#include "genmc-sys/src/lib.rs.h" + +// GenMC headers: +#include "ADT/value_ptr.hpp" +#include "ExecutionGraph/EventLabel.hpp" +#include "ExecutionGraph/LoadAnnotation.hpp" +#include "Runtime/InterpreterEnumAPI.hpp" +#include "Static/ModuleID.hpp" +#include "Support/ASize.hpp" +#include "Support/Error.hpp" +#include "Support/Logger.hpp" +#include "Support/MemAccess.hpp" +#include "Support/RMWOps.hpp" +#include "Support/SAddr.hpp" +#include "Support/SVal.hpp" +#include "Support/ThreadInfo.hpp" +#include "Support/Verbosity.hpp" +#include "Verification/GenMCDriver.hpp" +#include "Verification/MemoryModel.hpp" + +// C++ headers: +#include +#include +#include +#include + +/**** Memory access handling ****/ + +[[nodiscard]] auto MiriGenmcShim::handle_load( + ThreadId thread_id, + uint64_t address, + uint64_t size, + MemOrdering ord, + GenmcScalar old_val +) -> LoadResult { + // `type` is only used for printing. + const auto type = AType::Unsigned; + const auto ret = handle_load_reset_if_none( + thread_id, + ord, + SAddr(address), + ASize(size), + type + ); + + if (const auto* err = std::get_if(&ret)) + return LoadResultExt::from_error(format_error(*err)); + const auto* ret_val = std::get_if(&ret); + if (ret_val == nullptr) + ERROR("Unimplemented: load returned unexpected result."); + return LoadResultExt::from_value(*ret_val); +} + +[[nodiscard]] auto MiriGenmcShim::handle_store( + ThreadId thread_id, + uint64_t address, + uint64_t size, + GenmcScalar value, + GenmcScalar old_val, + MemOrdering ord +) -> StoreResult { + const auto pos = inc_pos(thread_id); + const auto ret = GenMCDriver::handleStore( + pos, + ord, + SAddr(address), + ASize(size), + /* type */ AType::Unsigned, // `type` is only used for printing. + GenmcScalarExt::to_sval(value), + EventDeps() + ); + + if (const auto* err = std::get_if(&ret)) + return StoreResultExt::from_error(format_error(*err)); + if (!std::holds_alternative(ret)) + ERROR("store returned unexpected result"); + + // FIXME(genmc,mixed-accesses): Use the value that GenMC returns from handleStore (once + // available). + const auto& g = getExec().getGraph(); + return StoreResultExt::ok( + /* is_coherence_order_maximal_write */ g.co_max(SAddr(address))->getPos() == pos + ); +} + +/**** Memory (de)allocation ****/ + +auto MiriGenmcShim::handle_malloc(ThreadId thread_id, uint64_t size, uint64_t alignment) + -> uint64_t { + const auto pos = inc_pos(thread_id); + + // These are only used for printing and features Miri-GenMC doesn't support (yet). + const auto storage_duration = StorageDuration::SD_Heap; + // Volatile, as opposed to "persistent" (i.e., non-volatile memory that persists over reboots) + const auto storage_type = StorageType::ST_Volatile; + const auto address_space = AddressSpace::AS_User; + + const SVal ret_val = GenMCDriver::handleMalloc( + pos, + size, + alignment, + storage_duration, + storage_type, + address_space, + EventDeps() + ); + return ret_val.get(); +} + +void MiriGenmcShim::handle_free(ThreadId thread_id, uint64_t address) { + const auto pos = inc_pos(thread_id); + GenMCDriver::handleFree(pos, SAddr(address), EventDeps()); + // FIXME(genmc): add error handling once GenMC returns errors from `handleFree` +} diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp new file mode 100644 index 0000000000000..c51b59e865170 --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp @@ -0,0 +1,42 @@ +/** This file contains functionality related to exploration, such as scheduling. */ + +#include "MiriInterface.hpp" + +// CXX.rs generated headers: +#include "genmc-sys/src/lib.rs.h" + +// GenMC headers: +#include "Support/Error.hpp" +#include "Support/Verbosity.hpp" + +// C++ headers: +#include + +auto MiriGenmcShim::schedule_next( + const int curr_thread_id, + const ActionKind curr_thread_next_instr_kind +) -> SchedulingResult { + // The current thread is the only one where the `kind` could have changed since we last made + // a scheduling decision. + threads_action_[curr_thread_id].kind = curr_thread_next_instr_kind; + + if (const auto result = GenMCDriver::scheduleNext(threads_action_)) + return SchedulingResult { ExecutionState::Ok, static_cast(result.value()) }; + if (GenMCDriver::isExecutionBlocked()) + return SchedulingResult { ExecutionState::Blocked, 0 }; + return SchedulingResult { ExecutionState::Finished, 0 }; +} + +/**** Execution start/end handling ****/ + +void MiriGenmcShim::handle_execution_start() { + threads_action_.clear(); + threads_action_.push_back(Action(ActionKind::Load, Event::getInit())); + GenMCDriver::handleExecutionStart(); +} + +auto MiriGenmcShim::handle_execution_end() -> std::unique_ptr { + // FIXME(genmc): add error handling once GenMC returns an error here. + GenMCDriver::handleExecutionEnd(); + return {}; +} diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp new file mode 100644 index 0000000000000..7194ed02da432 --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp @@ -0,0 +1,185 @@ +/** This file contains functionality related to creation of the GenMCDriver, + * including translating settings set by Miri. */ + +#include "MiriInterface.hpp" + +// CXX.rs generated headers: +#include "genmc-sys/src/lib.rs.h" + +// GenMC headers: +#include "Support/Error.hpp" +#include "Support/Verbosity.hpp" +#include "Verification/InterpreterCallbacks.hpp" + +// C++ headers: +#include + +/** + * Translate the Miri-GenMC `LogLevel` to the GenMC `VerbosityLevel`. + * Downgrade any debug options to `Tip` if `ENABLE_GENMC_DEBUG` is not enabled. + */ +static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel { + switch (log_level) { + case LogLevel::Quiet: + return VerbosityLevel::Quiet; + case LogLevel::Error: + return VerbosityLevel::Error; + case LogLevel::Warning: + return VerbosityLevel::Warning; + case LogLevel::Tip: + return VerbosityLevel::Tip; +#ifdef ENABLE_GENMC_DEBUG + case LogLevel::Debug1Revisits: + return VerbosityLevel::Debug1; + case LogLevel::Debug2MemoryAccesses: + return VerbosityLevel::Debug2; + case LogLevel::Debug3ReadsFrom: + return VerbosityLevel::Debug3; +#else + // Downgrade to `Tip` if the debug levels are not available. + case LogLevel::Debug1Revisits: + case LogLevel::Debug2MemoryAccesses: + case LogLevel::Debug3ReadsFrom: + return VerbosityLevel::Tip; +#endif + default: + WARN_ONCE( + "unknown-log-level", + "Unknown `LogLevel`, defaulting to `VerbosityLevel::Tip`." + ); + return VerbosityLevel::Tip; + } +} + +/* unsafe */ void set_log_level_raw(LogLevel log_level) { + // The `logLevel` is a static, non-atomic variable. + // It should never be changed if `MiriGenmcShim` still exists, since any of its methods may read + // the `logLevel`, otherwise it may cause data races. + logLevel = to_genmc_verbosity_level(log_level); +} + +/* unsafe */ auto MiriGenmcShim::create_handle(const GenmcParams& params) + -> std::unique_ptr { + auto conf = std::make_shared(); + + // Set whether GenMC should print execution graphs after every explored/blocked execution. + // FIXME(genmc): pass these settings from Miri. + conf->printExecGraphs = false; + conf->printBlockedExecs = false; + + // `1024` is the default value that GenMC uses. + // If any thread has at least this many events, a warning/tip will be printed. + // + // Miri produces a lot more events than GenMC, so the graph size warning triggers on almost + // all programs. The current value is large enough so the warning is not be triggered by any + // reasonable programs. + // FIXME(genmc): The emitted warning mentions features not supported by Miri ('--unroll' + // parameter). + // FIXME(genmc): A more appropriate limit should be chosen once the warning is useful for + // Miri. + conf->warnOnGraphSize = 1024 * 1024; + + // We only support the RC11 memory model for Rust. + conf->model = ModelType::RC11; + + // This prints the seed that GenMC picks for randomized scheduling during estimation mode. + conf->printRandomScheduleSeed = params.print_random_schedule_seed; + + // FIXME(genmc): supporting IPR requires annotations for `assume` and `spinloops`. + conf->ipr = false; + // FIXME(genmc): supporting BAM requires `Barrier` support + detecting whether return value + // of barriers are used. + conf->disableBAM = true; + + // Instruction caching could help speed up verification by filling the graph from cache, if + // the list of values read by all load events in a thread have been seen before. Combined + // with not replaying completed threads, this can also reducing the amount of Mir + // interpretation required by Miri. With the current setup, this would be incorrect, since + // Miri doesn't give GenMC the actual values read by non-atomic reads. + conf->instructionCaching = false; + // Many of Miri's checks work under the assumption that threads are only executed in an + // order that could actually happen during a normal execution. Formally, this means that + // replaying an execution needs to respect the po-rf-relation of the executiongraph (po == + // program-order, rf == reads-from). This means, any event in the graph, when replayed, must + // happen after any events that happen before it in the same graph according to the program + // code, and all (non-atomic) reads must happen after the write event they read from. + // + // Not replaying completed threads means any read event from that thread never happens in + // Miri's memory, so this would only work if there are never any non-atomic reads from any + // value written by the skipped thread. + conf->replayCompletedThreads = true; + + // FIXME(genmc): implement symmetry reduction. + ERROR_ON( + params.do_symmetry_reduction, + "Symmetry reduction is currently unsupported in GenMC mode." + ); + conf->symmetryReduction = params.do_symmetry_reduction; + + // FIXME(genmc): expose this setting to Miri (useful for testing Miri-GenMC). + conf->schedulePolicy = SchedulePolicy::WF; + + // Set the mode used for this driver, either estimation or verification. + // FIXME(genmc): implement estimation mode. + const auto mode = GenMCDriver::Mode(GenMCDriver::VerificationMode {}); + + // Running Miri-GenMC without race detection is not supported. + // Disabling this option also changes the behavior of the replay scheduler to only schedule + // at atomic operations, which is required with Miri. This happens because Miri can generate + // multiple GenMC events for a single MIR terminator. Without this option, the scheduler + // might incorrectly schedule an atomic MIR terminator because the first event it creates is + // a non-atomic (e.g., `StorageLive`). + conf->disableRaceDetection = false; + + // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory + // that is allowed to leak and memory that is not. + conf->warnUnfreedMemory = false; + + // FIXME(genmc,error handling): This function currently exits on error, but will return an + // error value in the future. The return value should be checked once this change is made. + checkConfig(*conf); + + // Create the actual driver and Miri-GenMC communication shim. + auto driver = std::make_unique(std::move(conf), mode); + + // FIXME(genmc,HACK): Until a proper solution is implemented in GenMC, these callbacks will + // allow Miri to return information about global allocations and override uninitialized memory + // checks for non-atomic loads (Miri handles those without GenMC, so the error would be wrong). + auto interpreter_callbacks = InterpreterCallbacks { + // Miri already ensures that memory accesses are valid, so this check doesn't matter. + // We check that the address is static, but skip checking if it is part of an actual + // allocation. + /* isStaticallyAllocated: */ [](SAddr addr) { return addr.isStatic(); }, + // FIXME(genmc,error reporting): Once a proper a proper API for passing such information is + // implemented in GenMC, Miri should use it to improve the produced error messages. + /* getStaticName: */ [](SAddr addr) { return "[UNKNOWN STATIC]"; }, + // This function is called to get the initial value stored at the given address. + // + // From a Miri perspective, this API doesn't work very well: most memory starts out + // "uninitialized"; + // only statics have an initial value. And their initial value is just a sequence of bytes, + // but GenMC + // expect this to be already split into separate atomic variables. So we return a dummy + // value. + // This value should never be visible to the interpreted program. + // GenMC does not understand uninitialized memory the same way Miri does, which may cause + // this function to be called. The returned value can be visible to Miri or the user: + // - Printing the execution graph may contain this value in place of uninitialized values. + // FIXME(genmc): NOTE: printing the execution graph is not yet implemented. + // - Non-atomic loads may return this value, but Miri ignores values of non-atomic loads. + // - Atomic loads will *not* see this value once mixed atomic-non-atomic support is added. + // Currently, atomic loads can see this value, unless initialized by an *atomic* store. + // FIXME(genmc): update this comment once mixed atomic-non-atomic support is added. + // + // FIXME(genmc): implement proper support for uninitialized memory in GenMC. Ideally, the + // initial value getter would return an `optional`, since the memory location may be + // uninitialized. + /* initValGetter: */ [](const AAccess& a) { return SVal(0xDEAD); }, + // Miri serves non-atomic loads from its own memory and these GenMC checks are wrong in + // that case. This should no longer be required with proper mixed-size access support. + /* skipUninitLoadChecks: */ [](MemOrdering ord) { return ord == MemOrdering::NotAtomic; }, + }; + driver->setInterpCallbacks(std::move(interpreter_callbacks)); + + return driver; +} diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/ThreadManagement.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/ThreadManagement.cpp new file mode 100644 index 0000000000000..352d27adc3e8b --- /dev/null +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/ThreadManagement.cpp @@ -0,0 +1,54 @@ + +/** This file contains functionality related thread management (creation, finishing, join, etc.) */ + +#include "MiriInterface.hpp" + +// CXX.rs generated headers: +#include "genmc-sys/src/lib.rs.h" + +// GenMC headers: +#include "Support/Error.hpp" +#include "Support/Verbosity.hpp" + +// C++ headers: +#include + +void MiriGenmcShim::handle_thread_create(ThreadId thread_id, ThreadId parent_id) { + // NOTE: The threadCreate event happens in the parent: + const auto pos = inc_pos(parent_id); + // FIXME(genmc): for supporting symmetry reduction, these will need to be properly set: + const unsigned fun_id = 0; + const SVal arg = SVal(0); + const ThreadInfo child_info = ThreadInfo { thread_id, parent_id, fun_id, arg }; + + // NOTE: Default memory ordering (`Release`) used here. + const auto child_tid = GenMCDriver::handleThreadCreate(pos, child_info, EventDeps()); + // Sanity check the thread id, which is the index in the `threads_action_` array. + BUG_ON(child_tid != thread_id || child_tid <= 0 || child_tid != threads_action_.size()); + threads_action_.push_back(Action(ActionKind::Load, Event(child_tid, 0))); +} + +void MiriGenmcShim::handle_thread_join(ThreadId thread_id, ThreadId child_id) { + // The thread join event happens in the parent. + const auto pos = inc_pos(thread_id); + + // NOTE: Default memory ordering (`Acquire`) used here. + const auto ret = GenMCDriver::handleThreadJoin(pos, child_id, EventDeps()); + // If the join failed, decrease the event index again: + if (!std::holds_alternative(ret)) { + dec_pos(thread_id); + } + + // NOTE: Thread return value is ignored, since Miri doesn't need it. +} + +void MiriGenmcShim::handle_thread_finish(ThreadId thread_id, uint64_t ret_val) { + const auto pos = inc_pos(thread_id); + // NOTE: Default memory ordering (`Release`) used here. + GenMCDriver::handleThreadFinish(pos, SVal(ret_val)); +} + +void MiriGenmcShim::handle_thread_kill(ThreadId thread_id) { + const auto pos = inc_pos(thread_id); + GenMCDriver::handleThreadKill(pos); +} diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs index ab46d729ea167..406c90809fcd5 100644 --- a/src/tools/miri/genmc-sys/src/lib.rs +++ b/src/tools/miri/genmc-sys/src/lib.rs @@ -1,17 +1,90 @@ +use std::str::FromStr; +use std::sync::OnceLock; + +pub use cxx::UniquePtr; + pub use self::ffi::*; +/// Defined in "genmc/src/Support/SAddr.hpp". +/// The first bit of all global addresses must be set to `1`. +/// This means the mask, interpreted as an address, is the lower bound of where the global address space starts. +/// +/// FIXME(genmc): rework this if non-64bit support is added to GenMC (the current allocation scheme only allows for 64bit addresses). +/// FIXME(genmc): currently we use `get_global_alloc_static_mask()` to ensure the constant is consistent between Miri and GenMC, +/// but if https://github.com/dtolnay/cxx/issues/1051 is fixed we could share the constant directly. +pub const GENMC_GLOBAL_ADDRESSES_MASK: u64 = 1 << 63; + +/// GenMC thread ids are C++ type `int`, which is equivalent to Rust's `i32` on most platforms. +/// The main thread always has thread id 0. +pub const GENMC_MAIN_THREAD_ID: i32 = 0; + +/// Changing GenMC's log level is not thread safe, so we limit it to only be set once to prevent any data races. +/// This value will be initialized when the first `MiriGenmcShim` is created. +static GENMC_LOG_LEVEL: OnceLock = OnceLock::new(); + +// Create a new handle to the GenMC model checker. +// The first call to this function determines the log level of GenMC, any future call with a different log level will panic. +pub fn create_genmc_driver_handle( + params: &GenmcParams, + genmc_log_level: LogLevel, +) -> UniquePtr { + // SAFETY: Only setting the GenMC log level once is guaranteed by the `OnceLock`. + // No other place calls `set_log_level_raw`, so the `logLevel` value in GenMC will not change once we initialize it once. + // All functions that use GenMC's `logLevel` can only be accessed in safe Rust through a `MiriGenmcShim`. + // There is no way to get `MiriGenmcShim` other than through `create_handle`, and we only call it *after* setting the log level, preventing any possible data races. + assert_eq!( + &genmc_log_level, + GENMC_LOG_LEVEL.get_or_init(|| { + unsafe { set_log_level_raw(genmc_log_level) }; + genmc_log_level + }), + "Attempt to change the GenMC log level after it was already set" + ); + unsafe { MiriGenmcShim::create_handle(params) } +} + +impl GenmcScalar { + pub const UNINIT: Self = Self { value: 0, is_init: false }; + + pub const fn from_u64(value: u64) -> Self { + Self { value, is_init: true } + } +} + impl Default for GenmcParams { fn default() -> Self { - Self { - print_random_schedule_seed: false, - do_symmetry_reduction: false, - // FIXME(GenMC): Add defaults for remaining parameters - } + Self { print_random_schedule_seed: false, do_symmetry_reduction: false } + } +} + +impl Default for LogLevel { + fn default() -> Self { + // FIXME(genmc): set `Tip` by default once the GenMC tips are relevant to Miri. + Self::Warning + } +} + +impl FromStr for LogLevel { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + Ok(match s { + "quiet" => LogLevel::Quiet, + "error" => LogLevel::Error, + "warning" => LogLevel::Warning, + "tip" => LogLevel::Tip, + "debug1" => LogLevel::Debug1Revisits, + "debug2" => LogLevel::Debug2MemoryAccesses, + "debug3" => LogLevel::Debug3ReadsFrom, + _ => return Err("invalid log level"), + }) } } #[cxx::bridge] mod ffi { + /**** Types shared between Miri/Rust and Miri/C++ through cxx_bridge: ****/ + /// Parameters that will be given to GenMC for setting up the model checker. /// (The fields of this struct are visible to both Rust and C++) #[derive(Clone, Debug)] @@ -20,11 +93,221 @@ mod ffi { pub do_symmetry_reduction: bool, // FIXME(GenMC): Add remaining parameters. } + + /// This is mostly equivalent to GenMC `VerbosityLevel`, but the debug log levels are always present (not conditionally compiled based on `ENABLE_GENMC_DEBUG`). + /// We add this intermediate type to prevent changes to the GenMC log-level from breaking the Miri + /// build, and to have a stable type for the C++-Rust interface, independent of `ENABLE_GENMC_DEBUG`. + #[derive(Debug)] + enum LogLevel { + /// Disable *all* logging (including error messages on a crash). + Quiet, + /// Log errors. + Error, + /// Log errors and warnings. + Warning, + /// Log errors, warnings and tips. + Tip, + /// Debug print considered revisits. + /// Downgraded to `Tip` if `GENMC_DEBUG` is not enabled. + Debug1Revisits, + /// Print the execution graph after every memory access. + /// Also includes the previous debug log level. + /// Downgraded to `Tip` if `GENMC_DEBUG` is not enabled. + Debug2MemoryAccesses, + /// Print reads-from values considered by GenMC. + /// Also includes the previous debug log level. + /// Downgraded to `Tip` if `GENMC_DEBUG` is not enabled. + Debug3ReadsFrom, + } + + /// This type corresponds to `Option` (or `std::optional`), where `SVal` is the type that GenMC uses for storing values. + /// CXX doesn't support `std::optional` currently, so we need to use an extra `bool` to define whether this value is initialized or not. + #[derive(Debug, Clone, Copy)] + struct GenmcScalar { + value: u64, + is_init: bool, + } + + #[must_use] + #[derive(Debug, Clone, Copy)] + enum ExecutionState { + Ok, + Blocked, + Finished, + } + + #[must_use] + #[derive(Debug)] + struct SchedulingResult { + exec_state: ExecutionState, + next_thread: i32, + } + + #[must_use] + #[derive(Debug)] + struct LoadResult { + /// If not null, contains the error encountered during the handling of the load. + error: UniquePtr, + /// Indicates whether a value was read or not. + has_value: bool, + /// The value that was read. Should not be used if `has_value` is `false`. + read_value: GenmcScalar, + } + + #[must_use] + #[derive(Debug)] + struct StoreResult { + /// If not null, contains the error encountered during the handling of the store. + error: UniquePtr, + /// `true` if the write should also be reflected in Miri's memory representation. + is_coherence_order_maximal_write: bool, + } + + /**** Types shared between Miri/Rust and GenMC/C++ through cxx_bridge: ****/ + + #[derive(Debug)] + /// Corresponds to GenMC's type with the same name. + /// Should only be modified if changed by GenMC. + enum ActionKind { + /// Any Mir terminator that's atomic and has load semantics. + Load, + /// Anything that's not a `Load`. + NonLoad, + } + + #[derive(Debug)] + /// Corresponds to GenMC's type with the same name. + /// Should only be modified if changed by GenMC. + enum MemOrdering { + NotAtomic = 0, + Relaxed = 1, + // We skip 2 in case we support consume. + Acquire = 3, + Release = 4, + AcquireRelease = 5, + SequentiallyConsistent = 6, + } + + // # Safety + // + // This block is unsafe to allow defining safe methods inside. + // + // `get_global_alloc_static_mask` is safe since it just returns a constant. + // All methods on `MiriGenmcShim` are safe by the correct usage of the two unsafe functions + // `set_log_level_raw` and `MiriGenmcShim::create_handle`. + // See the doc comment on those two functions for their safety requirements. unsafe extern "C++" { include!("MiriInterface.hpp"); - type MiriGenMCShim; + /**** Types shared between Miri/Rust and Miri/C++: ****/ + type MiriGenmcShim; + + /**** Types shared between Miri/Rust and GenMC/C++: ****/ + type ActionKind; + type MemOrdering; + + /// Set the log level for GenMC. + /// + /// # Safety + /// + /// This function is not thread safe, since it writes to the global, mutable, non-atomic `logLevel` variable. + /// Any GenMC function may read from `logLevel` unsynchronized. + /// The safest way to use this function is to set the log level exactly once before first calling `create_handle`. + /// Never calling this function is safe, GenMC will fall back to its default log level. + unsafe fn set_log_level_raw(log_level: LogLevel); + + /// Create a new `MiriGenmcShim`, which wraps a `GenMCDriver`. + /// + /// # Safety + /// + /// This function is marked as unsafe since the `logLevel` global variable is non-atomic. + /// This function should not be called in an unsynchronized way with `set_log_level_raw`, since + /// this function and any methods on the returned `MiriGenmcShim` may read the `logLevel`, + /// causing a data race. + /// The safest way to use these functions is to call `set_log_level_raw` once, and only then + /// start creating handles. + /// There should not be any other (safe) way to create a `MiriGenmcShim`. + #[Self = "MiriGenmcShim"] + unsafe fn create_handle(params: &GenmcParams) -> UniquePtr; + /// Get the bit mask that GenMC expects for global memory allocations. + fn get_global_alloc_static_mask() -> u64; + + /// This function must be called at the start of any execution, before any events are reported to GenMC. + fn handle_execution_start(self: Pin<&mut MiriGenmcShim>); + /// This function must be called at the end of any execution, even if an error was found during the execution. + /// Returns `null`, or a string containing an error message if an error occured. + fn handle_execution_end(self: Pin<&mut MiriGenmcShim>) -> UniquePtr; + + /***** Functions for handling events encountered during program execution. *****/ + + /**** Memory access handling ****/ + fn handle_load( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + address: u64, + size: u64, + memory_ordering: MemOrdering, + old_value: GenmcScalar, + ) -> LoadResult; + fn handle_store( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + address: u64, + size: u64, + value: GenmcScalar, + old_value: GenmcScalar, + memory_ordering: MemOrdering, + ) -> StoreResult; + + /**** Memory (de)allocation ****/ + fn handle_malloc( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + size: u64, + alignment: u64, + ) -> u64; + fn handle_free(self: Pin<&mut MiriGenmcShim>, thread_id: i32, address: u64); + + /**** Thread management ****/ + fn handle_thread_create(self: Pin<&mut MiriGenmcShim>, thread_id: i32, parent_id: i32); + fn handle_thread_join(self: Pin<&mut MiriGenmcShim>, thread_id: i32, child_id: i32); + fn handle_thread_finish(self: Pin<&mut MiriGenmcShim>, thread_id: i32, ret_val: u64); + fn handle_thread_kill(self: Pin<&mut MiriGenmcShim>, thread_id: i32); + + /***** Exploration related functionality *****/ + + /// Ask the GenMC scheduler for a new thread to schedule and + /// return whether the execution is finished, blocked, or can continue. + /// Updates the next instruction kind for the given thread id. + fn schedule_next( + self: Pin<&mut MiriGenmcShim>, + curr_thread_id: i32, + curr_thread_next_instr_kind: ActionKind, + ) -> SchedulingResult; + + /// Check whether there are more executions to explore. + /// If there are more executions, this method prepares for the next execution and returns `true`. + fn is_exploration_done(self: Pin<&mut MiriGenmcShim>) -> bool; + + /**** Result querying functionality. ****/ + + // NOTE: We don't want to share the `VerificationResult` type with the Rust side, since it + // is very large, uses features that CXX.rs doesn't support and may change as GenMC changes. + // Instead, we only use the result on the C++ side, and only expose these getter function to + // the Rust side. + // Each `GenMCDriver` contains one `VerificationResult`, and each `MiriGenmcShim` contains on `GenMCDriver`. + // GenMC builds up the content of the `struct VerificationResult` over the course of an exploration, + // but it's safe to look at it at any point, since it is only accessible through exactly one `MiriGenmcShim`. + // All these functions for querying the result can be safely called repeatedly and at any time, + // though the results may be incomplete if called before `handle_execution_end`. - fn createGenmcHandle(config: &GenmcParams) -> UniquePtr; + /// Get the number of blocked executions encountered by GenMC (cast into a fixed with integer) + fn get_blocked_execution_count(self: &MiriGenmcShim) -> u64; + /// Get the number of executions explored by GenMC (cast into a fixed with integer) + fn get_explored_execution_count(self: &MiriGenmcShim) -> u64; + /// Get all messages that GenMC produced (errors, warnings), combined into one string. + fn get_result_message(self: &MiriGenmcShim) -> UniquePtr; + /// If an error occurred, return a string describing the error, otherwise, return `nullptr`. + fn get_error_string(self: &MiriGenmcShim) -> UniquePtr; } } diff --git a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp deleted file mode 100644 index 0827bb3d40746..0000000000000 --- a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "MiriInterface.hpp" - -#include "genmc-sys/src/lib.rs.h" - -auto MiriGenMCShim::createHandle(const GenmcParams &config) - -> std::unique_ptr -{ - auto conf = std::make_shared(); - - // Miri needs all threads to be replayed, even fully completed ones. - conf->replayCompletedThreads = true; - - // We only support the RC11 memory model for Rust. - conf->model = ModelType::RC11; - - conf->printRandomScheduleSeed = config.print_random_schedule_seed; - - // FIXME(genmc): disable any options we don't support currently: - conf->ipr = false; - conf->disableBAM = true; - conf->instructionCaching = false; - - ERROR_ON(config.do_symmetry_reduction, "Symmetry reduction is currently unsupported in GenMC mode."); - conf->symmetryReduction = config.do_symmetry_reduction; - - // FIXME(genmc): Should there be a way to change this option from Miri? - conf->schedulePolicy = SchedulePolicy::WF; - - // FIXME(genmc): implement estimation mode: - conf->estimate = false; - conf->estimationMax = 1000; - const auto mode = conf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{}) - : GenMCDriver::Mode(GenMCDriver::VerificationMode{}); - - // Running Miri-GenMC without race detection is not supported. - // Disabling this option also changes the behavior of the replay scheduler to only schedule at atomic operations, which is required with Miri. - // This happens because Miri can generate multiple GenMC events for a single MIR terminator. Without this option, - // the scheduler might incorrectly schedule an atomic MIR terminator because the first event it creates is a non-atomic (e.g., `StorageLive`). - conf->disableRaceDetection = false; - - // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory - // that is allowed to leak and memory that is not. - conf->warnUnfreedMemory = false; - - // FIXME(genmc): check config: - // checkConfigOptions(*conf); - - auto driver = std::make_unique(std::move(conf), mode); - return driver; -} diff --git a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp b/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp deleted file mode 100644 index e55522ef41897..0000000000000 --- a/src/tools/miri/genmc-sys/src_cpp/MiriInterface.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef GENMC_MIRI_INTERFACE_HPP -#define GENMC_MIRI_INTERFACE_HPP - -#include "rust/cxx.h" - -#include "config.h" - -#include "Config/Config.hpp" -#include "Verification/GenMCDriver.hpp" - -#include - -/**** Types available to Miri ****/ - -// Config struct defined on the Rust side and translated to C++ by cxx.rs: -struct GenmcParams; - -struct MiriGenMCShim : private GenMCDriver -{ - -public: - MiriGenMCShim(std::shared_ptr conf, Mode mode /* = VerificationMode{} */) - : GenMCDriver(std::move(conf), nullptr, mode) - { - std::cerr << "C++: GenMC handle created!" << std::endl; - } - - virtual ~MiriGenMCShim() - { - std::cerr << "C++: GenMC handle destroyed!" << std::endl; - } - - static std::unique_ptr createHandle(const GenmcParams &config); -}; - -/**** Functions available to Miri ****/ - -// NOTE: CXX doesn't support exposing static methods to Rust currently, so we expose this function instead. -static inline auto createGenmcHandle(const GenmcParams &config) -> std::unique_ptr -{ - return MiriGenMCShim::createHandle(config); -} - -#endif /* GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index afd8afbaeab07..5d94a1f4138a6 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -34,6 +34,8 @@ pub struct GlobalStateInner { /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset /// from the base address, and we need to find the `AllocId` it belongs to. This is not the /// *full* inverse of `base_addr`; dead allocations have been removed. + /// Note that in GenMC mode, dead allocations are *not* removed -- and also, addresses are never + /// reused. This lets us use the address as a cross-execution-stable identifier for an allocation. int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and @@ -123,7 +125,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miri's address assignment leaks state across thread boundaries, which is incompatible // with GenMC execution. So we instead let GenMC assign addresses to allocations. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?; + let addr = + genmc_ctx.handle_alloc(this, alloc_id, info.size, info.align, memory_kind)?; return interp_ok(addr); } @@ -180,7 +183,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.active_thread(), ) { if let Some(clock) = clock { - this.acquire_clock(&clock); + this.acquire_clock(&clock)?; } interp_ok(reuse_addr) } else { @@ -242,7 +245,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(this.is_alloc_live(alloc_id)); + // In GenMC mode, we keep all allocations, so this check doesn't apply there. + if this.machine.data_race.as_genmc_ref().is_none() { + debug_assert!(this.is_alloc_live(alloc_id)); + } Some(alloc_id) } else { None @@ -459,6 +465,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> MiriMachine<'tcx> { pub fn free_alloc_id(&mut self, dead_id: AllocId, size: Size, align: Align, kind: MemoryKind) { + // In GenMC mode, we can't remove dead allocation info since such pointers can + // still be stored in atomics and we need this info to convert GenMC pointers to Miri pointers. + // `global_state.reuse` is also unused so we can just skip this entire function. + if self.data_race.as_genmc_ref().is_some() { + return; + } + let global_state = self.alloc_addresses.get_mut(); let rng = self.rng.get_mut(); diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index ae1b25f8857a0..b96359316b921 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -39,7 +39,7 @@ use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use miri::{ BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, - ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, + ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, run_genmc_mode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -187,9 +187,18 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } if let Some(_genmc_config) = &config.genmc_config { - let _genmc_ctx = Rc::new(GenmcCtx::new(&config)); + let eval_entry_once = |genmc_ctx: Rc| { + miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx)) + }; + + // FIXME(genmc): add estimation mode here. - todo!("GenMC mode not yet implemented"); + let return_code = run_genmc_mode(&config, eval_entry_once, tcx).unwrap_or_else(|| { + tcx.dcx().abort_if_errors(); + rustc_driver::EXIT_FAILURE + }); + + exit(return_code); }; if let Some(many_seeds) = self.many_seeds.take() { @@ -735,9 +744,11 @@ fn main() { // Validate settings for data race detection and GenMC mode. if miri_config.genmc_config.is_some() { if !miri_config.data_race_detector { - fatal_error!("Cannot disable data race detection in GenMC mode (currently)"); + fatal_error!("Cannot disable data race detection in GenMC mode"); } else if !miri_config.weak_memory_emulation { fatal_error!("Cannot disable weak memory emulation in GenMC mode"); + } else if !miri_config.native_lib.is_empty() { + fatal_error!("native-lib not supported in GenMC mode."); } if miri_config.borrow_tracker.is_some() { eprintln!( @@ -745,6 +756,9 @@ fn main() { ); miri_config.borrow_tracker = None; } + // We enable fixed scheduling so Miri doesn't randomly yield before a terminator, which anyway + // would be a NOP in GenMC mode. + miri_config.fixed_scheduling = true; } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector { fatal_error!( "Weak memory emulation cannot be enabled when the data race detector is disabled" diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 2977efaae04ac..5fe00ab02c4b9 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -740,6 +740,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { if let Some(access) = access { assert_eq!(access, AccessKind::Write); // Make sure the data race model also knows about this. + // FIXME(genmc): Ensure this is still done in GenMC mode. Check for other places where GenMC may need to be informed. if let Some(data_race) = alloc_extra.data_race.as_vclocks_mut() { data_race.write( alloc_id, diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 38d76f5cf73b7..19d37a691d90c 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -719,8 +719,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Only metadata on the location itself is used. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - let old_val = None; + let old_val = this.run_for_validation_ref(|this| this.read_scalar(place)).discard_err(); return genmc_ctx.atomic_load( this, place.ptr().addr(), @@ -751,11 +750,22 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // The program didn't actually do a read, so suppress the memory access hooks. // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! - let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); + let old_val = this.run_for_validation_ref(|this| this.read_scalar(dest)).discard_err(); + // Inform GenMC about the atomic store. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?; + if genmc_ctx.atomic_store( + this, + dest.ptr().addr(), + dest.layout.size, + val, + old_val, + atomic, + )? { + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + this.allow_data_races_mut(|this| this.write_scalar(val, dest))?; + } return interp_ok(()); } this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; @@ -779,7 +789,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic rmw operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_rmw_op( this, place.ptr().addr(), @@ -787,8 +796,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { atomic, (op, not), rhs.to_scalar(), + old.to_scalar(), )?; - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -818,14 +830,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic atomic exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - let (old_val, _is_success) = genmc_ctx.atomic_exchange( + let (old_val, new_val) = genmc_ctx.atomic_exchange( this, place.ptr().addr(), place.layout.size, new, atomic, + old, )?; + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(old_val); } @@ -851,7 +868,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic min/max operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_min_max_op( this, place.ptr().addr(), @@ -860,8 +876,13 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { min, old.layout.backend_repr.is_signed(), rhs.to_scalar(), + old.to_scalar(), )?; - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -903,15 +924,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; - // Failure ordering cannot be stronger than success ordering, therefore first attempt - // to read with the failure ordering and if successful then try again with the success - // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // Inform GenMC about the atomic atomic compare exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( + let (old_value, new_value, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( this, place.ptr().addr(), place.layout.size, @@ -920,11 +938,15 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { success, fail, can_fail_spuriously, + old.to_scalar(), )?; - if cmpxchg_success { - this.allow_data_races_mut(|this| this.write_scalar(new, place))?; + + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if let Some(new_value) = new_value { + this.allow_data_races_mut(|this| this.write_scalar(new_value, place))?; } - return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success))); + return interp_ok(Immediate::ScalarPair(old_value, Scalar::from_bool(cmpxchg_success))); } // `binary_op` will bail if either of them is not a scalar. @@ -985,11 +1007,16 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Acquire the given clock into the current thread, establishing synchronization with /// the moment when that clock snapshot was taken via `release_clock`. - fn acquire_clock(&self, clock: &VClock) { + fn acquire_clock(&self, clock: &VClock) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock(clock, &this.machine.threads); + match &this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(_genmc_ctx) => + throw_unsup_format!("acquire_clock is not (yet) supported in GenMC mode."), + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.acquire_clock(clock, &this.machine.threads), } + interp_ok(()) } } diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs index c56adab90fe2b..66116d5cf23c7 100644 --- a/src/tools/miri/src/concurrency/genmc/config.rs +++ b/src/tools/miri/src/concurrency/genmc/config.rs @@ -1,13 +1,14 @@ -use super::GenmcParams; +use genmc_sys::{GenmcParams, LogLevel}; /// Configuration for GenMC mode. /// The `params` field is shared with the C++ side. /// The remaining options are kept on the Rust side. #[derive(Debug, Default, Clone)] pub struct GenmcConfig { + /// Parameters sent to the C++ side to create a new handle to the GenMC model checker. pub(super) params: GenmcParams, - do_estimation: bool, - // FIXME(GenMC): add remaining options. + /// The log level for GenMC. + pub(super) log_level: LogLevel, } impl GenmcConfig { @@ -29,7 +30,15 @@ impl GenmcConfig { if trimmed_arg.is_empty() { return Ok(()); // this corresponds to "-Zmiri-genmc" } - // FIXME(GenMC): implement remaining parameters. - todo!(); + let genmc_config = genmc_config.as_mut().unwrap(); + let Some(trimmed_arg) = trimmed_arg.strip_prefix("-") else { + return Err(format!("Invalid GenMC argument \"-Zmiri-genmc{trimmed_arg}\"")); + }; + if let Some(log_level) = trimmed_arg.strip_prefix("log=") { + genmc_config.log_level = log_level.parse()?; + } else { + return Err(format!("Invalid GenMC argument: \"-Zmiri-genmc-{trimmed_arg}\"")); + } + Ok(()) } } diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs index 79d27c4be1591..1960ef37cc9f3 100644 --- a/src/tools/miri/src/concurrency/genmc/dummy.rs +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -1,30 +1,49 @@ -#![allow(unused)] - use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{InterpCx, InterpResult}; +use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult}; use rustc_middle::mir; +pub use self::run::run_genmc_mode; use crate::{ - AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriMachine, Scalar, + ThreadId, ThreadManager, VisitProvenance, VisitWith, }; +#[derive(Clone, Copy, Debug)] +pub enum ExitType { + MainThreadFinish, + ExitCalled, +} + #[derive(Debug)] pub struct GenmcCtx {} #[derive(Debug, Default, Clone)] pub struct GenmcConfig {} -impl GenmcCtx { - pub fn new(_miri_config: &MiriConfig) -> Self { - unreachable!() +mod run { + use std::rc::Rc; + + use rustc_middle::ty::TyCtxt; + + use crate::{GenmcCtx, MiriConfig}; + + pub fn run_genmc_mode<'tcx>( + _config: &MiriConfig, + _eval_entry: impl Fn(Rc) -> Option, + _tcx: TyCtxt<'tcx>, + ) -> Option { + unreachable!(); } +} + +impl GenmcCtx { + // We don't provide the `new` function in the dummy module. - pub fn get_stuck_execution_count(&self) -> usize { + pub fn get_blocked_execution_count(&self) -> usize { unreachable!() } - pub fn print_genmc_graph(&self) { + pub fn get_explored_execution_count(&self) -> usize { unreachable!() } @@ -34,17 +53,6 @@ impl GenmcCtx { /**** Memory access handling ****/ - pub(crate) fn handle_execution_start(&self) { - unreachable!() - } - - pub(crate) fn handle_execution_end<'tcx>( - &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - ) -> Result<(), String> { - unreachable!() - } - pub(super) fn set_ongoing_action_data_race_free(&self, _enable: bool) { unreachable!() } @@ -67,8 +75,9 @@ impl GenmcCtx { _address: Size, _size: Size, _value: Scalar, + _old_value: Option, _ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx, bool> { unreachable!() } @@ -76,7 +85,7 @@ impl GenmcCtx { &self, _machine: &MiriMachine<'tcx>, _ordering: AtomicFenceOrd, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } @@ -86,22 +95,24 @@ impl GenmcCtx { _address: Size, _size: Size, _ordering: AtomicRwOrd, - (rmw_op, not): (mir::BinOp, bool), + (_rmw_op, _not): (mir::BinOp, bool), _rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { unreachable!() } pub(crate) fn atomic_min_max_op<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - ordering: AtomicRwOrd, - min: bool, - is_signed: bool, - rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + _min: bool, + _is_signed: bool, + _rhs_scalar: Scalar, + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { unreachable!() } @@ -112,7 +123,8 @@ impl GenmcCtx { _size: Size, _rhs_scalar: Scalar, _ordering: AtomicRwOrd, - ) -> InterpResult<'tcx, (Scalar, bool)> { + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { unreachable!() } @@ -126,7 +138,8 @@ impl GenmcCtx { _success: AtomicRwOrd, _fail: AtomicReadOrd, _can_fail_spuriously: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option, bool)> { unreachable!() } @@ -135,7 +148,7 @@ impl GenmcCtx { _machine: &MiriMachine<'tcx>, _address: Size, _size: Size, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } @@ -144,7 +157,7 @@ impl GenmcCtx { _machine: &MiriMachine<'tcx>, _address: Size, _size: Size, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } @@ -152,7 +165,8 @@ impl GenmcCtx { pub(crate) fn handle_alloc<'tcx>( &self, - _machine: &MiriMachine<'tcx>, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _alloc_id: AllocId, _size: Size, _alignment: Align, _memory_kind: MemoryKind, @@ -163,11 +177,10 @@ impl GenmcCtx { pub(crate) fn handle_dealloc<'tcx>( &self, _machine: &MiriMachine<'tcx>, + _alloc_id: AllocId, _address: Size, - _size: Size, - _align: Align, _kind: MemoryKind, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } @@ -176,8 +189,10 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, _threads: &ThreadManager<'tcx>, + _start_routine: crate::Pointer, + _func_arg: &crate::ImmTy<'tcx>, _new_thread_id: ThreadId, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } @@ -185,24 +200,26 @@ impl GenmcCtx { &self, _active_thread_id: ThreadId, _child_thread_id: ThreadId, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx> { unreachable!() } - pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) { + pub(crate) fn handle_thread_finish<'tcx>(&self, _threads: &ThreadManager<'tcx>) { unreachable!() } - pub(crate) fn handle_thread_finish<'tcx>( + pub(crate) fn handle_exit<'tcx>( &self, - _threads: &ThreadManager<'tcx>, - ) -> InterpResult<'tcx, ()> { + _thread: ThreadId, + _exit_code: i32, + _exit_type: ExitType, + ) -> InterpResult<'tcx> { unreachable!() } /**** Scheduling functionality ****/ - pub(crate) fn schedule_thread<'tcx>( + pub fn schedule_thread<'tcx>( &self, _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, ) -> InterpResult<'tcx, ThreadId> { @@ -211,6 +228,7 @@ impl GenmcCtx { /**** Blocking instructions ****/ + #[allow(unused)] pub(crate) fn handle_verifier_assume<'tcx>( &self, _machine: &MiriMachine<'tcx>, @@ -229,7 +247,7 @@ impl VisitProvenance for GenmcCtx { impl GenmcConfig { pub fn parse_arg( _genmc_config: &mut Option, - trimmed_arg: &str, + _trimmed_arg: &str, ) -> Result<(), String> { if cfg!(feature = "genmc") { Err(format!("GenMC is disabled in this build of Miri")) @@ -237,8 +255,4 @@ impl GenmcConfig { Err(format!("GenMC is not supported on this target")) } } - - pub fn should_print_graph(&self, _rep: usize) -> bool { - unreachable!() - } } diff --git a/src/tools/miri/src/concurrency/genmc/global_allocations.rs b/src/tools/miri/src/concurrency/genmc/global_allocations.rs new file mode 100644 index 0000000000000..272f8d2484038 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/global_allocations.rs @@ -0,0 +1,118 @@ +use std::collections::hash_map::Entry; +use std::sync::RwLock; + +use genmc_sys::{GENMC_GLOBAL_ADDRESSES_MASK, get_global_alloc_static_mask}; +use rand::SeedableRng; +use rand::rngs::StdRng; +use rustc_const_eval::interpret::{AllocId, AllocInfo, InterpResult, interp_ok}; +use rustc_data_structures::fx::FxHashMap; +use tracing::debug; + +use crate::alloc_addresses::AddressGenerator; + +#[derive(Debug)] +struct GlobalStateInner { + /// The base address for each *global* allocation. + base_addr: FxHashMap, + /// We use the same address generator that Miri uses in normal operation. + address_generator: AddressGenerator, + /// The address generator needs an Rng to randomize the offsets between allocations. + /// We don't use the `MiriMachine` Rng since this is global, cross-machine state. + rng: StdRng, +} + +/// Allocator for global memory in GenMC mode. +/// Miri doesn't discover all global allocations statically like LLI does for GenMC. +/// The existing global memory allocator in GenMC doesn't support this, so we take over these allocations. +/// Global allocations need to be in a specific address range, with the lower limit given by the `GENMC_GLOBAL_ADDRESSES_MASK` constant. +/// +/// Every global allocation must have the same addresses across all executions of a single program. +/// Therefore there is only 1 global allocator, and it syncs new globals across executions, even if they are explored in parallel. +#[derive(Debug)] +pub struct GlobalAllocationHandler(RwLock); + +impl GlobalAllocationHandler { + /// Create a new global address generator with a given max address `last_addr` + /// (corresponding to the highest address available on the target platform, unless another limit exists). + /// No addresses higher than this will be allocated. + /// Will panic if the given address limit is too small to allocate any addresses. + pub fn new(last_addr: u64) -> GlobalAllocationHandler { + assert_eq!(GENMC_GLOBAL_ADDRESSES_MASK, get_global_alloc_static_mask()); + assert_ne!(GENMC_GLOBAL_ADDRESSES_MASK, 0); + // FIXME(genmc): Remove if non-64bit targets are supported. + assert!( + GENMC_GLOBAL_ADDRESSES_MASK < last_addr, + "only 64bit platforms are currently supported (highest address {last_addr:#x} <= minimum global address {GENMC_GLOBAL_ADDRESSES_MASK:#x})." + ); + Self(RwLock::new(GlobalStateInner { + base_addr: FxHashMap::default(), + address_generator: AddressGenerator::new(GENMC_GLOBAL_ADDRESSES_MASK..last_addr), + // FIXME(genmc): We could provide a way to changes this seed, to allow for different global addresses. + rng: StdRng::seed_from_u64(0), + })) + } +} + +impl GlobalStateInner { + fn global_allocate_addr<'tcx>( + &mut self, + alloc_id: AllocId, + info: AllocInfo, + ) -> InterpResult<'tcx, u64> { + let entry = match self.base_addr.entry(alloc_id) { + Entry::Occupied(occupied_entry) => { + // Looks like some other thread allocated this for us + // between when we released the read lock and aquired the write lock, + // so we just return that value. + return interp_ok(*occupied_entry.get()); + } + Entry::Vacant(vacant_entry) => vacant_entry, + }; + + // This allocation does not have a base address yet, pick or reuse one. + // We are not in native lib mode (incompatible with GenMC mode), so we control the addresses ourselves. + let new_addr = self.address_generator.generate(info.size, info.align, &mut self.rng)?; + + // Cache the address for future use. + entry.insert(new_addr); + + interp_ok(new_addr) + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Allocate a new address for the given alloc id, or return the cached address. + /// Each alloc id is assigned one unique allocation which will not change if this function is called again with the same alloc id. + fn get_global_allocation_address( + &self, + global_allocation_handler: &GlobalAllocationHandler, + alloc_id: AllocId, + ) -> InterpResult<'tcx, u64> { + let this = self.eval_context_ref(); + let info = this.get_alloc_info(alloc_id); + + let global_state = global_allocation_handler.0.read().unwrap(); + if let Some(base_addr) = global_state.base_addr.get(&alloc_id) { + debug!( + "GenMC: address for global with alloc id {alloc_id:?} was cached: {base_addr} == {base_addr:#x}" + ); + return interp_ok(*base_addr); + } + + // We need to upgrade to a write lock. `std::sync::RwLock` doesn't support this, so we drop the guard and lock again + // Note that another thread might allocate the address while the `RwLock` is unlocked, but we handle this case in the allocation function. + drop(global_state); + let mut global_state = global_allocation_handler.0.write().unwrap(); + // With the write lock, we can safely allocate an address only once per `alloc_id`. + let new_addr = global_state.global_allocate_addr(alloc_id, info)?; + debug!("GenMC: global with alloc id {alloc_id:?} got address: {new_addr} == {new_addr:#x}"); + assert_eq!( + GENMC_GLOBAL_ADDRESSES_MASK, + new_addr & GENMC_GLOBAL_ADDRESSES_MASK, + "Global address allocated outside global address space." + ); + + interp_ok(new_addr) + } +} diff --git a/src/tools/miri/src/concurrency/genmc/helper.rs b/src/tools/miri/src/concurrency/genmc/helper.rs new file mode 100644 index 0000000000000..b70ca8faadfed --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/helper.rs @@ -0,0 +1,97 @@ +use genmc_sys::MemOrdering; +use rustc_abi::Size; +use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_middle::ty::ScalarInt; +use tracing::debug; + +use super::GenmcScalar; +use crate::{AtomicReadOrd, AtomicWriteOrd, MiriInterpCx, Scalar, throw_unsup_format}; + +/// Maximum size memory access in bytes that GenMC supports. +pub(super) const MAX_ACCESS_SIZE: u64 = 8; + +/// This function is used to split up a large memory access into aligned, non-overlapping chunks of a limited size. +/// Returns an iterator over the chunks, yielding `(base address, size)` of each chunk, ordered by address. +pub fn split_access(address: Size, size: Size) -> impl Iterator { + let start_address = address.bytes(); + let end_address = start_address + size.bytes(); + + let start_address_aligned = start_address.next_multiple_of(MAX_ACCESS_SIZE); + let end_address_aligned = (end_address / MAX_ACCESS_SIZE) * MAX_ACCESS_SIZE; // prev_multiple_of + + debug!( + "GenMC: splitting NA memory access into {MAX_ACCESS_SIZE} byte chunks: {}B + {} * {MAX_ACCESS_SIZE}B + {}B = {size:?}", + start_address_aligned - start_address, + (end_address_aligned - start_address_aligned) / MAX_ACCESS_SIZE, + end_address - end_address_aligned, + ); + + // FIXME(genmc): could make remaining accesses powers-of-2, instead of 1 byte. + let start_chunks = (start_address..start_address_aligned).map(|address| (address, 1)); + let aligned_chunks = (start_address_aligned..end_address_aligned) + .step_by(MAX_ACCESS_SIZE.try_into().unwrap()) + .map(|address| (address, MAX_ACCESS_SIZE)); + let end_chunks = (end_address_aligned..end_address).map(|address| (address, 1)); + + start_chunks.chain(aligned_chunks).chain(end_chunks) +} + +/// Inverse function to `scalar_to_genmc_scalar`. +/// +/// Convert a Miri `Scalar` to a `GenmcScalar`. +/// To be able to restore pointer provenance from a `GenmcScalar`, the base address of the allocation of the pointer is also stored in the `GenmcScalar`. +/// We cannot use the `AllocId` instead of the base address, since Miri has no control over the `AllocId`, and it may change across executions. +/// Pointers with `Wildcard` provenance are not supported. +pub fn scalar_to_genmc_scalar<'tcx>( + _ecx: &MiriInterpCx<'tcx>, + scalar: Scalar, +) -> InterpResult<'tcx, GenmcScalar> { + interp_ok(match scalar { + rustc_const_eval::interpret::Scalar::Int(scalar_int) => { + // FIXME(genmc): Add u128 support once GenMC supports it. + let value: u64 = scalar_int.to_uint(scalar_int.size()).try_into().unwrap(); + GenmcScalar { value, is_init: true } + } + rustc_const_eval::interpret::Scalar::Ptr(_pointer, _size) => + throw_unsup_format!( + "FIXME(genmc): Implement sending pointers (with provenance) to GenMC." + ), + }) +} + +/// Inverse function to `scalar_to_genmc_scalar`. +/// +/// Convert a `GenmcScalar` back into a Miri `Scalar`. +/// For pointers, attempt to convert the stored base address of their allocation back into an `AllocId`. +pub fn genmc_scalar_to_scalar<'tcx>( + _ecx: &MiriInterpCx<'tcx>, + scalar: GenmcScalar, + size: Size, +) -> InterpResult<'tcx, Scalar> { + // FIXME(genmc): Add GenmcScalar to Miri Pointer conversion. + + // NOTE: GenMC always returns 64 bit values, and the upper bits are not yet truncated. + // FIXME(genmc): GenMC should be doing the truncation, not Miri. + let (value_scalar_int, _got_truncated) = ScalarInt::truncate_from_uint(scalar.value, size); + interp_ok(Scalar::Int(value_scalar_int)) +} + +impl AtomicReadOrd { + pub(super) fn to_genmc(self) -> MemOrdering { + match self { + AtomicReadOrd::Relaxed => MemOrdering::Relaxed, + AtomicReadOrd::Acquire => MemOrdering::Acquire, + AtomicReadOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +impl AtomicWriteOrd { + pub(super) fn to_genmc(self) -> MemOrdering { + match self { + AtomicWriteOrd::Relaxed => MemOrdering::Relaxed, + AtomicWriteOrd::Release => MemOrdering::Release, + AtomicWriteOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs index 3617775e27eaf..b5d20a439c01c 100644 --- a/src/tools/miri/src/concurrency/genmc/mod.rs +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -1,78 +1,171 @@ -#![allow(unused)] // FIXME(GenMC): remove this +use std::cell::{Cell, RefCell}; +use std::sync::Arc; -use std::cell::Cell; - -use genmc_sys::{GenmcParams, createGenmcHandle}; +use genmc_sys::{ + GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, MemOrdering, MiriGenmcShim, UniquePtr, + create_genmc_driver_handle, +}; use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; -use rustc_middle::mir; - +use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult, interp_ok}; +use rustc_middle::{mir, throw_machine_stop, throw_ub_format, throw_unsup_format}; +// FIXME(genmc,tracing): Implement some work-around for enabling debug/trace level logging (currently disabled statically in rustc). +use tracing::{debug, info}; + +use self::global_allocations::{EvalContextExt as _, GlobalAllocationHandler}; +use self::helper::{MAX_ACCESS_SIZE, genmc_scalar_to_scalar, scalar_to_genmc_scalar}; +use self::thread_id_map::ThreadIdMap; +use crate::concurrency::genmc::helper::split_access; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, + MiriMachine, MiriMemoryKind, Scalar, TerminationInfo, ThreadId, ThreadManager, VisitProvenance, + VisitWith, }; mod config; +mod global_allocations; +mod helper; +mod run; +pub(crate) mod scheduling; +mod thread_id_map; pub use self::config::GenmcConfig; +pub use self::run::run_genmc_mode; -// FIXME(GenMC): add fields -pub struct GenmcCtx { - /// Some actions Miri does are allowed to cause data races. - /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set. +#[derive(Clone, Copy, Debug)] +pub enum ExitType { + MainThreadFinish, + ExitCalled, +} + +/// The exit status of a program. +/// GenMC must store this if a thread exits while any others can still run. +/// The other threads must also be explored before the program is terminated. +#[derive(Clone, Copy, Debug)] +struct ExitStatus { + exit_code: i32, + exit_type: ExitType, +} + +impl ExitStatus { + fn do_leak_check(self) -> bool { + matches!(self.exit_type, ExitType::MainThreadFinish) + } +} + +/// State that is reset at the start of every execution. +#[derive(Debug, Default)] +struct PerExecutionState { + /// Thread id management, such as mapping between Miri `ThreadId` and GenMC's thread ids, or selecting GenMC thread ids. + thread_id_manager: RefCell, + + /// A flag to indicate that we should not forward non-atomic accesses to genmc, e.g. because we + /// are executing an atomic operation. allow_data_races: Cell, + + /// The exit status of the program. We keep running other threads even after `exit` to ensure + /// we cover all possible executions. + /// `None` if no thread has called `exit` and the main thread isn't finished yet. + exit_status: Cell>, } -impl GenmcCtx { - /// Create a new `GenmcCtx` from a given config. - pub fn new(miri_config: &MiriConfig) -> Self { - let genmc_config = miri_config.genmc_config.as_ref().unwrap(); +impl PerExecutionState { + fn reset(&self) { + self.allow_data_races.replace(false); + self.thread_id_manager.borrow_mut().reset(); + self.exit_status.set(None); + } +} - let handle = createGenmcHandle(&genmc_config.params); - assert!(!handle.is_null()); +#[derive(Debug)] +struct GlobalState { + /// Keep track of global allocations, to ensure they keep the same address across different executions, even if the order of allocations changes. + /// The `AllocId` for globals is stable across executions, so we can use it as an identifier. + global_allocations: GlobalAllocationHandler, +} - eprintln!("Miri: GenMC handle creation successful!"); +impl GlobalState { + fn new(target_usize_max: u64) -> Self { + Self { global_allocations: GlobalAllocationHandler::new(target_usize_max) } + } +} - drop(handle); - eprintln!("Miri: Dropping GenMC handle successful!"); +/// The main interface with GenMC. +/// Each `GenmcCtx` owns one `MiriGenmcShim`, which owns one `GenMCDriver` (the GenMC model checker). +/// For each GenMC run (estimation or verification), one or more `GenmcCtx` can be created (one per Miri thread). +/// However, for now, we only ever have one `GenmcCtx` per run. +/// +/// In multithreading, each worker thread has its own `GenmcCtx`, which will have their results combined in the end. +/// FIXME(genmc): implement multithreading. +/// +/// Some data is shared across all `GenmcCtx` in the same run, namely data for global allocation handling. +/// Globals must be allocated in a consistent manner, i.e., each global allocation must have the same address in each execution. +/// +/// Some state is reset between each execution in the same run. +pub struct GenmcCtx { + /// Handle to the GenMC model checker. + handle: RefCell>, - // FIXME(GenMC): implement - std::process::exit(0); + /// State that is reset at the start of every execution. + exec_state: PerExecutionState, + + /// State that persists across executions. + /// All `GenmcCtx` in one verification step share this state. + global_state: Arc, +} + +/// GenMC Context creation and administrative / query actions +impl GenmcCtx { + /// Create a new `GenmcCtx` from a given config. + fn new(miri_config: &MiriConfig, global_state: Arc) -> Self { + let genmc_config = miri_config.genmc_config.as_ref().unwrap(); + let handle = + RefCell::new(create_genmc_driver_handle(&genmc_config.params, genmc_config.log_level)); + Self { handle, exec_state: Default::default(), global_state } } - pub fn get_stuck_execution_count(&self) -> usize { - todo!() + /// Get the number of blocked executions encountered by GenMC. + pub fn get_blocked_execution_count(&self) -> u64 { + let mc = self.handle.borrow(); + mc.as_ref().unwrap().get_blocked_execution_count() } - pub fn print_genmc_graph(&self) { - todo!() + /// Get the number of explored executions encountered by GenMC. + pub fn get_explored_execution_count(&self) -> u64 { + let mc = self.handle.borrow(); + mc.as_ref().unwrap().get_explored_execution_count() } - /// This function determines if we should continue exploring executions or if we are done. - /// - /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. - pub fn is_exploration_done(&self) -> bool { - todo!() + /// Check if GenMC encountered an error that wasn't immediately returned during execution. + /// Returns a string representation of the error if one occurred. + pub fn try_get_error(&self) -> Option { + let mc = self.handle.borrow(); + mc.as_ref() + .unwrap() + .get_error_string() + .as_ref() + .map(|error| error.to_string_lossy().to_string()) } - /// Inform GenMC that a new program execution has started. - /// This function should be called at the start of every execution. - pub(crate) fn handle_execution_start(&self) { - todo!() + /// Check if GenMC encountered an error that wasn't immediately returned during execution. + /// Returns a string representation of the error if one occurred. + pub fn get_result_message(&self) -> String { + let mc = self.handle.borrow(); + mc.as_ref() + .unwrap() + .get_result_message() + .as_ref() + .map(|error| error.to_string_lossy().to_string()) + .expect("there should always be a message") } - /// Inform GenMC that the program's execution has ended. + /// This function determines if we should continue exploring executions or if we are done. /// - /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). - pub(crate) fn handle_execution_end<'tcx>( - &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - ) -> Result<(), String> { - todo!() + /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. + pub fn is_exploration_done(&self) -> bool { + let mut mc = self.handle.borrow_mut(); + mc.as_mut().unwrap().is_exploration_done() } - /**** Memory access handling ****/ - /// Select whether data race free actions should be allowed. This function should be used carefully! /// /// If `true` is passed, allow for data races to happen without triggering an error, until this function is called again with argument `false`. @@ -83,10 +176,59 @@ impl GenmcCtx { /// # Panics /// If data race free is attempted to be set more than once (i.e., no nesting allowed). pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) { - let old = self.allow_data_races.replace(enable); + debug!("GenMC: set_ongoing_action_data_race_free ({enable})"); + let old = self.exec_state.allow_data_races.replace(enable); assert_ne!(old, enable, "cannot nest allow_data_races"); } + /// Check whether data races are currently allowed (e.g., for loading values for validation which are not actually loaded by the program). + fn get_alloc_data_races(&self) -> bool { + self.exec_state.allow_data_races.get() + } +} + +/// GenMC event handling. These methods are used to inform GenMC about events happening in the program, and to handle scheduling decisions. +impl GenmcCtx { + /// Prepare for the next execution and inform GenMC about it. + /// Must be called before at the start of every execution. + fn prepare_next_execution(&self) { + // Reset per-execution state. + self.exec_state.reset(); + // Inform GenMC about the new execution. + let mut mc = self.handle.borrow_mut(); + mc.as_mut().unwrap().handle_execution_start(); + } + + /// Inform GenMC that the program's execution has ended. + /// + /// This function must be called even when the execution is blocked + /// (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`). + /// Don't call this function if an error was found. + /// + /// GenMC detects certain errors only when the execution ends. + /// If an error occured, a string containing a short error description is returned. + /// + /// GenMC currently doesn't return an error in all cases immediately when one happens. + /// This function will also check for those, and return their error description. + /// + /// To get the all messages (warnings, errors) that GenMC produces, use the `get_result_message` method. + fn handle_execution_end(&self) -> Option { + let mut mc = self.handle.borrow_mut(); + let result = mc.as_mut().unwrap().handle_execution_end(); + result.as_ref().map(|msg| msg.to_string_lossy().to_string())?; + + // GenMC currently does not return an error value immediately in all cases. + // We manually query for any errors here to ensure we don't miss any. + drop(mc); // `try_get_error` needs access to the `RefCell`. + self.try_get_error() + } + + /**** Memory access handling ****/ + + /// Inform GenMC about an atomic load. + /// Returns that value that the load should read. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_load<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -95,89 +237,143 @@ impl GenmcCtx { ordering: AtomicReadOrd, old_val: Option, ) -> InterpResult<'tcx, Scalar> { - assert!(!self.allow_data_races.get()); - todo!() + assert!(!self.get_alloc_data_races(), "atomic load with data race checking disabled."); + let genmc_old_value = if let Some(scalar) = old_val { + scalar_to_genmc_scalar(ecx, scalar)? + } else { + GenmcScalar::UNINIT + }; + let read_value = + self.handle_load(&ecx.machine, address, size, ordering.to_genmc(), genmc_old_value)?; + genmc_scalar_to_scalar(ecx, read_value, size) } + /// Inform GenMC about an atomic store. + /// Returns `true` if the stored value should be reflected in Miri's memory. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_store<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, address: Size, size: Size, value: Scalar, + old_value: Option, ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + ) -> InterpResult<'tcx, bool> { + assert!(!self.get_alloc_data_races(), "atomic store with data race checking disabled."); + let genmc_value = scalar_to_genmc_scalar(ecx, value)?; + let genmc_old_value = if let Some(scalar) = old_value { + scalar_to_genmc_scalar(ecx, scalar)? + } else { + GenmcScalar::UNINIT + }; + self.handle_store( + &ecx.machine, + address, + size, + genmc_value, + genmc_old_value, + ordering.to_genmc(), + ) } + /// Inform GenMC about an atomic fence. pub(crate) fn atomic_fence<'tcx>( &self, - machine: &MiriMachine<'tcx>, - ordering: AtomicFenceOrd, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + _machine: &MiriMachine<'tcx>, + _ordering: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + assert!(!self.get_alloc_data_races(), "atomic fence with data race checking disabled."); + throw_unsup_format!("FIXME(genmc): Add support for atomic fences.") } /// Inform GenMC about an atomic read-modify-write operation. /// - /// Returns `(old_val, new_val)`. + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_rmw_op<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - ordering: AtomicRwOrd, - (rmw_op, not): (mir::BinOp, bool), - rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { - assert!(!self.allow_data_races.get()); - todo!() + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + (_rmw_op, _not): (mir::BinOp, bool), + _rhs_scalar: Scalar, + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!( + !self.get_alloc_data_races(), + "atomic read-modify-write operation with data race checking disabled." + ); + throw_unsup_format!("FIXME(genmc): Add support for atomic RMW.") } /// Inform GenMC about an atomic `min` or `max` operation. /// - /// Returns `(old_val, new_val)`. + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_min_max_op<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - ordering: AtomicRwOrd, - min: bool, - is_signed: bool, - rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { - assert!(!self.allow_data_races.get()); - todo!() + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + _min: bool, + _is_signed: bool, + _rhs_scalar: Scalar, + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!( + !self.get_alloc_data_races(), + "atomic min/max operation with data race checking disabled." + ); + throw_unsup_format!("FIXME(genmc): Add support for atomic min/max.") } + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_exchange<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - rhs_scalar: Scalar, - ordering: AtomicRwOrd, - ) -> InterpResult<'tcx, (Scalar, bool)> { - assert!(!self.allow_data_races.get()); - todo!() + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _rhs_scalar: Scalar, + _ordering: AtomicRwOrd, + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!( + !self.get_alloc_data_races(), + "atomic swap operation with data race checking disabled." + ); + throw_unsup_format!("FIXME(genmc): Add support for atomic swap.") } + /// Inform GenMC about an atomic compare-exchange operation. + /// + /// Returns the old value read by the compare exchange, optionally the value that Miri should write back to its memory, and whether the compare-exchange was a success or not. + /// + /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_compare_exchange<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - expected_old_value: Scalar, - new_value: Scalar, - success: AtomicRwOrd, - fail: AtomicReadOrd, - can_fail_spuriously: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { - assert!(!self.allow_data_races.get()); - todo!() + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _expected_old_value: Scalar, + _new_value: Scalar, + _success: AtomicRwOrd, + _fail: AtomicReadOrd, + _can_fail_spuriously: bool, + _old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option, bool)> { + assert!( + !self.get_alloc_data_races(), + "atomic compare-exchange with data race checking disabled." + ); + throw_unsup_format!("FIXME(genmc): Add support for atomic compare_exchange.") } /// Inform GenMC about a non-atomic memory load @@ -188,40 +384,178 @@ impl GenmcCtx { machine: &MiriMachine<'tcx>, address: Size, size: Size, - ) -> InterpResult<'tcx, ()> { - todo!() + ) -> InterpResult<'tcx> { + debug!( + "GenMC: received memory_load (non-atomic): address: {:#x}, size: {}", + address.bytes(), + size.bytes() + ); + if self.get_alloc_data_races() { + debug!("GenMC: data race checking disabled, ignoring non-atomic load."); + return interp_ok(()); + } + // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them + if size.bytes() == 0 { + return interp_ok(()); + } + + let handle_load = |address, size| { + // NOTE: Values loaded non-atomically are still handled by Miri, so we discard whatever we get from GenMC + let _read_value = self.handle_load( + machine, + address, + size, + MemOrdering::NotAtomic, + // This value is used to update the co-maximal store event to the same location. + // We don't need to update that store, since if it is ever read by any atomic loads, the value will be updated then. + // We use uninit for lack of a better value, since we don't know whether the location we currently load from is initialized or not. + GenmcScalar::UNINIT, + )?; + interp_ok(()) + }; + + // This load is small enough so GenMC can handle it. + if size.bytes() <= MAX_ACCESS_SIZE { + return handle_load(address, size); + } + + // This load is too big to be a single GenMC access, we have to split it. + // FIXME(genmc): This will misbehave if there are non-64bit-atomics in there. + // Needs proper support on the GenMC side for large and mixed atomic accesses. + for (address, size) in split_access(address, size) { + handle_load(Size::from_bytes(address), Size::from_bytes(size))?; + } + interp_ok(()) } + /// Inform GenMC about a non-atomic memory store + /// + /// NOTE: Unlike for *atomic* stores, we don't provide the actual stored values to GenMC here. pub(crate) fn memory_store<'tcx>( &self, machine: &MiriMachine<'tcx>, address: Size, size: Size, - ) -> InterpResult<'tcx, ()> { - todo!() + ) -> InterpResult<'tcx> { + debug!( + "GenMC: received memory_store (non-atomic): address: {:#x}, size: {}", + address.bytes(), + size.bytes() + ); + if self.get_alloc_data_races() { + debug!("GenMC: data race checking disabled, ignoring non-atomic store."); + return interp_ok(()); + } + // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them + if size.bytes() == 0 { + return interp_ok(()); + } + + let handle_store = |address, size| { + // We always write the the stored values to Miri's memory, whether GenMC says the write is co-maximal or not. + // The GenMC scheduler ensures that replaying an execution happens in porf-respecting order (po := program order, rf: reads-from order). + // This means that for any non-atomic read Miri performs, the corresponding write has already been replayed. + let _is_co_max_write = self.handle_store( + machine, + address, + size, + // We don't know the value that this store will write, but GenMC expects that we give it an actual value. + // Unfortunately, there are situations where this value can actually become visible + // to the program: when there is an atomic load reading from a non-atomic store. + // FIXME(genmc): update once mixed atomic-non-atomic support is added. Afterwards, this value should never be readable. + GenmcScalar::from_u64(0xDEADBEEF), + // This value is used to update the co-maximal store event to the same location. + // This old value cannot be read anymore by any future loads, since we are doing another non-atomic store to the same location. + // Any future load will either see the store we are adding now, or we have a data race (there can only be one possible non-atomic value to read from at any time). + // We use uninit for lack of a better value, since we don't know whether the location we currently write to is initialized or not. + GenmcScalar::UNINIT, + MemOrdering::NotAtomic, + )?; + interp_ok(()) + }; + + // This store is small enough so GenMC can handle it. + if size.bytes() <= MAX_ACCESS_SIZE { + return handle_store(address, size); + } + + // This store is too big to be a single GenMC access, we have to split it. + // FIXME(genmc): This will misbehave if there are non-64bit-atomics in there. + // Needs proper support on the GenMC side for large and mixed atomic accesses. + for (address, size) in split_access(address, size) { + handle_store(Size::from_bytes(address), Size::from_bytes(size))?; + } + interp_ok(()) } /**** Memory (de)allocation ****/ + /// This is also responsible for determining the address of the new allocation. pub(crate) fn handle_alloc<'tcx>( &self, - machine: &MiriMachine<'tcx>, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + alloc_id: AllocId, size: Size, alignment: Align, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - todo!() + assert!( + !self.get_alloc_data_races(), + "memory allocation with data race checking disabled." + ); + let machine = &ecx.machine; + if memory_kind == MiriMemoryKind::Global.into() { + return ecx + .get_global_allocation_address(&self.global_state.global_allocations, alloc_id); + } + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread); + // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte + let genmc_size = size.bytes().max(1); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut().unwrap(); + let chosen_address = pinned_mc.handle_malloc(genmc_tid, genmc_size, alignment.bytes()); + + // Non-global addresses should not be in the global address space or null. + assert_ne!(0, chosen_address, "GenMC malloc returned nullptr."); + assert_eq!(0, chosen_address & GENMC_GLOBAL_ADDRESSES_MASK); + // Sanity check the address alignment: + assert!( + chosen_address.is_multiple_of(alignment.bytes()), + "GenMC returned address {chosen_address:#x} with lower alignment than requested ({}).", + alignment.bytes() + ); + + interp_ok(chosen_address) } pub(crate) fn handle_dealloc<'tcx>( &self, machine: &MiriMachine<'tcx>, + alloc_id: AllocId, address: Size, - size: Size, - align: Align, kind: MemoryKind, - ) -> InterpResult<'tcx, ()> { - todo!() + ) -> InterpResult<'tcx> { + assert_ne!( + kind, + MiriMemoryKind::Global.into(), + "we probably shouldn't try to deallocate global allocations (alloc_id: {alloc_id:?})" + ); + assert!( + !self.get_alloc_data_races(), + "memory deallocation with data race checking disabled." + ); + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut().unwrap(); + pinned_mc.handle_free(genmc_tid, address.bytes()); + + interp_ok(()) } /**** Thread management ****/ @@ -229,50 +563,95 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, threads: &ThreadManager<'tcx>, + // FIXME(genmc,symmetry reduction): pass info to GenMC + _start_routine: crate::Pointer, + _func_arg: &crate::ImmTy<'tcx>, new_thread_id: ThreadId, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + ) -> InterpResult<'tcx> { + assert!(!self.get_alloc_data_races(), "thread creation with data race checking disabled."); + let mut thread_infos = self.exec_state.thread_id_manager.borrow_mut(); + + let curr_thread_id = threads.active_thread(); + let genmc_parent_tid = thread_infos.get_genmc_tid(curr_thread_id); + let genmc_new_tid = thread_infos.add_thread(new_thread_id); + + let mut mc = self.handle.borrow_mut(); + mc.as_mut().unwrap().handle_thread_create(genmc_new_tid, genmc_parent_tid); + + interp_ok(()) } pub(crate) fn handle_thread_join<'tcx>( &self, active_thread_id: ThreadId, child_thread_id: ThreadId, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() - } + ) -> InterpResult<'tcx> { + assert!(!self.get_alloc_data_races(), "thread join with data race checking disabled."); + let thread_infos = self.exec_state.thread_id_manager.borrow(); - pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) { - todo!() - } + let genmc_curr_tid = thread_infos.get_genmc_tid(active_thread_id); + let genmc_child_tid = thread_infos.get_genmc_tid(child_thread_id); - pub(crate) fn handle_thread_finish<'tcx>( - &self, - threads: &ThreadManager<'tcx>, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + let mut mc = self.handle.borrow_mut(); + mc.as_mut().unwrap().handle_thread_join(genmc_curr_tid, genmc_child_tid); + + interp_ok(()) } - /**** Scheduling functionality ****/ + pub(crate) fn handle_thread_finish<'tcx>(&self, threads: &ThreadManager<'tcx>) { + assert!(!self.get_alloc_data_races(), "thread finish with data race checking disabled."); + let curr_thread_id = threads.active_thread(); - /// Ask for a scheduling decision. This should be called before every MIR instruction. - /// - /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). - /// - /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors. - pub(crate) fn schedule_thread<'tcx>( + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread_id); + + debug!("GenMC: thread {curr_thread_id:?} ({genmc_tid:?}) finished."); + let mut mc = self.handle.borrow_mut(); + // NOTE: Miri doesn't support return values for threads, but GenMC expects one, so we return 0 + mc.as_mut().unwrap().handle_thread_finish(genmc_tid, /* ret_val */ 0); + } + + /// Handle a call to `libc::exit` or the exit of the main thread. + /// Unless an error is returned, the program should continue executing (in a different thread, chosen by the next scheduling call). + pub(crate) fn handle_exit<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - ) -> InterpResult<'tcx, ThreadId> { - assert!(!self.allow_data_races.get()); - todo!() + thread: ThreadId, + exit_code: i32, + exit_type: ExitType, + ) -> InterpResult<'tcx> { + // Calling `libc::exit` doesn't do cleanup, so we skip the leak check in that case. + let exit_status = ExitStatus { exit_code, exit_type }; + + if let Some(old_exit_status) = self.exec_state.exit_status.get() { + throw_ub_format!( + "`exit` called twice, first with status {old_exit_status:?}, now with status {exit_status:?}", + ); + } + + // FIXME(genmc): Add a flag to continue exploration even when the program exits with a non-zero exit code. + if exit_code != 0 { + info!("GenMC: 'exit' called with non-zero argument, aborting execution."); + let leak_check = exit_status.do_leak_check(); + throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check }); + } + + if matches!(exit_type, ExitType::ExitCalled) { + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let genmc_tid = thread_infos.get_genmc_tid(thread); + + let mut mc = self.handle.borrow_mut(); + mc.as_mut().unwrap().handle_thread_kill(genmc_tid); + } else { + assert_eq!(thread, ThreadId::MAIN_THREAD); + } + // We continue executing now, so we store the exit status. + self.exec_state.exit_status.set(Some(exit_status)); + interp_ok(()) } /**** Blocking instructions ****/ + #[allow(unused)] pub(crate) fn handle_verifier_assume<'tcx>( &self, machine: &MiriMachine<'tcx>, @@ -282,14 +661,119 @@ impl GenmcCtx { } } -impl VisitProvenance for GenmcCtx { - fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { - // We don't have any tags. +impl GenmcCtx { + /// Inform GenMC about a load (atomic or non-atomic). + /// Returns the value that GenMC wants this load to read. + fn handle_load<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + memory_ordering: MemOrdering, + genmc_old_value: GenmcScalar, + ) -> InterpResult<'tcx, GenmcScalar> { + assert!( + size.bytes() != 0 + && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) + ); + if size.bytes() > MAX_ACCESS_SIZE { + throw_unsup_format!( + "GenMC mode currently does not support atomics larger than {MAX_ACCESS_SIZE} bytes.", + ); + } + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let curr_thread_id = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread_id); + + debug!( + "GenMC: load, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} == {addr:#x}, size: {size:?}, ordering: {memory_ordering:?}, old_value: {genmc_old_value:x?}", + addr = address.bytes() + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut().unwrap(); + let load_result = pinned_mc.handle_load( + genmc_tid, + address.bytes(), + size.bytes(), + memory_ordering, + genmc_old_value, + ); + + if let Some(error) = load_result.error.as_ref() { + // FIXME(genmc): error handling + throw_ub_format!("{}", error.to_string_lossy()); + } + + if !load_result.has_value { + // FIXME(GenMC): Implementing certain GenMC optimizations will lead to this. + unimplemented!("GenMC: load returned no value."); + } + + debug!("GenMC: load returned value: {:?}", load_result.read_value); + interp_ok(load_result.read_value) } -} -impl GenmcCtx { - fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { + /// Inform GenMC about a store (atomic or non-atomic). + /// Returns true if the store is co-maximal, i.e., it should be written to Miri's memory too. + fn handle_store<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + genmc_value: GenmcScalar, + genmc_old_value: GenmcScalar, + memory_ordering: MemOrdering, + ) -> InterpResult<'tcx, bool> { + assert!( + size.bytes() != 0 + && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) + ); + if size.bytes() > MAX_ACCESS_SIZE { + throw_unsup_format!( + "GenMC mode currently does not support atomics larger than {MAX_ACCESS_SIZE} bytes." + ); + } + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let curr_thread_id = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread_id); + + debug!( + "GenMC: store, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} = {addr:#x}, size: {size:?}, ordering {memory_ordering:?}, value: {genmc_value:?}", + addr = address.bytes() + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut().unwrap(); + let store_result = pinned_mc.handle_store( + genmc_tid, + address.bytes(), + size.bytes(), + genmc_value, + genmc_old_value, + memory_ordering, + ); + + if let Some(error) = store_result.error.as_ref() { + // FIXME(genmc): error handling + throw_ub_format!("{}", error.to_string_lossy()); + } + + interp_ok(store_result.is_coherence_order_maximal_write) + } + + /**** Blocking functionality ****/ + + /// Handle a user thread getting blocked. + /// This may happen due to an manual `assume` statement added by a user + /// or added by some automated program transformation, e.g., for spinloops. + fn handle_user_block<'tcx>(&self, _machine: &MiriMachine<'tcx>) -> InterpResult<'tcx> { todo!() } } + +impl VisitProvenance for GenmcCtx { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // We don't have any tags. + } +} diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs new file mode 100644 index 0000000000000..62553297a2024 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/run.rs @@ -0,0 +1,71 @@ +use std::rc::Rc; +use std::sync::Arc; + +use rustc_middle::ty::TyCtxt; + +use super::GlobalState; +use crate::rustc_const_eval::interpret::PointerArithmetic; +use crate::{GenmcCtx, MiriConfig}; + +/// Do a complete run of the program in GenMC mode. +/// This will call `eval_entry` multiple times, until either: +/// - An error is detected (indicated by a `None` return value) +/// - All possible executions are explored. +/// +/// FIXME(genmc): add estimation mode setting. +pub fn run_genmc_mode<'tcx>( + config: &MiriConfig, + eval_entry: impl Fn(Rc) -> Option, + tcx: TyCtxt<'tcx>, +) -> Option { + // There exists only one `global_state` per full run in GenMC mode. + // It is shared by all `GenmcCtx` in this run. + // FIXME(genmc): implement multithreading once GenMC supports it. + let global_state = Arc::new(GlobalState::new(tcx.target_usize_max())); + let genmc_ctx = Rc::new(GenmcCtx::new(config, global_state)); + + // `rep` is used to report the progress, Miri will panic on wrap-around. + for rep in 0u64.. { + tracing::info!("Miri-GenMC loop {}", rep + 1); + + // Prepare for the next execution and inform GenMC about it. + genmc_ctx.prepare_next_execution(); + + // Execute the program until completion to get the return value, or return if an error happens: + // FIXME(genmc): add an option to allow the user to see the GenMC output message when the verification is done. + let return_code = eval_entry(genmc_ctx.clone())?; + + // We inform GenMC that the execution is complete. If there was an error, we print it. + if let Some(error) = genmc_ctx.handle_execution_end() { + // This can be reached for errors that affect the entire execution, not just a specific event. + // For instance, linearizability checking and liveness checking report their errors this way. + // Neither are supported by Miri-GenMC at the moment though. However, GenMC also + // treats races on deallocation as global errors, so this code path is still reachable. + // Since we don't have any span information for the error at this point, + // we just print GenMC's error message. + eprintln!("(GenMC) Error detected: {error}"); + eprintln!(); + eprintln!("{}", genmc_ctx.get_result_message()); + return None; + } + + // Check if we've explored enough executions: + if !genmc_ctx.is_exploration_done() { + continue; + } + + eprintln!("(GenMC) Verification complete. No errors were detected."); + + let explored_execution_count = genmc_ctx.get_explored_execution_count(); + let blocked_execution_count = genmc_ctx.get_blocked_execution_count(); + + eprintln!("Number of complete executions explored: {explored_execution_count}"); + if blocked_execution_count > 0 { + eprintln!("Number of blocked executions seen: {blocked_execution_count}"); + } + + // Return the return code of the last execution. + return Some(return_code); + } + unreachable!() +} diff --git a/src/tools/miri/src/concurrency/genmc/scheduling.rs b/src/tools/miri/src/concurrency/genmc/scheduling.rs new file mode 100644 index 0000000000000..b5c23f2d0845f --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/scheduling.rs @@ -0,0 +1,69 @@ +use genmc_sys::{ActionKind, ExecutionState}; + +use super::GenmcCtx; +use crate::{ + InterpCx, InterpResult, MiriMachine, TerminationInfo, ThreadId, interp_ok, throw_machine_stop, +}; + +impl GenmcCtx { + pub(crate) fn schedule_thread<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + let thread_manager = &ecx.machine.threads; + let active_thread_id = thread_manager.active_thread(); + + // Determine whether the next instruction in the current thread might be a load. + // This is used for the "writes-first" scheduling in GenMC. + // Scheduling writes before reads can be beneficial for verification performance. + // `Load` is a safe default for the next instruction type if we cannot guarantee that it isn't a load. + let curr_thread_next_instr_kind = if !thread_manager.active_thread_ref().is_enabled() { + // The current thread can get blocked (e.g., due to a thread join, `Mutex::lock`, assume statement, ...), then we need to ask GenMC for another thread to schedule. + // Most to all blocking operations have load semantics, since they wait on something to change in another thread, + // e.g., a thread join waiting on another thread to finish (join loads the return value(s) of the other thread), + // or a thread waiting for another thread to unlock a `Mutex`, which loads the mutex state (Locked, Unlocked). + ActionKind::Load + } else { + // This thread is still enabled. If it executes a terminator next, we consider yielding, + // but in all other cases we just keep running this thread since it never makes sense + // to yield before a non-atomic operation. + let Some(frame) = thread_manager.active_thread_stack().last() else { + return interp_ok(active_thread_id); + }; + let either::Either::Left(loc) = frame.current_loc() else { + // We are unwinding, so the next step is definitely not atomic. + return interp_ok(active_thread_id); + }; + let basic_block = &frame.body().basic_blocks[loc.block]; + if let Some(_statement) = basic_block.statements.get(loc.statement_index) { + // Statements can't be atomic. + return interp_ok(active_thread_id); + } + + // FIXME(genmc): determine terminator kind. + ActionKind::Load + }; + + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let genmc_tid = thread_infos.get_genmc_tid(active_thread_id); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut().unwrap(); + let result = pinned_mc.schedule_next(genmc_tid, curr_thread_next_instr_kind); + // Depending on the exec_state, we either schedule the given thread, or we are finished with this execution. + match result.exec_state { + ExecutionState::Ok => interp_ok(thread_infos.get_miri_tid(result.next_thread)), + ExecutionState::Blocked => throw_machine_stop!(TerminationInfo::GenmcBlockedExecution), + ExecutionState::Finished => { + let exit_status = self.exec_state.exit_status.get().expect( + "If the execution is finished, we should have a return value from the program.", + ); + throw_machine_stop!(TerminationInfo::Exit { + code: exit_status.exit_code, + leak_check: exit_status.do_leak_check() + }); + } + _ => unreachable!(), + } + } +} diff --git a/src/tools/miri/src/concurrency/genmc/thread_id_map.rs b/src/tools/miri/src/concurrency/genmc/thread_id_map.rs new file mode 100644 index 0000000000000..9676496fe7fea --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/thread_id_map.rs @@ -0,0 +1,63 @@ +use genmc_sys::GENMC_MAIN_THREAD_ID; +use rustc_data_structures::fx::FxHashMap; + +use crate::ThreadId; + +#[derive(Debug)] +pub struct ThreadIdMap { + /// Map from Miri thread IDs to GenMC thread IDs. + /// We assume as little as possible about Miri thread IDs, so we use a map. + miri_to_genmc: FxHashMap, + /// Map from GenMC thread IDs to Miri thread IDs. + /// We control which thread IDs are used, so we choose them in as an incrementing counter. + genmc_to_miri: Vec, // FIXME(genmc): check if this assumption is (and will stay) correct. +} + +impl Default for ThreadIdMap { + fn default() -> Self { + let miri_to_genmc = [(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID)].into_iter().collect(); + let genmc_to_miri = vec![ThreadId::MAIN_THREAD]; + Self { miri_to_genmc, genmc_to_miri } + } +} + +impl ThreadIdMap { + pub fn reset(&mut self) { + self.miri_to_genmc.clear(); + self.miri_to_genmc.insert(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); + self.genmc_to_miri.clear(); + self.genmc_to_miri.push(ThreadId::MAIN_THREAD); + } + + #[must_use] + /// Add a new Miri thread to the mapping and dispense a new thread ID for GenMC to use. + pub fn add_thread(&mut self, thread_id: ThreadId) -> i32 { + // NOTE: We select the new thread ids as integers incremented by one (we use the length as the counter). + let next_thread_id = self.genmc_to_miri.len(); + let genmc_tid = next_thread_id.try_into().unwrap(); + // If there is already an entry, we override it. + // This could happen if Miri were to reuse `ThreadId`s, but we assume that if this happens, the previous thread with that id doesn't exist anymore. + self.miri_to_genmc.insert(thread_id, genmc_tid); + self.genmc_to_miri.push(thread_id); + + genmc_tid + } + + #[must_use] + /// Try to get the GenMC thread ID corresponding to a given Miri `ThreadId`. + /// Panics if there is no mapping for the given `ThreadId`. + pub fn get_genmc_tid(&self, thread_id: ThreadId) -> i32 { + *self.miri_to_genmc.get(&thread_id).unwrap() + } + + #[must_use] + /// Get the Miri `ThreadId` corresponding to a given GenMC thread id. + /// Panics if the given thread id isn't valid. + pub fn get_miri_tid(&self, genmc_tid: i32) -> ThreadId { + let index: usize = genmc_tid.try_into().unwrap(); + self.genmc_to_miri + .get(index) + .copied() + .expect("A thread id returned from GenMC should exist.") + } +} diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 165215f9270ce..3fb3d890419f7 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -142,7 +142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Synchronize with the previous completion of an InitOnce. /// Must only be called after checking that it is complete. #[inline] - fn init_once_observe_completed(&mut self, init_once_ref: &InitOnceRef) { + fn init_once_observe_completed(&mut self, init_once_ref: &InitOnceRef) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let init_once = init_once_ref.0.borrow(); @@ -152,6 +152,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "observing the completion of incomplete init once" ); - this.acquire_clock(&init_once.clock); + this.acquire_clock(&init_once.clock) } } diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 435615efd9fa7..9dae858592f1f 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -22,5 +22,5 @@ pub mod weak_memory; mod genmc; pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; -pub use self::genmc::{GenmcConfig, GenmcCtx}; +pub use self::genmc::{ExitType, GenmcConfig, GenmcCtx, run_genmc_mode}; pub use self::vector_clock::VClock; diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index fe1ef86ccd31e..00c5e337b1e9e 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -209,6 +209,11 @@ impl<'tcx> Thread<'tcx> { self.thread_name.as_deref() } + /// Return whether this thread is enabled or not. + pub fn is_enabled(&self) -> bool { + self.state.is_enabled() + } + /// Get the name of the current thread for display purposes; will include thread ID if not set. fn thread_display_name(&self, id: ThreadId) -> String { if let Some(ref thread_name) = self.thread_name { @@ -404,6 +409,7 @@ pub struct ThreadManager<'tcx> { /// A mapping from a thread-local static to the thread specific allocation. thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>, /// A flag that indicates that we should change the active thread. + /// Completely ignored in GenMC mode. yield_active_thread: bool, /// A flag that indicates that we should do round robin scheduling of threads else randomized scheduling is used. fixed_scheduling: bool, @@ -676,13 +682,6 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); - // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. - // FIXME(GenMC): Thread-local destructors *are* user code, so this is odd. Also now that we - // support pre-main constructors, it can get called there as well. - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let thread_id = this.active_thread(); - genmc_ctx.handle_thread_stack_empty(thread_id); - } let mut callback = this .active_thread_mut() .on_stack_empty @@ -703,19 +702,19 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// If GenMC mode is active, the scheduling is instead handled by GenMC. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - // In GenMC mode, we let GenMC do the scheduling + + // In GenMC mode, we let GenMC do the scheduling. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { let next_thread_id = genmc_ctx.schedule_thread(this)?; let thread_manager = &mut this.machine.threads; thread_manager.active_thread = next_thread_id; - thread_manager.yield_active_thread = false; assert!(thread_manager.threads[thread_manager.active_thread].state.is_enabled()); return interp_ok(SchedulingAction::ExecuteStep); } - // We are not in GenMC mode, so we control the schedule + // We are not in GenMC mode, so we control the scheduling. let thread_manager = &mut this.machine.threads; let clock = &this.machine.monotonic_clock; let rng = this.machine.rng.get_mut(); @@ -863,7 +862,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { GlobalDataRaceHandler::Vclocks(data_race) => data_race.thread_created(&this.machine.threads, new_thread_id, current_span), GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?, + genmc_ctx.handle_thread_create( + &this.machine.threads, + start_routine, + &func_arg, + new_thread_id, + )?, } // Write the current thread-id, switch to the next thread later // to treat this write operation as occurring on the current thread. @@ -916,13 +920,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = this.active_thread_mut(); assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated"); thread.state = ThreadState::Terminated; - match &mut this.machine.data_race { - GlobalDataRaceHandler::None => {} - GlobalDataRaceHandler::Vclocks(data_race) => - data_race.thread_terminated(&this.machine.threads), - GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_thread_finish(&this.machine.threads)?, - } + // Deallocate TLS. let gone_thread = this.active_thread(); { @@ -953,6 +951,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } + + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_terminated(&this.machine.threads), + GlobalDataRaceHandler::Genmc(genmc_ctx) => { + // Inform GenMC that the thread finished. + // This needs to happen once all accesses to the thread are done, including freeing any TLS statics. + genmc_ctx.handle_thread_finish(&this.machine.threads) + } + } + // Unblock joining threads. let unblock_reason = BlockReason::Join(gone_thread); let threads = &this.machine.threads.threads; @@ -978,6 +988,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback: DynUnblockCallback<'tcx>, ) { let this = self.eval_context_mut(); + if timeout.is_some() && this.machine.data_race.as_genmc_ref().is_some() { + panic!("Unimplemented: Timeouts not yet supported in GenMC mode."); + } let timeout = timeout.map(|(clock, anchor, duration)| { let anchor = match clock { TimeoutClock::RealTime => { @@ -1076,6 +1089,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "{:?} blocked on {:?} when trying to join", thread_mgr.active_thread, joined_thread_id ); + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + genmc_ctx.handle_thread_join(thread_mgr.active_thread, joined_thread_id)?; + } + // The joined thread is still running, we need to wait for it. // Once we get unblocked, perform the appropriate synchronization and write the return value. let dest = return_dest.clone(); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9ecbd31c5b9f9..34f560962e662 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -31,8 +31,9 @@ pub enum TerminationInfo { }, Int2PtrWithStrictProvenance, Deadlock, - /// In GenMC mode, an execution can get stuck in certain cases. This is not an error. - GenmcStuckExecution, + /// In GenMC mode, executions can get blocked, which stops the current execution without running any cleanup. + /// No leak checks should be performed if this happens, since they would give false positives. + GenmcBlockedExecution, MultipleSymbolDefinitions { link_name: Symbol, first: SpanData, @@ -77,7 +78,8 @@ impl fmt::Display for TerminationInfo { StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), TreeBorrowsUb { title, .. } => write!(f, "{title}"), Deadlock => write!(f, "the evaluated program deadlocked"), - GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"), + GenmcBlockedExecution => + write!(f, "GenMC determined that the execution got blocked (this is not an error)"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => @@ -243,11 +245,12 @@ pub fn report_error<'tcx>( labels.push(format!("this thread got stuck here")); None } - GenmcStuckExecution => { - // This case should only happen in GenMC mode. We treat it like a normal program exit. + GenmcBlockedExecution => { + // This case should only happen in GenMC mode. assert!(ecx.machine.data_race.as_genmc_ref().is_some()); - tracing::info!("GenMC: found stuck execution"); - return Some((0, true)); + // The program got blocked by GenMC without finishing the execution. + // No cleanup code was executed, so we don't do any leak checks. + return Some((0, false)); } MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 4c531a8d1f526..e6c2163105ad1 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -303,8 +303,21 @@ impl<'tcx> MainThreadState<'tcx> { // to be like a global `static`, so that all memory reached by it is considered to "not leak". this.terminate_active_thread(TlsAllocAction::Leak)?; - // Stop interpreter loop. - throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true }); + // In GenMC mode, we do not immediately stop execution on main thread exit. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // If there's no error, execution will continue (on another thread). + genmc_ctx.handle_exit( + ThreadId::MAIN_THREAD, + exit_code, + crate::concurrency::ExitType::MainThreadFinish, + )?; + } else { + // Stop interpreter loop. + throw_machine_stop!(TerminationInfo::Exit { + code: exit_code, + leak_check: true + }); + } } } interp_ok(Poll::Pending) @@ -505,10 +518,6 @@ pub fn eval_entry<'tcx>( // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - if let Some(genmc_ctx) = &genmc_ctx { - genmc_ctx.handle_execution_start(); - } - let mut ecx = match create_ecx(tcx, entry_id, entry_type, config, genmc_ctx).report_err() { Ok(v) => v, Err(err) => { @@ -532,15 +541,6 @@ pub fn eval_entry<'tcx>( // Show diagnostic, if any. let (return_code, leak_check) = report_error(&ecx, err)?; - // We inform GenMC that the execution is complete. - if let Some(genmc_ctx) = ecx.machine.data_race.as_genmc_ref() - && let Err(error) = genmc_ctx.handle_execution_end(&ecx) - { - // FIXME(GenMC): Improve error reporting. - tcx.dcx().err(format!("GenMC returned an error: \"{error}\"")); - return None; - } - // If we get here there was no fatal error. // Possibly check for memory leaks. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 507d4f7b42896..a9279bbefd8fd 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -133,7 +133,7 @@ pub use crate::concurrency::thread::{ BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; -pub use crate::concurrency::{GenmcConfig, GenmcCtx}; +pub use crate::concurrency::{GenmcConfig, GenmcCtx, run_genmc_mode}; pub use crate::data_structures::dedup_range_map::DedupRangeMap; pub use crate::data_structures::mono_hash_map::MonoHashMap; pub use crate::diagnostics::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 9482769a2fc79..4bb6dd2aafe02 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1427,9 +1427,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } match &machine.data_race { GlobalDataRaceHandler::None => {} - GlobalDataRaceHandler::Genmc(genmc_ctx) => { - genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; - } + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.memory_store(machine, ptr.addr(), range.size)?, GlobalDataRaceHandler::Vclocks(_global_state) => { let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &mut alloc_extra.data_race @@ -1465,7 +1464,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { match &machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, + genmc_ctx.handle_dealloc(machine, alloc_id, ptr.addr(), kind)?, GlobalDataRaceHandler::Vclocks(_global_state) => { let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); data_race.write( diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 21545b680299c..c6bc29cb8cb47 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -443,13 +443,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "exit" => { let [code] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let code = this.read_scalar(code)?.to_i32()?; + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // If there is no error, execution should continue (on a different thread). + genmc_ctx.handle_exit( + this.machine.threads.active_thread(), + code, + crate::concurrency::ExitType::ExitCalled, + )?; + todo!(); // FIXME(genmc): Add a way to return here that is allowed to not do progress (can't use existing EmulateItemResult variants). + } throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false }); } "abort" => { let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() - )) + )); } // Standard C allocation diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index d460abc783dd5..aac880feda40e 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -639,7 +639,7 @@ fn return_ready_list<'tcx>( &des.1, )?; // Synchronize waking thread with the event of interest. - ecx.acquire_clock(&epoll_event_instance.clock); + ecx.acquire_clock(&epoll_event_instance.clock)?; num_of_events = num_of_events.strict_add(1); } else { diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 2d35ef064db8b..ad8ea6410264f 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -299,7 +299,7 @@ fn eventfd_read<'tcx>( ); } else { // Synchronize with all prior `write` calls to this FD. - ecx.acquire_clock(&eventfd.clock.borrow()); + ecx.acquire_clock(&eventfd.clock.borrow())?; // Return old counter value into user-space buffer. ecx.write_int(counter, &buf_place)?; diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 817ddd7954df4..52073b58e70de 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -337,7 +337,7 @@ fn anonsocket_read<'tcx>( // Synchronize with all previous writes to this buffer. // FIXME: this over-synchronizes; a more precise approach would be to // only sync with the writes whose data we will read. - ecx.acquire_clock(&readbuf.clock); + ecx.acquire_clock(&readbuf.clock)?; // Do full read / partial read based on the space available. // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior. diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 9165e76b63d14..a893999ef8e52 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -60,7 +60,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { true } InitOnceStatus::Complete => { - this.init_once_observe_completed(init_once_ref); + this.init_once_observe_completed(init_once_ref)?; this.write_scalar(this.eval_windows("c", "FALSE"), pending_place)?; this.write_scalar(this.eval_windows("c", "TRUE"), dest)?; true diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr new file mode 100644 index 0000000000000..121ded2a181ca --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: Non-atomic race + --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + | +LL | X = 2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | f(); + | ^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr new file mode 100644 index 0000000000000..121ded2a181ca --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: Non-atomic race + --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + | +LL | X = 2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | f(); + | ^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr new file mode 100644 index 0000000000000..121ded2a181ca --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: Non-atomic race + --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + | +LL | X = 2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | f(); + | ^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rs b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rs new file mode 100644 index 0000000000000..1568a302f85ad --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@revisions: rlx_rlx rlx_acq rel_rlx + +// Translated from GenMC's test `wrong/racy/MP+rel+rlx`, `MP+rlx+acq` and `MP+rlx+rlx`. +// Test if Miri with GenMC can detect the data race on `X`. +// Relaxed orderings on an atomic store-load pair should not synchronize the non-atomic write to X, leading to a data race. + +// FIXME(genmc): once Miri-GenMC error reporting is improved, ensure that it correctly points to the two spans involved in the data race. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::{self, *}; + +use genmc::spawn_pthread_closure; + +static mut X: u64 = 0; +static Y: AtomicUsize = AtomicUsize::new(0); + +const STORE_ORD: Ordering = if cfg!(rel_rlx) { Release } else { Relaxed }; +const LOAD_ORD: Ordering = if cfg!(rlx_acq) { Acquire } else { Relaxed }; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X = 1; + Y.store(1, STORE_ORD); + }); + spawn_pthread_closure(|| { + if Y.load(LOAD_ORD) != 0 { + X = 2; //~ ERROR: Undefined Behavior: Non-atomic race + } + }); + } + 0 +} diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr new file mode 100644 index 0000000000000..e2b114df652f8 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + | +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr new file mode 100644 index 0000000000000..e2b114df652f8 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + | +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs new file mode 100644 index 0000000000000..dea2b5f952e7e --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs @@ -0,0 +1,73 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@revisions: sc3_rel1 release4 relaxed4 + +// The pass tests "2w2w_3sc_1rel.rs", "2w2w_4rel" and "2w2w_4sc" and the fail test "2w2w_weak.rs" are related. +// +// This test has multiple variants using different memory orderings. +// When using any combination of orderings except using all 4 `SeqCst`, the memory model allows the program to result in (X, Y) == (1, 1). +// The "pass" variants only check that we get the expected number of executions (3 for all SC, 4 otherwise), +// and a valid outcome every execution, but do not check that we get all allowed results. +// This "fail" variant ensures we can explore the execution resulting in (1, 1), an incorrect unsafe assumption that the result (1, 1) is impossible. +// +// Miri without GenMC is unable to produce this program execution and thus detect the incorrect assumption, even with `-Zmiri-many-seeds`. +// +// To get good coverage, we test the combination with the strongest orderings allowing this result (3 `SeqCst`, 1 `Release`), +// the weakest orderings (4 `Relaxed`), and one in between (4 `Release`). + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::{self, *}; + +use crate::genmc::{join_pthreads, spawn_pthread_closure}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +// Strongest orderings allowing result (1, 1). +#[cfg(seqcst_rel)] +const STORE_ORD_3: Ordering = SeqCst; +#[cfg(seqcst_rel)] +const STORE_ORD_1: Ordering = Release; + +// 4 * `Release`. +#[cfg(acqrel)] +const STORE_ORD_3: Ordering = Release; +#[cfg(acqrel)] +const STORE_ORD_1: Ordering = Release; + +// Weakest orderings (4 * `Relaxed`). +#[cfg(not(any(acqrel, seqcst_rel)))] +const STORE_ORD_3: Ordering = Relaxed; +#[cfg(not(any(acqrel, seqcst_rel)))] +const STORE_ORD_1: Ordering = Relaxed; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ids = [ + spawn_pthread_closure(|| { + X.store(1, STORE_ORD_3); + Y.store(2, STORE_ORD_3); + }), + spawn_pthread_closure(|| { + Y.store(1, STORE_ORD_1); + X.store(2, STORE_ORD_3); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // We mark the result (1, 1) as unreachable, which is incorrect. + let result = (X.load(Relaxed), Y.load(Relaxed)); + if result == (1, 1) { + // FIXME(genmc): Use `std::process::abort()` once backtraces for that are improved (https://github.com/rust-lang/rust/pull/146118) + std::hint::unreachable_unchecked(); //~ ERROR: entering unreachable code + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr new file mode 100644 index 0000000000000..e2b114df652f8 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + | +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/pass/litmus/2cowr.rs b/src/tools/miri/tests/genmc/pass/litmus/2cowr.rs new file mode 100644 index 0000000000000..d3fdb470ed367 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2cowr.rs @@ -0,0 +1,51 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "2CoWR". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + a = Y.load(Acquire); + }), + spawn_pthread_closure(|| { + b = X.load(Acquire); + }), + spawn_pthread_closure(|| { + X.store(1, Release); + }), + spawn_pthread_closure(|| { + Y.store(1, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (1, 0) | (1, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr b/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.rs b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.rs new file mode 100644 index 0000000000000..22fe9524c37f5 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.rs @@ -0,0 +1,54 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@revisions: release1 release2 + +// Translated from GenMC's test "2+2W+3sc+rel1" and "2+2W+3sc+rel2" (two variants that swap which store is `Release`). +// +// The pass tests "2w2w_3sc_1rel.rs", "2w2w_4rel" and "2w2w_4sc" and the fail test "2w2w_weak.rs" are related. +// Check "2w2w_weak.rs" for a more detailed description. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ids = [ + spawn_pthread_closure(|| { + X.store(1, SeqCst); + Y.store(2, SeqCst); + }), + // Variant 1: `Release` goes first. + #[cfg(release1)] + spawn_pthread_closure(|| { + Y.store(1, Release); + X.store(2, SeqCst); + }), + // Variant 2: `Release` goes second. + #[cfg(not(release1))] + spawn_pthread_closure(|| { + Y.store(1, SeqCst); + X.store(2, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + let result = (X.load(Relaxed), Y.load(Relaxed)); + if !matches!(result, (1, 2) | (1, 1) | (2, 2) | (2, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs new file mode 100644 index 0000000000000..bbe9995dea0b2 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "2+2W". +// +// The pass tests "2w2w_3sc_1rel.rs", "2w2w_4rel" and "2w2w_4sc" and the fail test "2w2w_weak.rs" are related. +// Check "2w2w_weak.rs" for a more detailed description. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ids = [ + spawn_pthread_closure(|| { + Y.store(1, Release); + X.store(2, Release); + }), + spawn_pthread_closure(|| { + X.store(1, Release); + Y.store(2, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + let result = (X.load(Relaxed), Y.load(Relaxed)); + if !matches!(result, (1, 2) | (1, 1) | (2, 2) | (2, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.rs b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.rs new file mode 100644 index 0000000000000..c5711ba04fce2 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "2+2W+4c". +// +// The pass tests "2w2w_3sc_1rel.rs", "2w2w_4rel" and "2w2w_4sc" and the fail test "2w2w_weak.rs" are related. +// Check "2w2w_weak.rs" for a more detailed description. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ids = [ + spawn_pthread_closure(|| { + X.store(1, SeqCst); + Y.store(2, SeqCst); + }), + spawn_pthread_closure(|| { + Y.store(1, SeqCst); + X.store(2, SeqCst); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + let result = (X.load(Relaxed), Y.load(Relaxed)); + if !matches!(result, (2, 1) | (2, 2) | (1, 2)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs new file mode 100644 index 0000000000000..79e7c7feb7aac --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs @@ -0,0 +1,64 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "IRIW-acq-sc" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let mut c = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, SeqCst); + }), + spawn_pthread_closure(|| { + a = X.load(Acquire); + Y.load(SeqCst); + }), + spawn_pthread_closure(|| { + b = Y.load(Acquire); + c = X.load(SeqCst); + }), + spawn_pthread_closure(|| { + Y.store(1, SeqCst); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!( + (a, b, c), + (0, 0, 0) + | (0, 0, 1) + | (0, 1, 0) + | (0, 1, 1) + | (1, 0, 0) + | (1, 0, 1) + | (1, 1, 0) + | (1, 1, 1) + ) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr new file mode 100644 index 0000000000000..c760b44605112 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 16 diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB.rs b/src/tools/miri/tests/genmc/pass/litmus/LB.rs new file mode 100644 index 0000000000000..1cee3230b127c --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/LB.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/LB" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + a = Y.load(Acquire); + X.store(2, Release); + }), + spawn_pthread_closure(|| { + b = X.load(Acquire); + Y.store(1, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 2) | (1, 0)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB.stderr b/src/tools/miri/tests/genmc/pass/litmus/LB.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/LB.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP.rs b/src/tools/miri/tests/genmc/pass/litmus/MP.rs new file mode 100644 index 0000000000000..e245cdd15eef2 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/MP" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + Y.store(1, Release); + }), + spawn_pthread_closure(|| { + a = Y.load(Acquire); + b = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (1, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB.rs b/src/tools/miri/tests/genmc/pass/litmus/SB.rs new file mode 100644 index 0000000000000..e592fe05c4e49 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/SB.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/SB" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + a = Y.load(Acquire); + }), + spawn_pthread_closure(|| { + Y.store(1, Release); + b = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (1, 0) | (1, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB.stderr b/src/tools/miri/tests/genmc/pass/litmus/SB.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/SB.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr.rs b/src/tools/miri/tests/genmc/pass/litmus/corr.rs new file mode 100644 index 0000000000000..d6c95100fc241 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoRR" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + X.store(2, Release); + }), + spawn_pthread_closure(|| { + a = X.load(Acquire); + b = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (0, 2) | (1, 1) | (1, 2) | (2, 2)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr.stderr new file mode 100644 index 0000000000000..be75e68fde77d --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr0.rs b/src/tools/miri/tests/genmc/pass/litmus/corr0.rs new file mode 100644 index 0000000000000..f722131fda846 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr0.rs @@ -0,0 +1,46 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoRR0" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + }), + spawn_pthread_closure(|| { + a = X.load(Acquire); + }), + spawn_pthread_closure(|| { + b = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (1, 0) | (1, 1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr1.rs b/src/tools/miri/tests/genmc/pass/litmus/corr1.rs new file mode 100644 index 0000000000000..a4e8249bac309 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr1.rs @@ -0,0 +1,58 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoRR1" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let mut c = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + }), + spawn_pthread_closure(|| { + X.store(2, Release); + }), + spawn_pthread_closure(|| { + a = X.load(Acquire); + b = X.load(Acquire); + }), + spawn_pthread_closure(|| { + c = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values (only 0, 1, 2 are allowed): + if !(matches!(a, 0..=2) && matches!(b, 0..=2) && matches!(c, 0..=2)) { + std::process::abort(); + } + // The 36 possible program executions can have 21 different results for (a, b, c). + // Of the 27 = 3*3*3 total results for (a, b, c), + // those where `a != 0` and `b == 0` are not allowed by the memory model. + // Once the load for `a` reads either 1 or 2, the load for `b` must see that store too, so it cannot read 0. + if a != 0 && b == 0 { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr new file mode 100644 index 0000000000000..f6d07e9c77b2b --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr2.rs b/src/tools/miri/tests/genmc/pass/litmus/corr2.rs new file mode 100644 index 0000000000000..2f490d3637797 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr2.rs @@ -0,0 +1,70 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoRR2" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let mut c = 1234; + let mut d = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + }), + spawn_pthread_closure(|| { + X.store(2, Release); + }), + spawn_pthread_closure(|| { + a = X.load(Acquire); + b = X.load(Acquire); + }), + spawn_pthread_closure(|| { + c = X.load(Acquire); + d = X.load(Acquire); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values (only 0, 1, 2 are allowed): + if !(matches!(a, 0..=2) && matches!(b, 0..=2) && matches!(c, 0..=2) && matches!(d, 0..=2)) { + std::process::abort(); + } + + // The 72 possible program executions can have 47 different results for (a, b, c, d). + // Of the 81 = 3*3*3*3 total results for (a, b, c, d), + // those where `a != 0` and `b == 0` are not allowed by the memory model. + // Once the load for `a` reads either 1 or 2, the load for `b` must see that store too, so it cannot read 0. + // The same applies to `c, d` in the other thread. + // + // Additionally, if one thread reads `1, 2` or `2, 1`, the other thread cannot see the opposite order. + if a != 0 && b == 0 { + std::process::abort(); + } else if c != 0 && d == 0 { + std::process::abort(); + } else if (a, b) == (1, 2) && (c, d) == (2, 1) { + std::process::abort(); + } else if (a, b) == (2, 1) && (c, d) == (1, 2) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr new file mode 100644 index 0000000000000..78a90b63feab6 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/src/tools/miri/tests/genmc/pass/litmus/corw.rs b/src/tools/miri/tests/genmc/pass/litmus/corw.rs new file mode 100644 index 0000000000000..7acc20822a4f4 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corw.rs @@ -0,0 +1,43 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoRW" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let ids = [ + spawn_pthread_closure(|| { + a = X.load(Acquire); + X.store(1, Release); + }), + spawn_pthread_closure(|| { + X.store(2, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values (the load cannot read `1`): + if !matches!(a, 0 | 2) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/corw.stderr b/src/tools/miri/tests/genmc/pass/litmus/corw.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/corw.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/cowr.rs b/src/tools/miri/tests/genmc/pass/litmus/cowr.rs new file mode 100644 index 0000000000000..1c51f23a09c66 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cowr.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "CoWR" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let mut a = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Release); + a = X.load(Acquire); + }), + spawn_pthread_closure(|| { + X.store(2, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values (the load cannot read `0`): + if !matches!(a, 1 | 2) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr b/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/default.rs b/src/tools/miri/tests/genmc/pass/litmus/default.rs new file mode 100644 index 0000000000000..55fb1ac34acb4 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/default.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/default" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + a = X.load(Acquire); + b = X.load(Acquire); + }), + spawn_pthread_closure(|| { + X.store(1, Release); + }), + spawn_pthread_closure(|| { + X.store(2, Release); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((a, b), (0, 0) | (0, 1) | (0, 2) | (1, 1) | (1, 2) | (2, 1) | (2, 2)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/default.stderr b/src/tools/miri/tests/genmc/pass/litmus/default.stderr new file mode 100644 index 0000000000000..e0313930282ea --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/default.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 12 diff --git a/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr b/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr new file mode 100644 index 0000000000000..15017249dc3a7 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 9 diff --git a/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr b/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr new file mode 100644 index 0000000000000..15017249dc3a7 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 9 diff --git a/src/tools/miri/tests/genmc/pass/litmus/detour.rs b/src/tools/miri/tests/genmc/pass/litmus/detour.rs new file mode 100644 index 0000000000000..7136c029bbb54 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/detour.rs @@ -0,0 +1,68 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@revisions: join no_join + +// Translated from GenMC's "litmus/detour" test. + +// This test has two revisitions to test whether we get the same result +// independent of whether we join the spawned threads or not. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicI64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicI64 = AtomicI64::new(0); +static Y: AtomicI64 = AtomicI64::new(0); +static Z: AtomicI64 = AtomicI64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + Z.store(0, Relaxed); + + unsafe { + // Make these static so we can exit the main thread while the other threads still run. + // If these are `let mut` like the other tests, this will cause a use-after-free bug. + static mut A: i64 = 1234; + static mut B: i64 = 1234; + static mut C: i64 = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Relaxed); + }), + spawn_pthread_closure(|| { + A = Z.load(Relaxed); + X.store(A.wrapping_sub(1), Relaxed); + B = X.load(Relaxed); + Y.store(B, Relaxed); + }), + spawn_pthread_closure(|| { + C = Y.load(Relaxed); + Z.store(C, Relaxed); + }), + ]; + + // The `no_join` revision doesn't join any of the running threads to test that + // we still explore the same number of executions in that case. + if cfg!(no_join) { + return 0; + } + + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!((A, B, C), (0, 1, 0) | (0, -1, 0) | (0, 1, 1) | (0, -1, -1)) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs new file mode 100644 index 0000000000000..9a08d517b7c60 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs @@ -0,0 +1,54 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "fr+w+w+w+reads" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let mut result = [1234; 4]; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Relaxed); + }), + spawn_pthread_closure(|| { + X.store(2, Relaxed); + }), + spawn_pthread_closure(|| { + X.store(3, Relaxed); + }), + spawn_pthread_closure(|| { + result[0] = X.load(Relaxed); + result[1] = X.load(Relaxed); + result[2] = X.load(Relaxed); + result[3] = X.load(Relaxed); + }), + ]; + + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + for val in result { + if !matches!(val, 0..=3) { + std::process::abort(); + } + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr new file mode 100644 index 0000000000000..3b6ba238f5342 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 210 diff --git a/src/tools/miri/tests/genmc/pass/test_cxx_build.rs b/src/tools/miri/tests/genmc/pass/test_cxx_build.rs deleted file mode 100644 index f621bd9114fa4..0000000000000 --- a/src/tools/miri/tests/genmc/pass/test_cxx_build.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} diff --git a/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr b/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr deleted file mode 100644 index 4b7aa824bd122..0000000000000 --- a/src/tools/miri/tests/genmc/pass/test_cxx_build.stderr +++ /dev/null @@ -1,5 +0,0 @@ -warning: borrow tracking has been disabled, it is not (yet) supported in GenMC mode. -C++: GenMC handle created! -Miri: GenMC handle creation successful! -C++: GenMC handle destroyed! -Miri: Dropping GenMC handle successful! diff --git a/src/tools/miri/tests/utils/genmc.rs b/src/tools/miri/tests/utils/genmc.rs new file mode 100644 index 0000000000000..fb6334bd06086 --- /dev/null +++ b/src/tools/miri/tests/utils/genmc.rs @@ -0,0 +1,57 @@ +#![allow(unused)] + +use std::ffi::c_void; + +use libc::{self, pthread_attr_t, pthread_t}; + +/// Spawn a thread using `pthread_create`, abort the process on any errors. +pub unsafe fn spawn_pthread( + f: extern "C" fn(*mut c_void) -> *mut c_void, + value: *mut c_void, +) -> pthread_t { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + + if unsafe { libc::pthread_create(&raw mut thread_id, attr, f, value) } != 0 { + std::process::abort(); + } + thread_id +} + +/// Unsafe because we do *not* check that `F` is `Send + 'static`. +/// That makes it much easier to write tests... +pub unsafe fn spawn_pthread_closure(f: F) -> pthread_t { + let mut thread_id: pthread_t = 0; + let attr: *const pthread_attr_t = std::ptr::null(); + let f = Box::new(f); + extern "C" fn thread_func(f: *mut c_void) -> *mut c_void { + let f = unsafe { Box::from_raw(f as *mut F) }; + f(); + std::ptr::null_mut() + } + if unsafe { + libc::pthread_create( + &raw mut thread_id, + attr, + thread_func::, + Box::into_raw(f) as *mut c_void, + ) + } != 0 + { + std::process::abort(); + } + thread_id +} + +// Join the given pthread, abort the process on any errors. +pub unsafe fn join_pthread(thread_id: pthread_t) { + if unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) } != 0 { + std::process::abort(); + } +} + +// Join the `N` given pthreads, abort the process on any errors. +pub unsafe fn join_pthreads(thread_ids: [pthread_t; N]) { + let _ = thread_ids.map(|id| join_pthread(id)); +} From d9619ed1c54f7c20b74913982cf0715002380e10 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 4 Sep 2025 04:52:52 +0000 Subject: [PATCH 135/251] Prepare for merging from rust-lang/rust This updates the rust-version file to 9385c64c95d971329e62917adc4349c8ccdbafe0. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index d44488399f8b9..7420b6200967c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -51ff895062ba60a7cba53f57af928c3fb7b0f2f4 +9385c64c95d971329e62917adc4349c8ccdbafe0 From 169013d9eaae1d0b3d4d07058017698837ee09ff Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 4 Sep 2025 12:10:39 +0300 Subject: [PATCH 136/251] Fix typo in config To make it backwards-compatible. --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index c2252185a3aa3..84f158cdea69f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -2832,7 +2832,7 @@ enum ReborrowHintsDef { #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum AdjustmentHintsDef { - #[serde(alias = "Reborrow")] + #[serde(alias = "reborrow")] Borrows, #[serde(with = "true_or_always")] #[serde(untagged)] From d5cb7e7c7c0f77c7a7b064584ae44e74acc155ca Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 4 Sep 2025 12:18:22 +0300 Subject: [PATCH 137/251] Add a regression test for a fixed new trait solver bug Not sure what exactly fixed it, but why not. --- .../hir-ty/src/tests/regression/new_solver.rs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 20190fbc04564..e4ee52f45eb75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use super::check_infer; +use crate::tests::{check_infer, check_no_mismatches}; #[test] fn opaque_generics() { @@ -50,3 +50,24 @@ fn main() { "#]], ); } + +#[test] +fn regression_20487() { + check_no_mismatches( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +trait Foo { + fn bar(&self) -> u32 { + 0xCAFE + } +} + +fn debug(_: &dyn Foo) {} + +impl Foo for i32 {} + +fn main() { + debug(&1); +}"#, + ); +} From 7ff5a3d277939c9a3648f2dc270ff2e9166bcf70 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 4 Sep 2025 22:36:31 +0300 Subject: [PATCH 138/251] Upgrade rustc crates The main changes are (there are some other small changes): - Using a specific type for trait IDs in the new solver, allowing us to simplify a lot of code. - Add `BoundConst` similar to `BoundTy` and `BoundRegion` (previously consts used `BoundVar` directly), due to a new trait requirement. --- src/tools/rust-analyzer/Cargo.lock | 77 ++- src/tools/rust-analyzer/Cargo.toml | 16 +- .../crates/hir-ty/src/display.rs | 12 +- .../crates/hir-ty/src/dyn_compatibility.rs | 72 +-- .../crates/hir-ty/src/lower_nextsolver.rs | 64 +-- .../hir-ty/src/lower_nextsolver/path.rs | 5 +- .../crates/hir-ty/src/method_resolution.rs | 6 +- .../crates/hir-ty/src/next_solver/consts.rs | 29 +- .../crates/hir-ty/src/next_solver/def_id.rs | 57 ++ .../crates/hir-ty/src/next_solver/fold.rs | 8 +- .../crates/hir-ty/src/next_solver/fulfill.rs | 2 +- .../hir-ty/src/next_solver/generic_arg.rs | 2 - .../infer/canonical/instantiate.rs | 3 +- .../hir-ty/src/next_solver/infer/mod.rs | 6 +- .../next_solver/infer/relate/higher_ranked.rs | 8 +- .../crates/hir-ty/src/next_solver/interner.rs | 511 +++++++----------- .../crates/hir-ty/src/next_solver/ir_print.rs | 10 +- .../crates/hir-ty/src/next_solver/mapping.rs | 32 +- .../hir-ty/src/next_solver/predicate.rs | 8 +- .../crates/hir-ty/src/next_solver/solver.rs | 8 +- .../crates/hir-ty/src/next_solver/ty.rs | 27 + .../crates/hir-ty/src/next_solver/util.rs | 28 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 5 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 29 +- 24 files changed, 446 insertions(+), 579 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b008aa1c50f88..344e6d101fe35 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1360,7 +1360,7 @@ dependencies = [ "expect-test", "intern", "parser", - "ra-ap-rustc_lexer 0.123.0", + "ra-ap-rustc_lexer", "rustc-hash 2.1.1", "smallvec", "span", @@ -1596,8 +1596,8 @@ dependencies = [ "drop_bomb", "edition", "expect-test", - "ra-ap-rustc_lexer 0.123.0", - "rustc-literal-escaper", + "ra-ap-rustc_lexer", + "rustc-literal-escaper 0.0.4", "stdx", "tracing", ] @@ -1717,7 +1717,7 @@ dependencies = [ "object", "paths", "proc-macro-test", - "ra-ap-rustc_lexer 0.123.0", + "ra-ap-rustc_lexer", "span", "syntax-bridge", "temp-dir", @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18c877575c259d127072e9bfc41d985202262fb4d6bfdae3d1252147c2562c2" +checksum = "0c6789d94fb3e6e30d62f55e99a321ba63484a8bb3b4ead338687c9ddc282d28" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1875,24 +1875,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc17e8ce797f2a8d03b838fbf166749b876164432ce81e37d283bf69e3cf80" +checksum = "aaab80bda0f05e9842e3afb7779b0bad0a4b54e0f7ba6deb5705dcf86482811d" [[package]] name = "ra-ap-rustc_hashes" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439ed1df3472443133b66949f81080dff88089b42f825761455463709ee1cad" +checksum = "64bd405e538102b5f699241794b2eefee39d5414c0e4bc72435e91430c51f905" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a24fe0be21be1f8ebc21dcb40129214fb4cefb0f2753f3d46b6dbe656a1a45" +checksum = "521621e271aa03b8433dad5981838278d6cfd7d2d8c9f4eb6d427f1d671f90fc" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1900,9 +1900,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "844a27ddcad0116facae2df8e741fd788662cf93dc13029cd864f2b8013b81f9" +checksum = "245e30f2e1fef258913cc548b36f575549c8af31cbc4649929d21deda96ceeb7" dependencies = [ "proc-macro2", "quote", @@ -1911,20 +1911,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.121.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22944e31fb91e9b3e75bcbc91e37d958b8c0825a6160927f2856831d2ce83b36" -dependencies = [ - "memchr", - "unicode-properties", - "unicode-xid", -] - -[[package]] -name = "ra-ap-rustc_lexer" -version = "0.123.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b734cfcb577d09877799a22742f1bd398be6c00bc428d9de56d48d11ece5771" +checksum = "a82681f924500e888c860e60ed99e9bf702a219a69374f59116c4261525a2157" dependencies = [ "memchr", "unicode-properties", @@ -1933,9 +1922,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7dfbdf1d045ff4e385e1efdfc3799379895e9c3f3b9b379a0bef4cb238441" +checksum = "0c9ce51f2431fbdc7fabd2d957522b6e27f41f68ec2af74b52a6f4116352ce1a" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1946,19 +1935,19 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.121.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81057891bc2063ad9e353f29462fbc47a0f5072560af34428ae9313aaa5e9d97" +checksum = "adc85ef3fdb6c084bde84857d8948dc66b752129dc8417a8614ce490e99a143f" dependencies = [ - "ra-ap-rustc_lexer 0.121.0", - "rustc-literal-escaper", + "ra-ap-rustc_lexer", + "rustc-literal-escaper 0.0.5", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b0ee1f059b9dea0818c6c7267478926eee95ba4c7dcf89c8db32fa165d3904" +checksum = "3cd81eccf33d9528905d4e5abaa254b3129a6405d6c5f123fed9b73a3d217f35" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1969,9 +1958,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bc59fb10a922c38a24cb8a1494f799b0af30bd041acbea689378d3bf330534b" +checksum = "11cb0da02853698d9c89e1d1c01657b9969752befd56365e8899d4310e52b373" dependencies = [ "bitflags 2.9.1", "derive-where", @@ -1988,9 +1977,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.123.0" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58878914b6dac7499baeecc8dbb4b9d9dda88030e4ab90cd3b4e87523fbedafe" +checksum = "ffc93adeb52c483ede13bee6680466458218243ab479c04fb71bb53925a6e0ff" dependencies = [ "proc-macro2", "quote", @@ -2140,6 +2129,12 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +[[package]] +name = "rustc-literal-escaper" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" + [[package]] name = "rustc-stable-hash" version = "0.1.2" @@ -2445,7 +2440,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.4", "rustc_apfloat", "smol_str", "stdx", @@ -2773,7 +2768,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "intern", - "ra-ap-rustc_lexer 0.123.0", + "ra-ap-rustc_lexer", "stdx", "text-size", ] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 05ee190480c97..f325027ee5871 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,14 +89,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.123", default-features = false } -ra-ap-rustc_parse_format = { version = "0.121", default-features = false } -ra-ap-rustc_index = { version = "0.123", default-features = false } -ra-ap-rustc_abi = { version = "0.123", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.123", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.123", default-features = false } -ra-ap-rustc_type_ir = { version = "0.123", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.123", default-features = false } +ra-ap-rustc_lexer = { version = "0.126", default-features = false } +ra-ap-rustc_parse_format = { version = "0.126", default-features = false } +ra-ap-rustc_index = { version = "0.126", default-features = false } +ra-ap-rustc_abi = { version = "0.126", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.126", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.126", default-features = false } +ra-ap-rustc_type_ir = { version = "0.126", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.126", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 5b8093f6b7246..fcb79e9ffb579 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -737,7 +737,7 @@ impl<'db> HirDisplay for crate::next_solver::Const<'db> { match self.kind() { rustc_type_ir::ConstKind::Placeholder(_) => write!(f, ""), rustc_type_ir::ConstKind::Bound(db, bound_const) => { - write!(f, "?{}.{}", db.as_u32(), bound_const.as_u32()) + write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32()) } rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"), rustc_type_ir::ConstKind::Param(param) => { @@ -1208,10 +1208,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { let contains_impl_fn_ns = |bounds: &[BoundExistentialPredicate<'_>]| { bounds.iter().any(|bound| match bound.skip_binder() { rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { - let trait_ = match trait_ref.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; + let trait_ = trait_ref.def_id.0; fn_traits(db, trait_).any(|it| it == trait_) } _ => false, @@ -2217,10 +2214,7 @@ impl HirDisplay for TraitRef { impl<'db> HirDisplay for crate::next_solver::TraitRef<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let trait_ = match self.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; + let trait_ = self.def_id.0; f.start_location_link(trait_.into()); write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; f.end_location_link(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 23280b1f3b42b..d4b3751cf5666 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -2,12 +2,11 @@ use std::ops::ControlFlow; -use hir_def::hir::generics::LocalTypeOrConstParamId; use hir_def::{ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, - TypeAliasId, lang_item::LangItem, signatures::TraitFlags, + TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, + lang_item::LangItem, signatures::TraitFlags, }; -use hir_def::{TypeOrConstParamId, TypeParamId}; use intern::Symbol; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -22,7 +21,7 @@ use crate::{ db::{HirDatabase, InternedOpaqueTyId}, lower_nextsolver::associated_ty_item_bounds, next_solver::{ - Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, + Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TraitRef, TypingMode, infer::DbInternerInferExt, mk_param, }, traits::next_trait_solve_in_ctxt, @@ -56,16 +55,12 @@ pub fn dyn_compatibility( trait_: TraitId, ) -> Option { let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); - for super_trait in elaborate::supertrait_def_ids(interner, SolverDefId::TraitId(trait_)) { - let super_trait = match super_trait { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - if let Some(v) = db.dyn_compatibility_of_trait(super_trait) { - return if super_trait == trait_ { + for super_trait in elaborate::supertrait_def_ids(interner, trait_.into()) { + if let Some(v) = db.dyn_compatibility_of_trait(super_trait.0) { + return if super_trait.0 == trait_ { Some(v) } else { - Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait)) + Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait.0)) }; } } @@ -82,13 +77,8 @@ where F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>, { let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); - for super_trait in elaborate::supertrait_def_ids(interner, SolverDefId::TraitId(trait_)).skip(1) - { - let super_trait = match super_trait { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - if db.dyn_compatibility_of_trait(super_trait).is_some() { + for super_trait in elaborate::supertrait_def_ids(interner, trait_.into()).skip(1) { + if db.dyn_compatibility_of_trait(super_trait.0).is_some() { cb(DynCompatibilityViolation::HasNonCompatibleSuperTrait(trait_))?; } } @@ -151,7 +141,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| { match pred.kind().skip_binder() { ClauseKind::Trait(trait_pred) => { - if SolverDefId::TraitId(sized) == trait_pred.def_id() + if sized == trait_pred.def_id().0 && let rustc_type_ir::TyKind::Param(param_ty) = trait_pred.trait_ref.self_ty().kind() && param_ty.index == 0 @@ -257,15 +247,9 @@ fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable id, - _ => unreachable!(), - }) - .collect(), + elaborate::supertrait_def_ids(interner, self.trait_.into()) + .map(|super_trait| super_trait.0) + .collect(), ) } if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) { @@ -390,8 +374,7 @@ where trait_ref: pred_trait_ref, polarity: PredicatePolarity::Positive, }) = pred - && let SolverDefId::TraitId(trait_id) = pred_trait_ref.def_id - && let trait_data = db.trait_signature(trait_id) + && let trait_data = db.trait_signature(pred_trait_ref.def_id.0) && trait_data.flags.contains(TraitFlags::AUTO) && let rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, .. }) = pred_trait_ref.self_ty().kind() @@ -464,25 +447,17 @@ fn receiver_is_dispatchable<'db>( let generic_predicates = &*db.generic_predicates_ns(func.into()); // Self: Unsize - let unsize_predicate = crate::next_solver::TraitRef::new( - interner, - SolverDefId::TraitId(unsize_did), - [self_param_ty, unsized_self_ty], - ); + let unsize_predicate = + TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]); // U: Trait - let trait_def_id = SolverDefId::TraitId(trait_); - let args = GenericArgs::for_item(interner, trait_def_id, |name, index, kind, _| { + let args = GenericArgs::for_item(interner, trait_.into(), |name, index, kind, _| { if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) } }); - let trait_predicate = - crate::next_solver::TraitRef::new_from_args(interner, trait_def_id, args); + let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); - let meta_sized_predicate = crate::next_solver::TraitRef::new( - interner, - SolverDefId::TraitId(meta_sized_did), - [unsized_self_ty], - ); + let meta_sized_predicate = + TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]); ParamEnv { clauses: Clauses::new_from_iter( @@ -497,11 +472,8 @@ fn receiver_is_dispatchable<'db>( }; // Receiver: DispatchFromDyn U]> - let predicate = crate::next_solver::TraitRef::new( - interner, - SolverDefId::TraitId(dispatch_from_dyn_did), - [receiver_ty, unsized_receiver_ty], - ); + let predicate = + TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]); let goal = crate::next_solver::Goal::new(interner, param_env, predicate); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 4578922ce3219..c6a8fa81edff5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -590,11 +590,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { .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| SolverDefId::TraitId(it) == trait_ref.def_id) { + if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { // Ignore this bound - } else if pointee_sized - .is_some_and(|it| SolverDefId::TraitId(it) == trait_ref.def_id) - { + } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { // Regard this as `?Sized` bound ctx.ty_ctx().unsized_types.insert(self_ty); } else { @@ -618,13 +616,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // Don't lower associated type bindings as the only possible relaxed trait bound // `?Sized` has no of them. // If we got another trait here ignore the bound completely. - let trait_id = - self.lower_trait_ref_from_path(path, self_ty).map(|(trait_ref, _)| { - match trait_ref.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - } - }); + let trait_id = self + .lower_trait_ref_from_path(path, self_ty) + .map(|(trait_ref, _)| trait_ref.def_id.0); if trait_id == sized_trait { self.unsized_types.insert(self_ty); } @@ -668,12 +662,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { .map_bound(|c| match c { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let id = match id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; let is_auto = - db.trait_signature(id).flags.contains(TraitFlags::AUTO); + db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); if is_auto { Some(ExistentialPredicate::AutoTrait(t.def_id())) } else { @@ -733,17 +723,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ( ExistentialPredicate::AutoTrait(lhs_id), ExistentialPredicate::AutoTrait(rhs_id), - ) => { - let lhs_id = match lhs_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - let rhs_id = match rhs_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - lhs_id.cmp(&rhs_id) - } + ) => lhs_id.0.cmp(&rhs_id.0), (ExistentialPredicate::Trait(_), _) => Ordering::Less, (_, ExistentialPredicate::Trait(_)) => Ordering::Greater, (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less, @@ -1195,11 +1175,7 @@ pub(crate) fn generic_predicates_for_param_query<'db>( }; rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| { - let tr = match tr { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - tr.trait_items(db).items.iter().any(|(name, item)| { + tr.0.trait_items(db).items.iter().any(|(name, item)| { matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name }) }) @@ -1629,11 +1605,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( .map_bound(|c| match c { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let id = match id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - let is_auto = db.trait_signature(id).flags.contains(TraitFlags::AUTO); + let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); if is_auto { Some(ExistentialPredicate::AutoTrait(t.def_id())) } else { @@ -1677,7 +1649,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new( interner, - SolverDefId::TraitId(trait_), + trait_.into(), [] as [crate::next_solver::GenericArg<'_>; 0], ))); bounds.push(sized_clause); @@ -1694,10 +1666,7 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>( ) -> Option<(TraitRef<'db>, TypeAliasId)> { let interner = DbInterner::new_with(db, None, None); rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { - let trait_id = match t.as_ref().skip_binder().def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; + let trait_id = t.as_ref().skip_binder().def_id.0; let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; Some((t.skip_binder(), assoc_type)) }) @@ -1727,10 +1696,7 @@ fn named_associated_type_shorthand_candidates<'db, R>( ) -> Option { let db = interner.db; let mut search = |t: TraitRef<'db>| -> Option { - let trait_id = match t.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; + let trait_id = t.def_id.0; let mut checked_traits = FxHashSet::default(); let mut check_trait = |trait_id: TraitId| { let name = &db.trait_signature(trait_id).name; @@ -1773,11 +1739,7 @@ fn named_associated_type_shorthand_candidates<'db, R>( rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(), _ => continue, }; - let trait_id = match trait_id { - SolverDefId::TraitId(trait_id) => trait_id, - _ => continue, - }; - stack.push(trait_id); + stack.push(trait_id.0); } tracing::debug!(?stack); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index ccdb5a0bdb4a9..7d6734303c48b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -208,10 +208,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { tracing::debug!(?trait_ref); self.skip_resolved_segment(); let segment = self.current_or_prev_segment; - let trait_id = match trait_ref.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; + let trait_id = trait_ref.def_id.0; let found = trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 8bd71df7c191d..f0be352fdd151 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -168,11 +168,7 @@ impl TyFingerprint { _ => None, }) .next()?; - let trait_id = match trait_ref { - SolverDefId::TraitId(id) => id, - _ => panic!("Bad GenericDefId in trait ref"), - }; - TyFingerprint::Dyn(trait_id) + TyFingerprint::Dyn(trait_ref.0) } TyKind::Ref(_, _, mutability) => match mutability { rustc_ast_ir::Mutability::Mut => TyFingerprint::Ref(Mutability::Mut), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index cfafc65d18443..23789b06e828b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -81,7 +81,7 @@ impl<'db> std::fmt::Debug for InternedWrapperNoDebug; +pub type PlaceholderConst = Placeholder; #[derive(Copy, Clone, Hash, Eq, PartialEq)] pub struct ParamConst { @@ -304,7 +304,7 @@ impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { fn new_bound( interner: DbInterner<'db>, debruijn: rustc_type_ir::DebruijnIndex, - var: BoundVar, + var: BoundConst, ) -> Self { Const::new(interner, ConstKind::Bound(debruijn, var)) } @@ -314,7 +314,7 @@ impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { debruijn: rustc_type_ir::DebruijnIndex, var: rustc_type_ir::BoundVar, ) -> Self { - Const::new(interner, ConstKind::Bound(debruijn, var)) + Const::new(interner, ConstKind::Bound(debruijn, BoundConst { var })) } fn new_unevaluated( @@ -340,26 +340,41 @@ impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct BoundConst { + pub var: BoundVar, +} + +impl<'db> rustc_type_ir::inherent::BoundVarLike> for BoundConst { + fn var(self) -> BoundVar { + self.var + } + + fn assert_eq(self, var: BoundVarKind) { + var.expect_const() + } +} + impl<'db> PlaceholderLike> for PlaceholderConst { - type Bound = rustc_type_ir::BoundVar; + type Bound = BoundConst; fn universe(self) -> rustc_type_ir::UniverseIndex { self.universe } fn var(self) -> rustc_type_ir::BoundVar { - self.bound + self.bound.var } fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self { Placeholder { universe: ui, bound: self.bound } } - fn new(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { + fn new(ui: rustc_type_ir::UniverseIndex, var: BoundConst) -> Self { Placeholder { universe: ui, bound: var } } fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { - Placeholder { universe: ui, bound: var } + Placeholder { universe: ui, bound: BoundConst { var } } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index c9632ddcd4bb5..8bbc6e3370399 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -88,3 +88,60 @@ impl<'db> inherent::DefId> for SolverDefId { true } } + +macro_rules! declare_id_wrapper { + ($name:ident, $wraps:ident) => { + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub struct $name(pub $wraps); + + impl std::fmt::Debug for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&self.0, f) + } + } + + impl From<$name> for $wraps { + #[inline] + fn from(value: $name) -> $wraps { + value.0 + } + } + + impl From<$wraps> for $name { + #[inline] + fn from(value: $wraps) -> $name { + Self(value) + } + } + + impl From<$name> for SolverDefId { + #[inline] + fn from(value: $name) -> SolverDefId { + value.0.into() + } + } + + impl TryFrom for $name { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId) -> Result { + match value { + SolverDefId::$wraps(it) => Ok(Self(it)), + _ => Err(()), + } + } + } + + impl<'db> inherent::DefId> for $name { + fn as_local(self) -> Option { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } + } + }; +} + +declare_id_wrapper!(TraitIdWrapper, TraitId); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs index 3cc1e64b6add0..405a57d9e898c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs @@ -6,6 +6,8 @@ use rustc_type_ir::{ inherent::{IntoKind, Region as _}, }; +use crate::next_solver::BoundConst; + use super::{ Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, Ty, TyKind, }; @@ -18,7 +20,7 @@ use super::{ pub trait BoundVarReplacerDelegate<'db> { fn replace_region(&mut self, br: BoundRegion) -> Region<'db>; fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db>; - fn replace_const(&mut self, bv: BoundVar) -> Const<'db>; + fn replace_const(&mut self, bv: BoundConst) -> Const<'db>; } /// A simple delegate taking 3 mutable functions. The used functions must @@ -27,7 +29,7 @@ pub trait BoundVarReplacerDelegate<'db> { pub struct FnMutDelegate<'db, 'a> { pub regions: &'a mut (dyn FnMut(BoundRegion) -> Region<'db> + 'a), pub types: &'a mut (dyn FnMut(BoundTy) -> Ty<'db> + 'a), - pub consts: &'a mut (dyn FnMut(BoundVar) -> Const<'db> + 'a), + pub consts: &'a mut (dyn FnMut(BoundConst) -> Const<'db> + 'a), } impl<'db, 'a> BoundVarReplacerDelegate<'db> for FnMutDelegate<'db, 'a> { @@ -37,7 +39,7 @@ impl<'db, 'a> BoundVarReplacerDelegate<'db> for FnMutDelegate<'db, 'a> { fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { (self.types)(bt) } - fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { + fn replace_const(&mut self, bv: BoundConst) -> Const<'db> { (self.consts)(bv) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs index 007a674ad399a..4258f4c7ac68b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -167,7 +167,7 @@ impl<'db> FulfillmentCtxt<'db> { } let result = delegate.evaluate_root_goal(goal, Span::dummy(), stalled_on); - let GoalEvaluation { certainty, has_changed, stalled_on } = match result { + let GoalEvaluation { goal: _, certainty, has_changed, stalled_on } = match result { Ok(result) => result, Err(NoSolution) => { errors.push(NextSolverError::TrueError(obligation)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index d284eb9c6b419..4e124d07d2b38 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -384,7 +384,6 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< signature_parts_ty: signature_parts_ty.expect_ty(), tupled_upvars_ty: tupled_upvars_ty.expect_ty(), coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), }, _ => panic!("GenericArgs were likely not for a CoroutineClosure."), } @@ -400,7 +399,6 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< resume_ty: resume_ty.expect_ty(), yield_ty: yield_ty.expect_ty(), return_ty: return_ty.expect_ty(), - witness: Ty::new_unit(interner), tupled_upvars_ty: Ty::new_unit(interner), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs index 0448f03463e4b..6c7a87ef52494 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs @@ -6,6 +6,7 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html +use crate::next_solver::BoundConst; use crate::next_solver::{ AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind, @@ -95,7 +96,7 @@ where GenericArgKind::Type(ty) => ty, r => panic!("{bound_ty:?} is a type but value is {r:?}"), }, - consts: &mut |bound_ct: BoundVar| match var_values[bound_ct].kind() { + consts: &mut |bound_ct: BoundConst| match var_values[bound_ct.var].kind() { GenericArgKind::Const(ct) => ct, c => panic!("{bound_ct:?} is a const but value is {c:?}"), }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 58832aef89529..585719144ef42 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -37,7 +37,7 @@ use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use crate::next_solver::fold::BoundVarReplacerDelegate; use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries; -use crate::next_solver::{BoundRegion, BoundTy, BoundVarKind}; +use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind}; use super::generics::GenericParamDef; use super::{ @@ -864,8 +864,8 @@ impl<'db> InferCtxt<'db> { fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { self.args[bt.var.index()].expect_ty() } - fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { - self.args[bv.index()].expect_const() + fn replace_const(&mut self, bv: BoundConst) -> Const<'db> { + self.args[bv.var.index()].expect_const() } } let delegate = ToFreshVars { args }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs index bb80c5157109c..62028e0e70399 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs @@ -10,8 +10,8 @@ use crate::next_solver::fold::FnMutDelegate; use crate::next_solver::infer::InferCtxt; use crate::next_solver::infer::snapshot::CombinedSnapshot; use crate::next_solver::{ - Binder, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst, PlaceholderRegion, - PlaceholderTy, Region, Ty, + Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst, + PlaceholderRegion, PlaceholderTy, Region, Ty, }; impl<'db> InferCtxt<'db> { @@ -50,10 +50,10 @@ impl<'db> InferCtxt<'db> { PlaceholderTy { universe: next_universe, bound: bound_ty }, ) }, - consts: &mut |bound_var: BoundVar| { + consts: &mut |bound: BoundConst| { Const::new_placeholder( self.interner, - PlaceholderConst { universe: next_universe, bound: bound_var }, + PlaceholderConst { universe: next_universe, bound }, ) }, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 6e1a5e9645573..5709beaefc292 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -19,7 +19,7 @@ use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::{ AdtDef as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike as _, Span as _, }; -use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, @@ -44,9 +44,11 @@ use rustc_type_ir::{ use crate::lower_nextsolver::{self, TyLoweringContext}; use crate::method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}; +use crate::next_solver::infer::InferCtxt; use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; use crate::next_solver::{ - CanonicalVarKind, FxIndexMap, InternedWrapperNoDebug, RegionAssumptions, SolverDefIds, + BoundConst, CanonicalVarKind, FxIndexMap, InternedWrapperNoDebug, RegionAssumptions, + SolverContext, SolverDefIds, TraitIdWrapper, }; use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase}; @@ -858,10 +860,35 @@ impl<'db> rustc_type_ir::relate::Relate> for Pattern<'db> { interned_vec_db!(PatList, Pattern); +macro_rules! as_lang_item { + ( + $solver_enum:ident, $var:ident; + + ignore = { + $( $ignore:ident ),* $(,)? + } + + $( $variant:ident ),* $(,)? + ) => {{ + // Ensure exhaustiveness. + if let Some(it) = None::<$solver_enum> { + match it { + $( $solver_enum::$variant => {} )* + $( $solver_enum::$ignore => {} )* + } + } + match $var { + $( LangItem::$variant => Some($solver_enum::$variant), )* + _ => None + } + }}; +} + impl<'db> rustc_type_ir::Interner for DbInterner<'db> { type DefId = SolverDefId; type LocalDefId = SolverDefId; type LocalDefIds = SolverDefIds; + type TraitId = TraitIdWrapper; type Span = Span; type GenericArgs = GenericArgs<'db>; @@ -923,7 +950,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { type Const = Const<'db>; type PlaceholderConst = PlaceholderConst; type ParamConst = ParamConst; - type BoundConst = rustc_type_ir::BoundVar; + type BoundConst = BoundConst; type ValueConst = ValueConst<'db>; type ValTree = Valtree<'db>; type ExprConst = ExprConst; @@ -1117,7 +1144,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ); let alias_args = GenericArgs::new_from_iter(self, args.iter().skip(trait_generics.own_params.len())); - (TraitRef::new_from_args(self, trait_def_id, trait_args), alias_args) + (TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args) } fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool { @@ -1305,11 +1332,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { #[tracing::instrument(skip(self), ret)] fn explicit_super_predicates_of( self, - def_id: Self::DefId, + def_id: Self::TraitId, ) -> EarlyBinder> { let predicates: Vec<(Clause<'db>, Span)> = self .db() - .generic_predicates_ns(def_id.try_into().unwrap()) + .generic_predicates_ns(def_id.0.into()) .iter() .cloned() .map(|p| (p, Span::dummy())) @@ -1369,65 +1396,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { false } - fn require_lang_item( - self, - lang_item: rustc_type_ir::lang_items::TraitSolverLangItem, - ) -> Self::DefId { + fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId { let lang_item = match lang_item { - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFn => LangItem::AsyncFn, - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnKindHelper => unimplemented!(), - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnKindUpvars => unimplemented!(), - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnMut => LangItem::AsyncFnMut, - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnOnce => LangItem::AsyncFnOnce, - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnOnceOutput => { - LangItem::AsyncFnOnceOutput - } - rustc_type_ir::lang_items::TraitSolverLangItem::AsyncIterator => unimplemented!(), - rustc_type_ir::lang_items::TraitSolverLangItem::CallOnceFuture => { - LangItem::CallOnceFuture - } - rustc_type_ir::lang_items::TraitSolverLangItem::CallRefFuture => { - LangItem::CallRefFuture - } - rustc_type_ir::lang_items::TraitSolverLangItem::Clone => LangItem::Clone, - rustc_type_ir::lang_items::TraitSolverLangItem::Copy => LangItem::Copy, - rustc_type_ir::lang_items::TraitSolverLangItem::Coroutine => LangItem::Coroutine, - rustc_type_ir::lang_items::TraitSolverLangItem::CoroutineReturn => { - LangItem::CoroutineReturn - } - rustc_type_ir::lang_items::TraitSolverLangItem::CoroutineYield => { - LangItem::CoroutineYield - } - rustc_type_ir::lang_items::TraitSolverLangItem::Destruct => LangItem::Destruct, - rustc_type_ir::lang_items::TraitSolverLangItem::DiscriminantKind => { - LangItem::DiscriminantKind - } - rustc_type_ir::lang_items::TraitSolverLangItem::Drop => LangItem::Drop, - rustc_type_ir::lang_items::TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, - rustc_type_ir::lang_items::TraitSolverLangItem::Fn => LangItem::Fn, - rustc_type_ir::lang_items::TraitSolverLangItem::FnMut => LangItem::FnMut, - rustc_type_ir::lang_items::TraitSolverLangItem::FnOnce => LangItem::FnOnce, - rustc_type_ir::lang_items::TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, - rustc_type_ir::lang_items::TraitSolverLangItem::FusedIterator => unimplemented!(), - rustc_type_ir::lang_items::TraitSolverLangItem::Future => LangItem::Future, - rustc_type_ir::lang_items::TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, - rustc_type_ir::lang_items::TraitSolverLangItem::Iterator => LangItem::Iterator, - rustc_type_ir::lang_items::TraitSolverLangItem::Metadata => LangItem::Metadata, - rustc_type_ir::lang_items::TraitSolverLangItem::Option => LangItem::Option, - rustc_type_ir::lang_items::TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, - rustc_type_ir::lang_items::TraitSolverLangItem::Poll => LangItem::Poll, - rustc_type_ir::lang_items::TraitSolverLangItem::Sized => LangItem::Sized, - rustc_type_ir::lang_items::TraitSolverLangItem::MetaSized => LangItem::MetaSized, - rustc_type_ir::lang_items::TraitSolverLangItem::PointeeSized => LangItem::PointeeSized, - rustc_type_ir::lang_items::TraitSolverLangItem::TransmuteTrait => { - LangItem::TransmuteTrait - } - rustc_type_ir::lang_items::TraitSolverLangItem::Tuple => LangItem::Tuple, - rustc_type_ir::lang_items::TraitSolverLangItem::Unpin => LangItem::Unpin, - rustc_type_ir::lang_items::TraitSolverLangItem::Unsize => LangItem::Unsize, - rustc_type_ir::lang_items::TraitSolverLangItem::BikeshedGuaranteedNoDrop => { - unimplemented!() - } + SolverLangItem::AsyncFnKindUpvars => unimplemented!(), + SolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + SolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, + SolverLangItem::CallRefFuture => LangItem::CallRefFuture, + SolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, + SolverLangItem::CoroutineYield => LangItem::CoroutineYield, + SolverLangItem::DynMetadata => LangItem::DynMetadata, + SolverLangItem::FutureOutput => LangItem::FutureOutput, + SolverLangItem::Metadata => LangItem::Metadata, + SolverLangItem::Option => LangItem::Option, + SolverLangItem::Poll => LangItem::Poll, }; let target = hir_def::lang_item::lang_item( self.db(), @@ -1448,216 +1429,131 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } + fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> TraitIdWrapper { + let lang_item = match lang_item { + SolverTraitLangItem::AsyncFn => LangItem::AsyncFn, + SolverTraitLangItem::AsyncFnKindHelper => unimplemented!(), + SolverTraitLangItem::AsyncFnMut => LangItem::AsyncFnMut, + SolverTraitLangItem::AsyncFnOnce => LangItem::AsyncFnOnce, + SolverTraitLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + SolverTraitLangItem::AsyncIterator => unimplemented!(), + SolverTraitLangItem::Clone => LangItem::Clone, + SolverTraitLangItem::Copy => LangItem::Copy, + SolverTraitLangItem::Coroutine => LangItem::Coroutine, + SolverTraitLangItem::Destruct => LangItem::Destruct, + SolverTraitLangItem::DiscriminantKind => LangItem::DiscriminantKind, + SolverTraitLangItem::Drop => LangItem::Drop, + SolverTraitLangItem::Fn => LangItem::Fn, + SolverTraitLangItem::FnMut => LangItem::FnMut, + SolverTraitLangItem::FnOnce => LangItem::FnOnce, + SolverTraitLangItem::FnPtrTrait => LangItem::FnPtrTrait, + SolverTraitLangItem::FusedIterator => unimplemented!(), + SolverTraitLangItem::Future => LangItem::Future, + SolverTraitLangItem::Iterator => LangItem::Iterator, + SolverTraitLangItem::PointeeTrait => LangItem::PointeeTrait, + SolverTraitLangItem::Sized => LangItem::Sized, + SolverTraitLangItem::MetaSized => LangItem::MetaSized, + SolverTraitLangItem::PointeeSized => LangItem::PointeeSized, + SolverTraitLangItem::TransmuteTrait => LangItem::TransmuteTrait, + SolverTraitLangItem::Tuple => LangItem::Tuple, + SolverTraitLangItem::Unpin => LangItem::Unpin, + SolverTraitLangItem::Unsize => LangItem::Unsize, + SolverTraitLangItem::BikeshedGuaranteedNoDrop => { + unimplemented!() + } + }; + lang_item + .resolve_trait(self.db(), self.krate.expect("Must have self.krate")) + .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")) + .into() + } + #[allow(clippy::match_like_matches_macro)] - fn is_lang_item( - self, - def_id: Self::DefId, - lang_item: rustc_type_ir::lang_items::TraitSolverLangItem, - ) -> bool { - use rustc_type_ir::lang_items::TraitSolverLangItem::*; - - // FIXME: derive PartialEq on TraitSolverLangItem - self.as_lang_item(def_id).map_or(false, |l| match (l, lang_item) { - (AsyncFn, AsyncFn) => true, - (AsyncFnKindHelper, AsyncFnKindHelper) => true, - (AsyncFnKindUpvars, AsyncFnKindUpvars) => true, - (AsyncFnMut, AsyncFnMut) => true, - (AsyncFnOnce, AsyncFnOnce) => true, - (AsyncFnOnceOutput, AsyncFnOnceOutput) => true, - (AsyncIterator, AsyncIterator) => true, - (CallOnceFuture, CallOnceFuture) => true, - (CallRefFuture, CallRefFuture) => true, - (Clone, Clone) => true, - (Copy, Copy) => true, - (Coroutine, Coroutine) => true, - (CoroutineReturn, CoroutineReturn) => true, - (CoroutineYield, CoroutineYield) => true, - (Destruct, Destruct) => true, - (DiscriminantKind, DiscriminantKind) => true, - (Drop, Drop) => true, - (DynMetadata, DynMetadata) => true, - (Fn, Fn) => true, - (FnMut, FnMut) => true, - (FnOnce, FnOnce) => true, - (FnPtrTrait, FnPtrTrait) => true, - (FusedIterator, FusedIterator) => true, - (Future, Future) => true, - (FutureOutput, FutureOutput) => true, - (Iterator, Iterator) => true, - (Metadata, Metadata) => true, - (Option, Option) => true, - (PointeeTrait, PointeeTrait) => true, - (Poll, Poll) => true, - (Sized, Sized) => true, - (TransmuteTrait, TransmuteTrait) => true, - (Tuple, Tuple) => true, - (Unpin, Unpin) => true, - (Unsize, Unsize) => true, - _ => false, - }) + fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool { + use SolverLangItem::*; + + // FIXME: derive PartialEq on SolverLangItem + self.as_lang_item(def_id) + .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) } - fn as_lang_item( - self, - def_id: Self::DefId, - ) -> Option { - use rustc_type_ir::lang_items::TraitSolverLangItem; + #[allow(clippy::match_like_matches_macro)] + fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool { + use SolverTraitLangItem::*; + + // FIXME: derive PartialEq on SolverTraitLangItem + self.as_trait_lang_item(def_id) + .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) + } + fn as_lang_item(self, def_id: Self::DefId) -> Option { let def_id: AttrDefId = match def_id { SolverDefId::TraitId(id) => id.into(), SolverDefId::TypeAliasId(id) => id.into(), + SolverDefId::AdtId(id) => id.into(), _ => panic!("Unexpected SolverDefId in as_lang_item"), }; let lang_item = self.db().lang_attr(def_id)?; - Some(match lang_item { - LangItem::Sized => TraitSolverLangItem::Sized, - LangItem::MetaSized => TraitSolverLangItem::MetaSized, - LangItem::PointeeSized => TraitSolverLangItem::PointeeSized, - LangItem::Unsize => TraitSolverLangItem::Unsize, - LangItem::StructuralPeq => return None, - LangItem::StructuralTeq => return None, - LangItem::Copy => TraitSolverLangItem::Copy, - LangItem::Clone => TraitSolverLangItem::Clone, - LangItem::Sync => return None, - LangItem::DiscriminantKind => TraitSolverLangItem::DiscriminantKind, - LangItem::Discriminant => return None, - LangItem::PointeeTrait => TraitSolverLangItem::PointeeTrait, - LangItem::Metadata => TraitSolverLangItem::Metadata, - LangItem::DynMetadata => TraitSolverLangItem::DynMetadata, - LangItem::Freeze => return None, - LangItem::FnPtrTrait => TraitSolverLangItem::FnPtrTrait, - LangItem::FnPtrAddr => return None, - LangItem::Drop => TraitSolverLangItem::Drop, - LangItem::Destruct => TraitSolverLangItem::Destruct, - LangItem::CoerceUnsized => return None, - LangItem::DispatchFromDyn => return None, - LangItem::TransmuteOpts => return None, - LangItem::TransmuteTrait => TraitSolverLangItem::TransmuteTrait, - LangItem::Add => return None, - LangItem::Sub => return None, - LangItem::Mul => return None, - LangItem::Div => return None, - LangItem::Rem => return None, - LangItem::Neg => return None, - LangItem::Not => return None, - LangItem::BitXor => return None, - LangItem::BitAnd => return None, - LangItem::BitOr => return None, - LangItem::Shl => return None, - LangItem::Shr => return None, - LangItem::AddAssign => return None, - LangItem::SubAssign => return None, - LangItem::MulAssign => return None, - LangItem::DivAssign => return None, - LangItem::RemAssign => return None, - LangItem::BitXorAssign => return None, - LangItem::BitAndAssign => return None, - LangItem::BitOrAssign => return None, - LangItem::ShlAssign => return None, - LangItem::ShrAssign => return None, - LangItem::Index => return None, - LangItem::IndexMut => return None, - LangItem::UnsafeCell => return None, - LangItem::VaList => return None, - LangItem::Deref => return None, - LangItem::DerefMut => return None, - LangItem::DerefTarget => return None, - LangItem::Receiver => return None, - LangItem::Fn => TraitSolverLangItem::Fn, - LangItem::FnMut => TraitSolverLangItem::FnMut, - LangItem::FnOnce => TraitSolverLangItem::FnOnce, - LangItem::FnOnceOutput => return None, - LangItem::Future => TraitSolverLangItem::Future, - LangItem::CoroutineState => return None, - LangItem::Coroutine => TraitSolverLangItem::Coroutine, - LangItem::CoroutineReturn => TraitSolverLangItem::CoroutineReturn, - LangItem::CoroutineYield => TraitSolverLangItem::CoroutineYield, - LangItem::Unpin => TraitSolverLangItem::Unpin, - LangItem::Pin => return None, - LangItem::PartialEq => return None, - LangItem::PartialOrd => return None, - LangItem::CVoid => return None, - LangItem::Panic => return None, - LangItem::PanicNounwind => return None, - LangItem::PanicFmt => return None, - LangItem::PanicDisplay => return None, - LangItem::ConstPanicFmt => return None, - LangItem::PanicBoundsCheck => return None, - LangItem::PanicMisalignedPointerDereference => return None, - LangItem::PanicInfo => return None, - LangItem::PanicLocation => return None, - LangItem::PanicImpl => return None, - LangItem::PanicCannotUnwind => return None, - LangItem::BeginPanic => return None, - LangItem::FormatAlignment => return None, - LangItem::FormatArgument => return None, - LangItem::FormatArguments => return None, - LangItem::FormatCount => return None, - LangItem::FormatPlaceholder => return None, - LangItem::FormatUnsafeArg => return None, - LangItem::ExchangeMalloc => return None, - LangItem::BoxFree => return None, - LangItem::DropInPlace => return None, - LangItem::AllocLayout => return None, - LangItem::Start => return None, - LangItem::EhPersonality => return None, - LangItem::EhCatchTypeinfo => return None, - LangItem::OwnedBox => return None, - LangItem::PhantomData => return None, - LangItem::ManuallyDrop => return None, - LangItem::MaybeUninit => return None, - LangItem::AlignOffset => return None, - LangItem::Termination => return None, - LangItem::Try => return None, - LangItem::Tuple => TraitSolverLangItem::Tuple, - LangItem::SliceLen => return None, - LangItem::TryTraitFromResidual => return None, - LangItem::TryTraitFromOutput => return None, - LangItem::TryTraitBranch => return None, - LangItem::TryTraitFromYeet => return None, - LangItem::PointerLike => return None, - LangItem::ConstParamTy => return None, - LangItem::Poll => TraitSolverLangItem::Poll, - LangItem::PollReady => return None, - LangItem::PollPending => return None, - LangItem::ResumeTy => return None, - LangItem::GetContext => return None, - LangItem::Context => return None, - LangItem::FuturePoll => return None, - LangItem::FutureOutput => TraitSolverLangItem::FutureOutput, - LangItem::Option => TraitSolverLangItem::Option, - LangItem::OptionSome => return None, - LangItem::OptionNone => return None, - LangItem::ResultOk => return None, - LangItem::ResultErr => return None, - LangItem::ControlFlowContinue => return None, - LangItem::ControlFlowBreak => return None, - LangItem::IntoFutureIntoFuture => return None, - LangItem::IntoIterIntoIter => return None, - LangItem::IteratorNext => return None, - LangItem::Iterator => TraitSolverLangItem::Iterator, - LangItem::PinNewUnchecked => return None, - LangItem::RangeFrom => return None, - LangItem::RangeFull => return None, - LangItem::RangeInclusiveStruct => return None, - LangItem::RangeInclusiveNew => return None, - LangItem::Range => return None, - LangItem::RangeToInclusive => return None, - LangItem::RangeTo => return None, - LangItem::String => return None, - LangItem::CStr => return None, - LangItem::AsyncFn => TraitSolverLangItem::AsyncFn, - LangItem::AsyncFnMut => TraitSolverLangItem::AsyncFnMut, - LangItem::AsyncFnOnce => TraitSolverLangItem::AsyncFnOnce, - LangItem::AsyncFnOnceOutput => TraitSolverLangItem::AsyncFnOnceOutput, - LangItem::CallRefFuture => TraitSolverLangItem::CallRefFuture, - LangItem::CallOnceFuture => TraitSolverLangItem::CallOnceFuture, - LangItem::Ordering => return None, - LangItem::PanicNullPointerDereference => return None, - LangItem::ReceiverTarget => return None, - LangItem::UnsafePinned => return None, - LangItem::AsyncFnOnceOutput => TraitSolverLangItem::AsyncFnOnceOutput, - }) + as_lang_item!( + SolverLangItem, lang_item; + + ignore = { + AsyncFnKindUpvars, + } + + Metadata, + DynMetadata, + CoroutineReturn, + CoroutineYield, + Poll, + FutureOutput, + Option, + AsyncFnOnceOutput, + CallRefFuture, + CallOnceFuture, + AsyncFnOnceOutput, + ) + } + + fn as_trait_lang_item(self, def_id: Self::TraitId) -> Option { + let def_id: AttrDefId = def_id.0.into(); + let lang_item = self.db().lang_attr(def_id)?; + as_lang_item!( + SolverTraitLangItem, lang_item; + + ignore = { + AsyncFnKindHelper, + AsyncIterator, + BikeshedGuaranteedNoDrop, + FusedIterator, + } + + Sized, + MetaSized, + PointeeSized, + Unsize, + Copy, + Clone, + DiscriminantKind, + PointeeTrait, + FnPtrTrait, + Drop, + Destruct, + TransmuteTrait, + Fn, + FnMut, + FnOnce, + Future, + Coroutine, + Unpin, + Tuple, + Iterator, + AsyncFn, + AsyncFnMut, + AsyncFnOnce, + AsyncFnOnceOutput, + AsyncFnOnceOutput, + ) } fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator { @@ -1670,15 +1566,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn for_each_relevant_impl( self, - trait_def_id: Self::DefId, + trait_: Self::TraitId, self_ty: Self::Ty, mut f: impl FnMut(Self::DefId), ) { - let trait_ = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("for_each_relevant_impl called for non-trait"), - }; - + let trait_ = trait_.0; let self_ty_fp = TyFingerprint::for_trait_impl_ns(&self_ty); let fps: &[TyFingerprint] = match self_ty.kind() { TyKind::Infer(InferTy::IntVar(..)) => &ALL_INT_FPS, @@ -1775,42 +1667,26 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } - fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool { - let trait_ = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("Unexpected SolverDefId in trait_is_auto"), - }; - let trait_data = self.db().trait_signature(trait_); + fn trait_is_auto(self, trait_: Self::TraitId) -> bool { + let trait_data = self.db().trait_signature(trait_.0); trait_data.flags.contains(TraitFlags::AUTO) } - fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool { - let trait_ = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("Unexpected SolverDefId in trait_is_alias"), - }; - let trait_data = self.db().trait_signature(trait_); + fn trait_is_alias(self, trait_: Self::TraitId) -> bool { + let trait_data = self.db().trait_signature(trait_.0); trait_data.flags.contains(TraitFlags::ALIAS) } - fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool { - let trait_ = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - crate::dyn_compatibility::dyn_compatibility(self.db(), trait_).is_none() + fn trait_is_dyn_compatible(self, trait_: Self::TraitId) -> bool { + crate::dyn_compatibility::dyn_compatibility(self.db(), trait_.0).is_none() } - fn trait_is_fundamental(self, def_id: Self::DefId) -> bool { - let trait_ = match def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("Unexpected SolverDefId in trait_is_fundamental"), - }; - let trait_data = self.db().trait_signature(trait_); + fn trait_is_fundamental(self, trait_: Self::TraitId) -> bool { + let trait_data = self.db().trait_signature(trait_.0); trait_data.flags.contains(TraitFlags::FUNDAMENTAL) } - fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool { + fn trait_may_be_implemented_via_object(self, trait_def_id: Self::TraitId) -> bool { // FIXME(next-solver): should check the `TraitFlags` for // the `#[rustc_do_not_implement_via_object]` flag true @@ -1920,12 +1796,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { (*entry.or_insert_with(|| BoundVarKind::Ty(BoundTyKind::Anon))).expect_ty(); Ty::new_bound(self.interner, DebruijnIndex::ZERO, BoundTy { var, kind }) } - fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { - let entry = self.map.entry(bv); + fn replace_const(&mut self, bv: BoundConst) -> Const<'db> { + let entry = self.map.entry(bv.var); let index = entry.index(); let var = BoundVar::from_usize(index); let () = (*entry.or_insert_with(|| BoundVarKind::Const)).expect_const(); - Const::new_bound(self.interner, DebruijnIndex::ZERO, var) + Const::new_bound(self.interner, DebruijnIndex::ZERO, BoundConst { var }) } } @@ -2008,24 +1884,16 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { unimplemented!() } - fn is_default_trait(self, def_id: Self::DefId) -> bool { - self.as_lang_item(def_id).map_or(false, |l| matches!(l, TraitSolverLangItem::Sized)) + fn is_default_trait(self, def_id: Self::TraitId) -> bool { + self.as_trait_lang_item(def_id).map_or(false, |l| matches!(l, SolverTraitLangItem::Sized)) } - fn trait_is_coinductive(self, trait_def_id: Self::DefId) -> bool { - let id = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - self.db().trait_signature(id).flags.contains(TraitFlags::COINDUCTIVE) + fn trait_is_coinductive(self, trait_: Self::TraitId) -> bool { + self.db().trait_signature(trait_.0).flags.contains(TraitFlags::COINDUCTIVE) } - fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool { - let id = match trait_def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - self.db().trait_signature(id).flags.contains(TraitFlags::UNSAFE) + fn trait_is_unsafe(self, trait_: Self::TraitId) -> bool { + self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) } fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool { @@ -2047,6 +1915,20 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { // FIXME(next-solver) unimplemented!() } + + type Probe = rustc_type_ir::solve::inspect::Probe>; + fn mk_probe(self, probe: rustc_type_ir::solve::inspect::Probe) -> Self::Probe { + probe + } + fn evaluate_root_goal_for_proof_tree_raw( + self, + canonical_goal: rustc_type_ir::solve::CanonicalInput, + ) -> (rustc_type_ir::solve::QueryResult, Self::Probe) { + rustc_next_trait_solver::solve::evaluate_root_goal_for_proof_tree_raw_provider::< + SolverContext<'db>, + Self, + >(self, canonical_goal) + } } impl<'db> DbInterner<'db> { @@ -2072,7 +1954,9 @@ impl<'db> DbInterner<'db> { BoundTy { var: shift_bv(t.var), kind: t.kind }, ) }, - consts: &mut |c| Const::new_bound(self, DebruijnIndex::ZERO, shift_bv(c)), + consts: &mut |c| { + Const::new_bound(self, DebruijnIndex::ZERO, BoundConst { var: shift_bv(c.var) }) + }, }, ) } @@ -2135,6 +2019,7 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { SolverDefId, + TraitIdWrapper, Pattern<'db>, Safety, FnAbi, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs index 4d32b27132357..407e157564397 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs @@ -58,10 +58,7 @@ impl<'db> IrPrint> for DbInterner<'db> { fn print_debug(t: &ty::TraitRef, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { salsa::with_attached_database(|db| { - let trait_ = match t.def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("Expected trait."), - }; + let trait_ = t.def_id.0; let self_ty = &t.args.as_slice()[0]; let trait_args = &t.args.as_slice()[1..]; if trait_args.is_empty() { @@ -122,10 +119,7 @@ impl<'db> IrPrint> for DbInterner<'db> { fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { salsa::with_attached_database(|db| { - let trait_ = match t.def_id { - SolverDefId::TraitId(id) => id, - _ => panic!("Expected trait."), - }; + let trait_ = t.def_id.0; fmt.write_str(&format!( "ExistentialTraitRef({:?}[{:?}])", db.as_view::().trait_signature(trait_).name.as_str(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 6755d065e10d3..dc54ee7d58785 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -22,6 +22,7 @@ use rustc_type_ir::{ use salsa::plumbing::FromId; use salsa::{Id, plumbing::AsId}; +use crate::next_solver::BoundConst; use crate::{ ConcreteConst, ConstScalar, ImplTraitId, Interner, MemoryMap, db::{ @@ -125,12 +126,12 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { match c.kind() { rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => { - let GenericParamId::ConstParamId(id) = self.params[var.as_usize()] else { + let GenericParamId::ConstParamId(id) = self.params[var.var.as_usize()] else { unreachable!() }; Const::new( self.cx(), - rustc_type_ir::ConstKind::Param(ParamConst { index: var.as_u32(), id }), + rustc_type_ir::ConstKind::Param(ParamConst { index: var.var.as_u32(), id }), ) } _ => c.super_fold_with(self), @@ -286,11 +287,8 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { .flags .contains(TraitFlags::AUTO) { - ExistentialPredicate::AutoTrait(SolverDefId::TraitId( - trait_id, - )) + ExistentialPredicate::AutoTrait(trait_id.into()) } else { - let def_id = SolverDefId::TraitId(trait_id); let args = GenericArgs::new_from_iter( interner, trait_ref @@ -301,7 +299,7 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { .map(|a| a.to_nextsolver(interner)), ); let trait_ref = ExistentialTraitRef::new_from_args( - interner, def_id, args, + interner, trait_id.into(), args, ); ExistentialPredicate::Trait(trait_ref) } @@ -473,7 +471,7 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { match &data.value { chalk_ir::ConstValue::BoundVar(bound_var) => rustc_type_ir::ConstKind::Bound( bound_var.debruijn.to_nextsolver(interner), - rustc_type_ir::BoundVar::from_usize(bound_var.index), + BoundConst { var: rustc_type_ir::BoundVar::from_usize(bound_var.index) }, ), chalk_ir::ConstValue::InferenceVar(inference_var) => { rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var( @@ -871,11 +869,7 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef { fn to_nextsolver(&self, interner: DbInterner<'db>) -> TraitRef<'db> { let args = self.substitution.to_nextsolver(interner); - TraitRef::new_from_args( - interner, - SolverDefId::TraitId(from_chalk_trait_id(self.trait_id)), - args, - ) + TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args) } } @@ -1207,20 +1201,14 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) trait_ref.def_id, [self_ty.into()].into_iter().chain(trait_ref.args.iter()), ); - let trait_id = match trait_ref.def_id { - SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; + let trait_id = to_chalk_trait_id(trait_ref.def_id.0); let substitution = convert_args_for_result(interner, trait_ref.args.as_slice()); let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; chalk_ir::WhereClause::Implemented(trait_ref) } rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => { - let trait_id = match trait_ { - SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; + let trait_id = to_chalk_trait_id(trait_.0); let substitution = chalk_ir::Substitution::from1( Interner, convert_ty_for_result(interner, self_ty), @@ -1354,7 +1342,7 @@ pub fn convert_const_for_result<'db>( rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - var.index(), + var.var.index(), )) } rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index 50261bb5e3816..c86d3a4aadb22 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -15,6 +15,8 @@ use rustc_type_ir::{ }; use smallvec::{SmallVec, smallvec}; +use crate::next_solver::TraitIdWrapper; + use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db}; pub type BoundExistentialPredicate<'db> = Binder<'db, ExistentialPredicate<'db>>; @@ -72,7 +74,7 @@ interned_vec_db!(BoundExistentialPredicates, BoundExistentialPredicate); impl<'db> rustc_type_ir::inherent::BoundExistentialPredicates> for BoundExistentialPredicates<'db> { - fn principal_def_id(self) -> Option< as rustc_type_ir::Interner>::DefId> { + fn principal_def_id(self) -> Option { self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) } @@ -89,9 +91,7 @@ impl<'db> rustc_type_ir::inherent::BoundExistentialPredicates> .transpose() } - fn auto_traits( - self, - ) -> impl IntoIterator as rustc_type_ir::Interner>::DefId> { + fn auto_traits(self) -> impl IntoIterator { self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 45888ac4d2352..1d0ee0e488dcf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -2,10 +2,10 @@ use hir_def::{AssocItemId, GeneralConstId, TypeAliasId}; use rustc_next_trait_solver::delegate::SolverDelegate; +use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::{ InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex, inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _}, - lang_items::TraitSolverLangItem, solve::{Certainty, NoSolution}, }; @@ -225,14 +225,14 @@ impl<'db> SolverDelegate for SolverContext<'db> { } if trait_pred.polarity() == PredicatePolarity::Positive { - match self.0.cx().as_lang_item(trait_pred.def_id()) { - Some(TraitSolverLangItem::Sized) | Some(TraitSolverLangItem::MetaSized) => { + match self.0.cx().as_trait_lang_item(trait_pred.def_id()) { + Some(SolverTraitLangItem::Sized) | Some(SolverTraitLangItem::MetaSized) => { let predicate = self.resolve_vars_if_possible(goal.predicate); if sizedness_fast_path(self.cx(), predicate, goal.param_env) { return Some(Certainty::Yes); } } - Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { + Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); // Unlike `Sized` traits, which always prefer the built-in impl, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 92f1076e75eca..4794e2d604509 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -4,6 +4,7 @@ use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId}; use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; +use rustc_type_ir::Interner; use rustc_type_ir::{ BoundVar, ClosureKind, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, UintTy, @@ -19,6 +20,7 @@ use rustc_type_ir::{ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; +use crate::next_solver::GenericArg; use crate::{ db::HirDatabase, interner::InternedWrapperNoDebug, @@ -645,6 +647,31 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) } + fn new_coroutine_witness_for_coroutine( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + coroutine_args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + // HACK: Coroutine witness types are lifetime erased, so they + // never reference any lifetime args from the coroutine. We erase + // the regions here since we may get into situations where a + // coroutine is recursively contained within itself, leading to + // witness types that differ by region args. This means that + // cycle detection in fulfillment will not kick in, which leads + // to unnecessary overflows in async code. See the issue: + // . + let coroutine_args = interner.mk_args_from_iter(coroutine_args.iter().map(|arg| { + match arg { + GenericArg::Ty(_) | GenericArg::Const(_) => arg, + GenericArg::Lifetime(_) => { + crate::next_solver::Region::new(interner, rustc_type_ir::RegionKind::ReErased) + .into() + } + } + })); + Ty::new_coroutine_witness(interner, def_id, coroutine_args) + } + fn new_ptr(interner: DbInterner<'db>, ty: Self, mutbl: rustc_ast_ir::Mutability) -> Self { Ty::new(interner, TyKind::RawPtr(ty, mutbl)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index 1db02e9eb611c..50b96a160ed10 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -14,7 +14,7 @@ use rustc_type_ir::inherent::{ AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike, Ty as _, }; -use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity, @@ -29,8 +29,8 @@ use rustc_type_ir::{InferCtxtLike, TypeFoldable}; use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext}; use crate::next_solver::infer::InferCtxt; use crate::next_solver::{ - CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion, - TypingMode, + BoundConst, CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, + PlaceholderRegion, TypingMode, }; use crate::{ db::HirDatabase, @@ -511,7 +511,7 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable>>( ) -> T { let types = &mut |ty: BoundTy| args.as_slice()[ty.var.index()].expect_ty(); let regions = &mut |region: BoundRegion| args.as_slice()[region.var.index()].expect_region(); - let consts = &mut |const_: BoundVar| args.as_slice()[const_.index()].expect_const(); + let consts = &mut |const_: BoundConst| args.as_slice()[const_.var.index()].expect_const(); let mut instantiate = BoundVarReplacer::new(interner, FnMutDelegate { types, regions, consts }); b.skip_binder().fold_with(&mut instantiate) } @@ -654,7 +654,10 @@ impl<'db> TypeFolder> for MiniCanonicalizer<'_, 'db> { ConstKind::Infer(infer) => { let len = self.vars.len(); let var = *self.vars.entry(c.into()).or_insert(len); - Const::new(self.cx(), ConstKind::Bound(self.db, BoundVar::from_usize(var))) + Const::new( + self.cx(), + ConstKind::Bound(self.db, BoundConst { var: BoundVar::from_usize(var) }), + ) } _ => c.super_fold_with(self), } @@ -852,7 +855,7 @@ pub struct PlaceholderReplacer<'a, 'db> { infcx: &'a InferCtxt<'db>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, BoundTy>, - mapped_consts: FxIndexMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], current_index: DebruijnIndex, } @@ -862,7 +865,7 @@ impl<'a, 'db> PlaceholderReplacer<'a, 'db> { infcx: &'a InferCtxt<'db>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, BoundTy>, - mapped_consts: FxIndexMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], value: T, ) -> T { @@ -1026,9 +1029,9 @@ pub fn sizedness_fast_path<'db>( if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder() && trait_pred.polarity == PredicatePolarity::Positive { - let sizedness = match tcx.as_lang_item(trait_pred.def_id()) { - Some(TraitSolverLangItem::Sized) => SizedTraitKind::Sized, - Some(TraitSolverLangItem::MetaSized) => SizedTraitKind::MetaSized, + let sizedness = match tcx.as_trait_lang_item(trait_pred.def_id()) { + Some(SolverTraitLangItem::Sized) => SizedTraitKind::Sized, + Some(SolverTraitLangItem::MetaSized) => SizedTraitKind::MetaSized, _ => return false, }; @@ -1051,7 +1054,10 @@ pub fn sizedness_fast_path<'db>( && clause_pred.self_ty() == trait_pred.self_ty() && (clause_pred.def_id() == trait_pred.def_id() || (sizedness == SizedTraitKind::MetaSized - && tcx.is_lang_item(clause_pred.def_id(), TraitSolverLangItem::Sized))) + && tcx.is_trait_lang_item( + clause_pred.def_id(), + SolverTraitLangItem::Sized, + ))) { return true; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 092d4e3a8d9e9..881b1c1a9db26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -212,10 +212,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl rustc_type_ir::ClauseKind::Trait(t) => { let t = rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args); - let trait_id = match t.def_id() { - crate::next_solver::SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; + let trait_id = to_chalk_trait_id(t.def_id().0); let substitution = convert_args_for_result(interner, t.trait_ref.args.as_slice()); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 46d3a2bcd67ce..6610375451dd0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -86,8 +86,7 @@ use hir_ty::{ method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - ClauseKind, DbInterner, GenericArgs, SolverDefId, infer::InferCtxt, - mapping::ChalkToNextSolver, + ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, mapping::ChalkToNextSolver, }, primitive::UintTy, traits::FnTrait, @@ -4251,13 +4250,7 @@ impl TypeParam { db.generic_predicates_for_param_ns(self.id.parent(), self.id.into(), None) .iter() .filter_map(|pred| match &pred.kind().skip_binder() { - ClauseKind::Trait(trait_ref) => { - let trait_ = match trait_ref.def_id() { - SolverDefId::TraitId(t) => t, - _ => unreachable!(), - }; - Some(Trait::from(trait_)) - } + ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), _ => None, }) .collect() @@ -4515,11 +4508,7 @@ impl Impl { pub fn trait_(self, db: &dyn HirDatabase) -> Option { let trait_ref = db.impl_trait_ns(self.id)?; let id = trait_ref.skip_binder().def_id; - let id = match id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - Some(Trait { id }) + Some(Trait { id: id.0 }) } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { @@ -4609,11 +4598,7 @@ impl<'db> TraitRef<'db> { } pub fn trait_(&self) -> Trait { - let id = match self.trait_ref.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - Trait { id } + Trait { id: self.trait_ref.def_id.0 } } pub fn self_ty(&self) -> TypeNs<'_> { @@ -5984,11 +5969,7 @@ impl<'db> TypeNs<'db> { infcx.interner, [self.ty].into_iter().chain(args.iter().map(|t| t.ty)).map(|t| t.into()), ); - let trait_ref = hir_ty::next_solver::TraitRef::new( - infcx.interner, - SolverDefId::TraitId(trait_.id), - args, - ); + let trait_ref = hir_ty::next_solver::TraitRef::new(infcx.interner, trait_.id.into(), args); let pred_kind = rustc_type_ir::Binder::dummy(rustc_type_ir::PredicateKind::Clause( rustc_type_ir::ClauseKind::Trait(rustc_type_ir::TraitPredicate { From 9a1eb85394e3612213e829ed871eb281079a2364 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 5 Sep 2025 04:53:05 +0000 Subject: [PATCH 139/251] Prepare for merging from rust-lang/rust This updates the rust-version file to b3cfb8faf84c5f3b7909479a9f9b6a3290d5f4d7. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 7420b6200967c..a51d86c3d6f15 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9385c64c95d971329e62917adc4349c8ccdbafe0 +b3cfb8faf84c5f3b7909479a9f9b6a3290d5f4d7 From 5cadd4541c96edf0caaf1847b3c13b1ced4d5121 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Sep 2025 09:07:08 +0200 Subject: [PATCH 140/251] make use of Duration::from_nanos_u128 --- src/tools/miri/src/clock.rs | 9 +-------- src/tools/miri/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index 34465e9cac60d..47608f873a481 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -46,14 +46,7 @@ impl Instant { InstantKind::Virtual { nanoseconds: earlier }, ) => { let duration = nanoseconds.saturating_sub(earlier); - // `Duration` does not provide a nice constructor from a `u128` of nanoseconds, - // so we have to implement this ourselves. - // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9). - // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX. - let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX); - // It is impossible for nanosecond to overflow because u32::MAX > 1e9. - let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap(); - Duration::new(seconds, nanosecond) + Duration::from_nanos_u128(duration) } _ => panic!("all `Instant` must be of the same kind"), } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 0856411b8e836..a00d9525fab54 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -18,6 +18,7 @@ #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] +#![feature(duration_from_nanos_u128)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, From b9b235acb088aa88d96890c930e174ab56abbccd Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 5 Sep 2025 15:34:49 +0800 Subject: [PATCH 141/251] Fix indent for unresolved_field fixes Examples --- ```rust mod indent { struct Foo {} fn foo() { let foo = Foo{}; foo.bar$0; } } ``` **Before this PR**: ```rust mod indent { struct Foo { bar: () } fn foo() { let foo = Foo{}; foo.bar; } } ``` **After this PR**: ```rust mod indent { struct Foo { bar: () } fn foo() { let foo = Foo{}; foo.bar; } } ``` --- New field list add newline ```rust mod indent { struct Foo; fn foo() { Foo.bar$0; } } ``` **Before this PR**: ```rust mod indent { struct Foo{ bar: () } fn foo() { Foo.bar; } } ``` **After this PR**: ```rust mod indent { struct Foo { bar: (), } fn foo() { Foo.bar; } } ``` --- .../src/handlers/unresolved_field.rs | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 690158989679b..358e0c43c2a93 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -1,5 +1,3 @@ -use std::iter; - use either::Either; use hir::{Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union, db::ExpandDatabase}; use ide_db::text_edit::TextEdit; @@ -194,17 +192,20 @@ fn add_field_to_struct_fix( Some(make::visibility_pub_crate()) }; // FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563 - let indent = IndentLevel::from_node(struct_syntax.value) + 1; + let indent = IndentLevel::from_node(struct_syntax.value); - let field = make::record_field(visibility, field_name, suggested_type).indent(indent); - let record_field_list = make::record_field_list(iter::once(field)); + let field = + make::record_field(visibility, field_name, suggested_type).indent(indent + 1); // A Unit Struct with no `;` is invalid syntax. We should not suggest this fix. let semi_colon = algo::skip_trivia_token(struct_syntax.value.last_token()?, Direction::Prev)?; if semi_colon.kind() != SyntaxKind::SEMICOLON { return None; } - src_change_builder.replace(semi_colon.text_range(), record_field_list.to_string()); + src_change_builder.replace( + semi_colon.text_range(), + format!(" {{\n{}{field},\n{indent}}}", indent + 1), + ); Some(Assist { id: AssistId::quick_fix("convert-unit-struct-to-record-struct"), @@ -230,7 +231,7 @@ fn record_field_layout( field_list: ast::RecordFieldList, struct_syntax: &SyntaxNode, ) -> Option<(TextSize, String)> { - let (offset, needs_comma, trailing_new_line, indent) = match field_list.fields().last() { + let (offset, needs_comma, indent) = match field_list.fields().last() { Some(record_field) => { let syntax = algo::skip_trivia_token(field_list.r_curly_token()?, Direction::Prev)?; @@ -239,19 +240,22 @@ fn record_field_layout( ( last_field_syntax.text_range().end(), syntax.kind() != SyntaxKind::COMMA, - false, last_field_indent, ) } // Empty Struct. Add a field right before the closing brace None => { let indent = IndentLevel::from_node(struct_syntax) + 1; - let offset = field_list.r_curly_token()?.text_range().start(); - (offset, false, true, indent) + let offset = field_list.l_curly_token()?.text_range().end(); + (offset, false, indent) } }; - let comma = if needs_comma { ",\n" } else { "" }; - let trailing_new_line = if trailing_new_line { "\n" } else { "" }; + let trailing_new_line = if !field_list.syntax().text().contains_char('\n') { + format!("\n{}", field_list.indent_level()) + } else { + String::new() + }; + let comma = if needs_comma { ",\n" } else { "\n" }; let record_field = make::record_field(visibility, name, suggested_type); Some((offset, format!("{comma}{indent}{record_field}{trailing_new_line}"))) @@ -377,18 +381,24 @@ fn foo() { fn unresolved_field_fix_on_unit() { check_fix( r#" + mod indent { struct Foo; fn foo() { Foo.bar$0; } + } "#, r#" - struct Foo{ bar: () } + mod indent { + struct Foo { + bar: (), + } fn foo() { Foo.bar; } + } "#, ); } @@ -396,6 +406,7 @@ fn foo() { fn unresolved_field_fix_on_empty() { check_fix( r#" + mod indent { struct Foo{ } @@ -403,8 +414,10 @@ fn foo() { let foo = Foo{}; foo.bar$0; } + } "#, r#" + mod indent { struct Foo{ bar: () } @@ -413,6 +426,32 @@ fn foo() { let foo = Foo{}; foo.bar; } + } + "#, + ); + + check_fix( + r#" + mod indent { + struct Foo {} + + fn foo() { + let foo = Foo{}; + foo.bar$0; + } + } + "#, + r#" + mod indent { + struct Foo { + bar: () + } + + fn foo() { + let foo = Foo{}; + foo.bar; + } + } "#, ); } From 1186db896e2f4013b1f15612b31ed18e2b653228 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Sep 2025 10:28:47 +0200 Subject: [PATCH 142/251] atomics: unify handling min/max and the other RMWs --- src/tools/miri/src/concurrency/data_race.rs | 85 +++++-------------- src/tools/miri/src/concurrency/genmc/dummy.rs | 19 +---- src/tools/miri/src/concurrency/genmc/mod.rs | 29 +------ src/tools/miri/src/intrinsics/atomic.rs | 74 ++++++++++------ src/tools/miri/src/intrinsics/mod.rs | 3 + 5 files changed, 83 insertions(+), 127 deletions(-) diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 19d37a691d90c..a7822d0d6fa31 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -56,6 +56,7 @@ use super::vector_clock::{VClock, VTimestamp, VectorIdx}; use super::weak_memory::EvalContextExt as _; use crate::concurrency::GlobalDataRaceHandler; use crate::diagnostics::RacingOp; +use crate::intrinsics::AtomicRmwOp; use crate::*; pub type AllocState = VClockAlloc; @@ -778,9 +779,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { &mut self, place: &MPlaceTy<'tcx>, rhs: &ImmTy<'tcx>, - op: mir::BinOp, - not: bool, - atomic: AtomicRwOrd, + atomic_op: AtomicRmwOp, + ord: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -793,8 +793,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this, place.ptr().addr(), place.layout.size, - atomic, - (op, not), + place.layout.backend_repr.is_signed(), + ord, + atomic_op, rhs.to_scalar(), old.to_scalar(), )?; @@ -804,13 +805,26 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } - let val = this.binary_op(op, &old, rhs)?; - let val = if not { this.unary_op(mir::UnOp::Not, &val)? } else { val }; + let val = match atomic_op { + AtomicRmwOp::MirOp { op, neg } => { + let val = this.binary_op(op, &old, rhs)?; + if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val } + } + AtomicRmwOp::Max => { + let lt = this.binary_op(mir::BinOp::Lt, &old, rhs)?.to_scalar().to_bool()?; + if lt { rhs } else { &old }.clone() + } + AtomicRmwOp::Min => { + let lt = this.binary_op(mir::BinOp::Lt, &old, rhs)?.to_scalar().to_bool()?; + if lt { &old } else { rhs }.clone() + } + }; + this.allow_data_races_mut(|this| this.write_immediate(*val, place))?; - this.validate_atomic_rmw(place, atomic)?; + this.validate_atomic_rmw(place, ord)?; - this.buffered_atomic_rmw(val.to_scalar(), place, atomic, old.to_scalar())?; + this.buffered_atomic_rmw(val.to_scalar(), place, ord, old.to_scalar())?; interp_ok(old) } @@ -852,59 +866,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { interp_ok(old) } - /// Perform an conditional atomic exchange with a memory place and a new - /// scalar value, the old value is returned. - fn atomic_min_max_scalar( - &mut self, - place: &MPlaceTy<'tcx>, - rhs: ImmTy<'tcx>, - min: bool, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx>> { - let this = self.eval_context_mut(); - this.atomic_access_check(place, AtomicAccessType::Rmw)?; - - let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; - - // Inform GenMC about the atomic min/max operation. - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let (old_val, new_val) = genmc_ctx.atomic_min_max_op( - this, - place.ptr().addr(), - place.layout.size, - atomic, - min, - old.layout.backend_repr.is_signed(), - rhs.to_scalar(), - old.to_scalar(), - )?; - // The store might be the latest store in coherence order (determined by GenMC). - // If it is, we need to update the value in Miri's memory: - if let Some(new_val) = new_val { - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; - } - return interp_ok(ImmTy::from_scalar(old_val, old.layout)); - } - - let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; - - #[rustfmt::skip] // rustfmt makes this unreadable - let new_val = if min { - if lt { &old } else { &rhs } - } else { - if lt { &rhs } else { &old } - }; - - this.allow_data_races_mut(|this| this.write_immediate(**new_val, place))?; - - this.validate_atomic_rmw(place, atomic)?; - - this.buffered_atomic_rmw(new_val.to_scalar(), place, atomic, old.to_scalar())?; - - // Return the old value. - interp_ok(old) - } - /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. If `can_fail_spuriously` is true, diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs index 1960ef37cc9f3..7c420961ec54a 100644 --- a/src/tools/miri/src/concurrency/genmc/dummy.rs +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -1,8 +1,8 @@ use rustc_abi::{Align, Size}; use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult}; -use rustc_middle::mir; pub use self::run::run_genmc_mode; +use crate::intrinsics::AtomicRmwOp; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, @@ -94,22 +94,9 @@ impl GenmcCtx { _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, _address: Size, _size: Size, - _ordering: AtomicRwOrd, - (_rmw_op, _not): (mir::BinOp, bool), - _rhs_scalar: Scalar, - _old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - unreachable!() - } - - pub(crate) fn atomic_min_max_op<'tcx>( - &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _ordering: AtomicRwOrd, - _min: bool, _is_signed: bool, + _ordering: AtomicRwOrd, + _atomic_op: AtomicRmwOp, _rhs_scalar: Scalar, _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option)> { diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs index b5d20a439c01c..26ce0b9c43ac7 100644 --- a/src/tools/miri/src/concurrency/genmc/mod.rs +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -7,7 +7,7 @@ use genmc_sys::{ }; use rustc_abi::{Align, Size}; use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult, interp_ok}; -use rustc_middle::{mir, throw_machine_stop, throw_ub_format, throw_unsup_format}; +use rustc_middle::{throw_machine_stop, throw_ub_format, throw_unsup_format}; // FIXME(genmc,tracing): Implement some work-around for enabling debug/trace level logging (currently disabled statically in rustc). use tracing::{debug, info}; @@ -15,6 +15,7 @@ use self::global_allocations::{EvalContextExt as _, GlobalAllocationHandler}; use self::helper::{MAX_ACCESS_SIZE, genmc_scalar_to_scalar, scalar_to_genmc_scalar}; use self::thread_id_map::ThreadIdMap; use crate::concurrency::genmc::helper::split_access; +use crate::intrinsics::AtomicRmwOp; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, MiriMachine, MiriMemoryKind, Scalar, TerminationInfo, ThreadId, ThreadManager, VisitProvenance, @@ -298,8 +299,9 @@ impl GenmcCtx { _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, _address: Size, _size: Size, + _is_signed: bool, _ordering: AtomicRwOrd, - (_rmw_op, _not): (mir::BinOp, bool), + _atomic_op: AtomicRmwOp, _rhs_scalar: Scalar, _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option)> { @@ -310,29 +312,6 @@ impl GenmcCtx { throw_unsup_format!("FIXME(genmc): Add support for atomic RMW.") } - /// Inform GenMC about an atomic `min` or `max` operation. - /// - /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. - /// - /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. - pub(crate) fn atomic_min_max_op<'tcx>( - &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _ordering: AtomicRwOrd, - _min: bool, - _is_signed: bool, - _rhs_scalar: Scalar, - _old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!( - !self.get_alloc_data_races(), - "atomic min/max operation with data race checking disabled." - ); - throw_unsup_format!("FIXME(genmc): Add support for atomic min/max.") - } - /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. /// /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index e634125292754..c9f63640b8541 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -5,10 +5,13 @@ use rustc_middle::{mir, ty}; use super::check_intrinsic_arg_count; use crate::*; -pub enum AtomicOp { - /// The `bool` indicates whether the result of the operation should be negated (`UnOp::Not`, - /// must be a boolean-typed operation). - MirOp(mir::BinOp, bool), +pub enum AtomicRmwOp { + MirOp { + op: mir::BinOp, + /// Indicates whether the result of the operation should be negated (`UnOp::Not`, must be a + /// boolean-typed operation). + neg: bool, + }, Max, Min, } @@ -106,55 +109,85 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "or" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::BitOr, neg: false }, + rw_ord(ord), + )?; } "xor" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::BitXor, neg: false }, + rw_ord(ord), + )?; } "and" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::BitAnd, neg: false }, + rw_ord(ord), + )?; } "nand" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::BitAnd, neg: true }, + rw_ord(ord), + )?; } "xadd" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::Add, neg: false }, + rw_ord(ord), + )?; } "xsub" => { let ord = get_ord_at(2); - this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?; + this.atomic_rmw_op( + args, + dest, + AtomicRmwOp::MirOp { op: BinOp::Sub, neg: false }, + rw_ord(ord), + )?; } "min" => { let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); - this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?; + this.atomic_rmw_op(args, dest, AtomicRmwOp::Min, rw_ord(ord))?; } "umin" => { let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); - this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?; + this.atomic_rmw_op(args, dest, AtomicRmwOp::Min, rw_ord(ord))?; } "max" => { let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); - this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?; + this.atomic_rmw_op(args, dest, AtomicRmwOp::Max, rw_ord(ord))?; } "umax" => { let ord = get_ord_at(1); // Later we will use the type to indicate signed vs unsigned, // so make sure it matches the intrinsic name. assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); - this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?; + this.atomic_rmw_op(args, dest, AtomicRmwOp::Max, rw_ord(ord))?; } _ => return interp_ok(EmulateItemResult::NotSupported), @@ -222,8 +255,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { &mut self, args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, - atomic_op: AtomicOp, - atomic: AtomicRwOrd, + atomic_op: AtomicRmwOp, + ord: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -240,14 +273,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ); } - let old = match atomic_op { - AtomicOp::Min => - this.atomic_min_max_scalar(&place, rhs, /* min */ true, atomic)?, - AtomicOp::Max => - this.atomic_min_max_scalar(&place, rhs, /* min */ false, atomic)?, - AtomicOp::MirOp(op, not) => - this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?, - }; + let old = this.atomic_rmw_op_immediate(&place, &rhs, atomic_op, ord)?; this.write_immediate(*old, dest)?; // old value is returned interp_ok(()) } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 5e46768b0e6cf..f6f9af47d0a74 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -3,6 +3,9 @@ mod atomic; mod simd; +pub use self::atomic::AtomicRmwOp; + +#[rustfmt::skip] // prevent `use` reordering use std::ops::Neg; use rand::Rng; From 69c7652a01a721be007cb9f7ef56f1e483f39fc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Sep 2025 13:31:01 +0200 Subject: [PATCH 143/251] atomic rmw intrinsics: RHS must be an integer --- src/tools/miri/src/intrinsics/atomic.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index c9f63640b8541..9bb0ab70de236 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -264,8 +264,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let place = this.deref_pointer(place)?; let rhs = this.read_immediate(rhs)?; + // The LHS can be a pointer, the RHS must be an integer. if !(place.layout.ty.is_integral() || place.layout.ty.is_raw_ptr()) - || !(rhs.layout.ty.is_integral() || rhs.layout.ty.is_raw_ptr()) + || !rhs.layout.ty.is_integral() { span_bug!( this.cur_span(), From a5bb60b19c1113a751c7dac00ea8ae0ac20cd15f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 6 Sep 2025 13:07:53 +0800 Subject: [PATCH 144/251] Add allow `else` keyword completion in LetStmt Example --- ```rust fn foo() { let _ = 2 el$0 } ``` -> ```rust fn foo() { let _ = 2 else { $0 }; } ``` --- .../ide-completion/src/completions/expr.rs | 6 +- .../ide-completion/src/completions/keyword.rs | 40 +++++ .../crates/ide-completion/src/context.rs | 1 + .../ide-completion/src/context/analysis.rs | 41 +++-- .../ide-completion/src/tests/expression.rs | 149 ++++++++++++++++++ 5 files changed, 220 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 1972f166134a4..2c7d9e97c44e7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -61,6 +61,7 @@ pub(crate) fn complete_expr_path( after_if_expr, in_condition, incomplete_let, + after_incomplete_let, in_value, ref ref_expr_parent, after_amp, @@ -385,8 +386,11 @@ pub(crate) fn complete_expr_path( add_keyword("let", "let $1 = $0;"); } - if after_if_expr { + if after_if_expr || after_incomplete_let { add_keyword("else", "else {\n $0\n}"); + } + + if after_if_expr { add_keyword("else if", "else if $1 {\n $0\n}"); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index aea4e119f2076..b3d770997ab0c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -247,6 +247,46 @@ fn main() { "#, ); + check_edit( + "else", + r#" +fn main() { + let x = if true { + () + } $0 + let y = 92; +} +"#, + r#" +fn main() { + let x = if true { + () + } else { + $0 +}; + let y = 92; +} +"#, + ); + + check_edit( + "else", + r#" +fn main() { + let x = 2 $0 + let y = 92; +} +"#, + r#" +fn main() { + let x = 2 else { + $0 +}; + let y = 92; +} +"#, + ); + check_edit( "loop", r#" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 265462d220169..007475688d209 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -147,6 +147,7 @@ pub(crate) struct PathExprCtx<'db> { /// Whether this expression is the direct condition of an if or while expression pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, + pub(crate) after_incomplete_let: bool, pub(crate) in_value: bool, pub(crate) ref_expr_parent: Option, pub(crate) after_amp: bool, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 17978b4c10798..33b98a33cabf6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -947,25 +947,29 @@ fn classify_name_ref<'db>( None } }; - let after_if_expr = |node: SyntaxNode| { - let prev_expr = (|| { - let node = match node.parent().and_then(ast::ExprStmt::cast) { - Some(stmt) => stmt.syntax().clone(), - None => node, - }; - let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; + let prev_expr = |node: SyntaxNode| { + let node = match node.parent().and_then(ast::ExprStmt::cast) { + Some(stmt) => stmt.syntax().clone(), + None => node, + }; + let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; - match_ast! { - match prev_sibling { - ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()), - ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()), - ast::Expr(expr) => Some(expr), - _ => None, - } + match_ast! { + match prev_sibling { + ast::ExprStmt(stmt) => stmt.expr().filter(|_| stmt.semicolon_token().is_none()), + ast::LetStmt(stmt) => stmt.initializer().filter(|_| stmt.semicolon_token().is_none()), + ast::Expr(expr) => Some(expr), + _ => None, } - })(); + } + }; + let after_if_expr = |node: SyntaxNode| { + let prev_expr = prev_expr(node); matches!(prev_expr, Some(ast::Expr::IfExpr(_))) }; + let after_incomplete_let = |node: SyntaxNode| { + prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast) + }; // We do not want to generate path completions when we are sandwiched between an item decl signature and its body. // ex. trait Foo $0 {} @@ -1265,10 +1269,14 @@ fn classify_name_ref<'db>( }; let is_func_update = func_update_record(it); let in_condition = is_in_condition(&expr); + let after_incomplete_let = after_incomplete_let(it.clone()).is_some(); + let incomplete_expr_stmt = + it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none()); let incomplete_let = it .parent() .and_then(ast::LetStmt::cast) - .is_some_and(|it| it.semicolon_token().is_none()); + .is_some_and(|it| it.semicolon_token().is_none()) + || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true); let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); @@ -1292,6 +1300,7 @@ fn classify_name_ref<'db>( self_param, in_value, incomplete_let, + after_incomplete_let, impl_, in_match_guard, }, 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 7a0d00444129f..56fbd91a60fcc 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 @@ -450,6 +450,155 @@ fn completes_in_let_initializer() { ) } +#[test] +fn completes_let_else() { + check( + r#"fn main() { let _ = 2 $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + + check( + r#"fn main() { let _ = 2 el$0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + + check_edit( + "else", + r#" +fn main() { + let _ = 2 $0 +} +"#, + r#" +fn main() { + let _ = 2 else { + $0 +}; +} +"#, + ); + + check_edit( + "else", + r#" +fn main() { + let _ = 2 el$0 +} +"#, + r#" +fn main() { + let _ = 2 else { + $0 +}; +} +"#, + ); + + check_edit( + "else", + r#" +fn main() { + let _ = 2 $0; +} +"#, + r#" +fn main() { + let _ = 2 else { + $0 +}; +} +"#, + ); + + check_edit( + "else", + r#" +fn main() { + let _ = 2 el$0; +} +"#, + r#" +fn main() { + let _ = 2 else { + $0 +}; +} +"#, + ); +} + #[test] fn completes_after_ref_expr() { check( From 93101b5783b522469320b60926918f308ddae6b6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 6 Sep 2025 14:32:36 +0200 Subject: [PATCH 145/251] s390x: use the new `u128::funnel_shl` --- library/stdarch/crates/core_arch/src/lib.rs | 3 ++- .../crates/core_arch/src/s390x/vector.rs | 17 +++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index 7d3cbd55ad85c..26a9cb5899183 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -33,7 +33,8 @@ x86_amx_intrinsics, f16, aarch64_unstable_target_feature, - bigint_helper_methods + bigint_helper_methods, + funnel_shifts )] #![cfg_attr(test, feature(test, abi_vectorcall, stdarch_internal))] #![deny(clippy::missing_inline_in_public_items)] diff --git a/library/stdarch/crates/core_arch/src/s390x/vector.rs b/library/stdarch/crates/core_arch/src/s390x/vector.rs index f6d14c45e0d2b..f018344ead12d 100644 --- a/library/stdarch/crates/core_arch/src/s390x/vector.rs +++ b/library/stdarch/crates/core_arch/src/s390x/vector.rs @@ -3513,17 +3513,6 @@ mod sealed { a.vec_srdb::<7>(b) } - unsafe fn funnel_shl_u128(a: u128, b: u128, c: u128) -> u128 { - #[repr(simd)] - struct Single([u128; 1]); - - transmute(simd_funnel_shl::( - transmute(a), - transmute(b), - transmute(c), - )) - } - macro_rules! impl_vec_sld { ($($ty:ident)*) => { $( @@ -3533,21 +3522,21 @@ mod sealed { #[target_feature(enable = "vector")] unsafe fn vec_sld(self, b: Self) -> Self { static_assert_uimm_bits!(C, 4); - transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 * 8 })) + transmute(u128::funnel_shl(transmute(self), transmute(b), C * 8)) } #[inline] #[target_feature(enable = "vector")] unsafe fn vec_sldw(self, b: Self) -> Self { static_assert_uimm_bits!(C, 2); - transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 * 4 * 8 })) + transmute(u128::funnel_shl(transmute(self), transmute(b), C * 4 * 8)) } #[inline] #[target_feature(enable = "vector-enhancements-2")] unsafe fn vec_sldb(self, b: Self) -> Self { static_assert_uimm_bits!(C, 3); - transmute(funnel_shl_u128(transmute(self), transmute(b), const { C as u128 })) + transmute(u128::funnel_shl(transmute(self), transmute(b), C)) } } From 589515bc8a1d4939c4a738e9bc895dcfb217d2d8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 12:37:15 +0200 Subject: [PATCH 146/251] update Cargo.lock --- library/stdarch/Cargo.lock | 217 ++++++++++++++++++++++++++----------- 1 file changed, 152 insertions(+), 65 deletions(-) diff --git a/library/stdarch/Cargo.lock b/library/stdarch/Cargo.lock index 9df0791b86523..a10a456acce1d 100644 --- a/library/stdarch/Cargo.lock +++ b/library/stdarch/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -43,29 +43,29 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "assert-instr-macro" @@ -84,30 +84,31 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "cc" -version = "1.2.31" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "clap" -version = "4.5.42" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -115,9 +116,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -127,9 +128,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.41" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -258,6 +259,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "fnv" version = "1.0.7" @@ -283,9 +290,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -323,12 +330,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -353,7 +360,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -379,9 +386,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "linked-hash-map" @@ -391,9 +398,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" @@ -428,9 +435,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -497,9 +504,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -507,9 +514,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -517,9 +524,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -529,9 +536,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -540,9 +547,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustc-demangle" @@ -593,9 +600,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.142" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -715,9 +722,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -774,7 +781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", - "indexmap 2.10.0", + "indexmap 2.11.0", "semver", ] @@ -791,20 +798,35 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys", + "windows-sys 0.60.2", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", ] [[package]] @@ -813,14 +835,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -829,48 +868,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -882,18 +969,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", From d70ef4f0a7468fe7fb2dfabf89d8ccbb956a45d9 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 12:38:02 +0200 Subject: [PATCH 147/251] move `compare_outputs` implementation into `SupportedArchitectureTest` definition --- .../crates/intrinsic-test/src/arm/mod.rs | 35 +++++++------------ .../crates/intrinsic-test/src/common/mod.rs | 31 +++++++++++++--- .../stdarch/crates/intrinsic-test/src/main.rs | 21 ++++------- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index 51f5ac4283783..d8f7ae9b30610 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -10,7 +10,6 @@ use std::fs::{self, File}; use rayon::prelude::*; use crate::common::cli::ProcessedCli; -use crate::common::compare::compare_outputs; use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; use crate::common::gen_rust::{ compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, write_main_rs, @@ -28,7 +27,17 @@ pub struct ArmArchitectureTest { } impl SupportedArchitectureTest for ArmArchitectureTest { - fn create(cli_options: ProcessedCli) -> Box { + type IntrinsicImpl = ArmIntrinsicType; + + fn cli_options(&self) -> &ProcessedCli { + &self.cli_options + } + + fn intrinsics(&self) -> &[Intrinsic] { + &self.intrinsics + } + + fn create(cli_options: ProcessedCli) -> Self { let a32 = cli_options.target.contains("v7"); let mut intrinsics = get_neon_intrinsics(&cli_options.filename, &cli_options.target) .expect("Error parsing input file"); @@ -50,10 +59,10 @@ impl SupportedArchitectureTest for ArmArchitectureTest { .collect::>(); intrinsics.dedup(); - Box::new(Self { + Self { intrinsics, cli_options, - }) + } } fn build_c_file(&self) -> bool { @@ -177,22 +186,4 @@ impl SupportedArchitectureTest for ArmArchitectureTest { compile_rust_programs(toolchain, target, linker) } - - fn compare_outputs(&self) -> bool { - if self.cli_options.toolchain.is_some() { - let intrinsics_name_list = self - .intrinsics - .iter() - .map(|i| i.name.clone()) - .collect::>(); - - compare_outputs( - &intrinsics_name_list, - &self.cli_options.runner, - &self.cli_options.target, - ) - } else { - true - } - } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index 5a57c8027db9b..f1def1e9c0eb0 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -1,5 +1,7 @@ use cli::ProcessedCli; +use crate::common::{intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition}; + pub mod argument; pub mod cli; pub mod compare; @@ -15,12 +17,33 @@ pub mod values; /// Architectures must support this trait /// to be successfully tested. pub trait SupportedArchitectureTest { - fn create(cli_options: ProcessedCli) -> Box - where - Self: Sized; + type IntrinsicImpl: IntrinsicTypeDefinition; + + fn cli_options(&self) -> &ProcessedCli; + fn intrinsics(&self) -> &[Intrinsic]; + + fn create(cli_options: ProcessedCli) -> Self; + fn build_c_file(&self) -> bool; fn build_rust_file(&self) -> bool; - fn compare_outputs(&self) -> bool; + + fn compare_outputs(&self) -> bool { + if self.cli_options().toolchain.is_some() { + let intrinsics_name_list = self + .intrinsics() + .iter() + .map(|i| i.name.clone()) + .collect::>(); + + compare::compare_outputs( + &intrinsics_name_list, + &self.cli_options().runner, + &self.cli_options().target, + ) + } else { + true + } + } } pub fn chunk_info(intrinsic_count: usize) -> (usize, usize) { diff --git a/library/stdarch/crates/intrinsic-test/src/main.rs b/library/stdarch/crates/intrinsic-test/src/main.rs index 538f317a2978b..44d7aafd827fe 100644 --- a/library/stdarch/crates/intrinsic-test/src/main.rs +++ b/library/stdarch/crates/intrinsic-test/src/main.rs @@ -13,23 +13,16 @@ fn main() { let args: Cli = clap::Parser::parse(); let processed_cli_options = ProcessedCli::new(args); - let test_environment_result: Option> = - match processed_cli_options.target.as_str() { - "aarch64-unknown-linux-gnu" - | "armv7-unknown-linux-gnueabihf" - | "aarch64_be-unknown-linux-gnu" => { - Some(ArmArchitectureTest::create(processed_cli_options)) - } + match processed_cli_options.target.as_str() { + "aarch64-unknown-linux-gnu" + | "armv7-unknown-linux-gnueabihf" + | "aarch64_be-unknown-linux-gnu" => run(ArmArchitectureTest::create(processed_cli_options)), - _ => None, - }; - - if test_environment_result.is_none() { - std::process::exit(0); + _ => std::process::exit(0), } +} - let test_environment = test_environment_result.unwrap(); - +fn run(test_environment: impl SupportedArchitectureTest) { info!("building C binaries"); if !test_environment.build_c_file() { std::process::exit(2); From 6ab097b2453c5247f8d78c7ed5dfd4184b9a1c1d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 12:42:48 +0200 Subject: [PATCH 148/251] move platform headers into `SupportedArchitectureTest` --- library/stdarch/crates/intrinsic-test/src/arm/mod.rs | 5 +++-- library/stdarch/crates/intrinsic-test/src/common/mod.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index d8f7ae9b30610..60e1ebe5f33ba 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -65,9 +65,10 @@ impl SupportedArchitectureTest for ArmArchitectureTest { } } + const PLATFORM_HEADERS: &[&str] = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; + fn build_c_file(&self) -> bool { let c_target = "aarch64"; - let platform_headers = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); @@ -81,7 +82,7 @@ impl SupportedArchitectureTest for ArmArchitectureTest { .map(|(i, chunk)| { let c_filename = format!("c_programs/mod_{i}.cpp"); let mut file = File::create(&c_filename).unwrap(); - write_mod_cpp(&mut file, notice, c_target, platform_headers, chunk).unwrap(); + write_mod_cpp(&mut file, notice, c_target, Self::PLATFORM_HEADERS, chunk).unwrap(); // compile this cpp file into a .o file. // diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index f1def1e9c0eb0..be08aaecaba19 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -24,6 +24,8 @@ pub trait SupportedArchitectureTest { fn create(cli_options: ProcessedCli) -> Self; + const PLATFORM_HEADERS: &[&str]; + fn build_c_file(&self) -> bool; fn build_rust_file(&self) -> bool; From 916424f38d1b3d763cf19c0392799d7208482573 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 13:16:40 +0200 Subject: [PATCH 149/251] move more constants into `SupportedArchitectureTest` --- .../crates/intrinsic-test/src/arm/config.rs | 13 ++--- .../crates/intrinsic-test/src/arm/mod.rs | 52 +++++++++++++------ .../crates/intrinsic-test/src/common/mod.rs | 16 ++++-- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/config.rs b/library/stdarch/crates/intrinsic-test/src/arm/config.rs index 9a7b37253d1cb..beaca621378d4 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/config.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/config.rs @@ -1,12 +1,7 @@ -pub fn build_notices(line_prefix: &str) -> String { - format!( - "\ -{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the -{line_prefix}test are derived from a JSON specification, published under the same license as the -{line_prefix}`intrinsic-test` crate.\n -" - ) -} +pub const NOTICE: &str = "\ +// This is a transient test file, not intended for distribution. Some aspects of the +// test are derived from a JSON specification, published under the same license as the +// `intrinsic-test` crate.\n"; pub const POLY128_OSTREAM_DEF: &str = r#"std::ostream& operator<<(std::ostream& os, poly128_t value) { std::stringstream temp; diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index 60e1ebe5f33ba..82dc5001adf06 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -5,11 +5,12 @@ mod intrinsic; mod json_parser; mod types; -use std::fs::{self, File}; +use std::fs::File; use rayon::prelude::*; use crate::common::cli::ProcessedCli; +use crate::common::compile_c::CppCompilation; use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; use crate::common::gen_rust::{ compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, write_main_rs, @@ -17,7 +18,6 @@ use crate::common::gen_rust::{ use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; use crate::common::{SupportedArchitectureTest, chunk_info}; -use config::{AARCH_CONFIGURATIONS, F16_FORMATTING_DEF, POLY128_OSTREAM_DEF, build_notices}; use intrinsic::ArmIntrinsicType; use json_parser::get_neon_intrinsics; @@ -65,24 +65,40 @@ impl SupportedArchitectureTest for ArmArchitectureTest { } } - const PLATFORM_HEADERS: &[&str] = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; + const NOTICE: &str = config::NOTICE; + + const PLATFORM_C_HEADERS: &[&str] = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; + const PLATFORM_C_DEFINITIONS: &str = config::POLY128_OSTREAM_DEF; + + const PLATFORM_RUST_DEFINITIONS: &str = config::F16_FORMATTING_DEF; + const PLATFORM_RUST_CFGS: &str = config::AARCH_CONFIGURATIONS; + + fn cpp_compilation(&self) -> Option { + compile::build_cpp_compilation(&self.cli_options) + } fn build_c_file(&self) -> bool { let c_target = "aarch64"; - let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); + let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); - let cpp_compiler_wrapped = compile::build_cpp_compilation(&self.cli_options); + let cpp_compiler_wrapped = self.cpp_compilation(); - let notice = &build_notices("// "); - fs::create_dir_all("c_programs").unwrap(); - self.intrinsics + std::fs::create_dir_all("c_programs").unwrap(); + self.intrinsics() .par_chunks(chunk_size) .enumerate() .map(|(i, chunk)| { let c_filename = format!("c_programs/mod_{i}.cpp"); let mut file = File::create(&c_filename).unwrap(); - write_mod_cpp(&mut file, notice, c_target, Self::PLATFORM_HEADERS, chunk).unwrap(); + write_mod_cpp( + &mut file, + Self::NOTICE, + c_target, + Self::PLATFORM_C_HEADERS, + chunk, + ) + .unwrap(); // compile this cpp file into a .o file. // @@ -103,8 +119,8 @@ impl SupportedArchitectureTest for ArmArchitectureTest { write_main_cpp( &mut file, c_target, - POLY128_OSTREAM_DEF, - self.intrinsics.iter().map(|i| i.name.as_str()), + Self::PLATFORM_C_DEFINITIONS, + self.intrinsics().iter().map(|i| i.name.as_str()), ) .unwrap(); @@ -149,7 +165,7 @@ impl SupportedArchitectureTest for ArmArchitectureTest { write_main_rs( &mut main_rs, chunk_count, - AARCH_CONFIGURATIONS, + Self::PLATFORM_RUST_CFGS, "", self.intrinsics.iter().map(|i| i.name.as_str()), ) @@ -159,7 +175,6 @@ impl SupportedArchitectureTest for ArmArchitectureTest { let toolchain = self.cli_options.toolchain.as_deref(); let linker = self.cli_options.linker.as_deref(); - let notice = &build_notices("// "); self.intrinsics .par_chunks(chunk_size) .enumerate() @@ -170,9 +185,14 @@ impl SupportedArchitectureTest for ArmArchitectureTest { trace!("generating `{rust_filename}`"); let mut file = File::create(rust_filename)?; - let cfg = AARCH_CONFIGURATIONS; - let definitions = F16_FORMATTING_DEF; - write_lib_rs(&mut file, architecture, notice, cfg, definitions, chunk)?; + write_lib_rs( + &mut file, + architecture, + Self::NOTICE, + Self::PLATFORM_RUST_CFGS, + Self::PLATFORM_RUST_DEFINITIONS, + chunk, + )?; let toml_filename = format!("rust_programs/mod_{i}/Cargo.toml"); trace!("generating `{toml_filename}`"); diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index be08aaecaba19..13e6c9fe9e28e 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -1,6 +1,8 @@ use cli::ProcessedCli; -use crate::common::{intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition}; +use crate::common::{ + compile_c::CppCompilation, intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition, +}; pub mod argument; pub mod cli; @@ -17,14 +19,22 @@ pub mod values; /// Architectures must support this trait /// to be successfully tested. pub trait SupportedArchitectureTest { - type IntrinsicImpl: IntrinsicTypeDefinition; + type IntrinsicImpl: IntrinsicTypeDefinition + Sync; fn cli_options(&self) -> &ProcessedCli; fn intrinsics(&self) -> &[Intrinsic]; fn create(cli_options: ProcessedCli) -> Self; - const PLATFORM_HEADERS: &[&str]; + const NOTICE: &str; + + const PLATFORM_C_HEADERS: &[&str]; + const PLATFORM_C_DEFINITIONS: &str; + + const PLATFORM_RUST_CFGS: &str; + const PLATFORM_RUST_DEFINITIONS: &str; + + fn cpp_compilation(&self) -> Option; fn build_c_file(&self) -> bool; fn build_rust_file(&self) -> bool; From 9d9ca01bfa541e9badd9f34c776b588cfbf0e3ce Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 13:23:24 +0200 Subject: [PATCH 150/251] move `print_result_c` into the inner intrinsic type --- .../intrinsic-test/src/arm/intrinsic.rs | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs index fd93eff76e09c..7c31fd4d9dd0a 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs @@ -41,18 +41,27 @@ impl IntrinsicDefinition for Intrinsic { /// rust debug output format for the return type. The generated line assumes /// there is an int i in scope which is the current pass number. fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { - let lanes = if self.results().num_vectors() > 1 { - (0..self.results().num_vectors()) + self.results().print_result_c(indentation, additional) + } +} + +impl ArmIntrinsicType { + /// Generates a std::cout for the intrinsics results that will match the + /// rust debug output format for the return type. The generated line assumes + /// there is an int i in scope which is the current pass number. + fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { + let lanes = if self.num_vectors() > 1 { + (0..self.num_vectors()) .map(|vector| { format!( r#""{ty}(" << {lanes} << ")""#, - ty = self.results().c_single_vector_type(), - lanes = (0..self.results().num_lanes()) + ty = self.c_single_vector_type(), + lanes = (0..self.num_lanes()) .map(move |idx| -> std::string::String { format!( "{cast}{lane_fn}(__return_value.val[{vector}], {lane})", - cast = self.results().c_promotion(), - lane_fn = self.results().get_lane_function(), + cast = self.c_promotion(), + lane_fn = self.get_lane_function(), lane = idx, vector = vector, ) @@ -63,13 +72,13 @@ impl IntrinsicDefinition for Intrinsic { }) .collect::>() .join(r#" << ", " << "#) - } else if self.results().num_lanes() > 1 { - (0..self.results().num_lanes()) + } else if self.num_lanes() > 1 { + (0..self.num_lanes()) .map(|idx| -> std::string::String { format!( "{cast}{lane_fn}(__return_value, {lane})", - cast = self.results().c_promotion(), - lane_fn = self.results().get_lane_function(), + cast = self.c_promotion(), + lane_fn = self.get_lane_function(), lane = idx ) }) @@ -78,28 +87,27 @@ impl IntrinsicDefinition for Intrinsic { } else { format!( "{promote}cast<{cast}>(__return_value)", - cast = match self.results.kind() { - TypeKind::Float if self.results().inner_size() == 16 => "float16_t".to_string(), - TypeKind::Float if self.results().inner_size() == 32 => "float".to_string(), - TypeKind::Float if self.results().inner_size() == 64 => "double".to_string(), - TypeKind::Int(Sign::Signed) => format!("int{}_t", self.results().inner_size()), - TypeKind::Int(Sign::Unsigned) => - format!("uint{}_t", self.results().inner_size()), - TypeKind::Poly => format!("poly{}_t", self.results().inner_size()), + cast = match self.kind() { + TypeKind::Float if self.inner_size() == 16 => "float16_t".to_string(), + TypeKind::Float if self.inner_size() == 32 => "float".to_string(), + TypeKind::Float if self.inner_size() == 64 => "double".to_string(), + TypeKind::Int(Sign::Signed) => format!("int{}_t", self.inner_size()), + TypeKind::Int(Sign::Unsigned) => format!("uint{}_t", self.inner_size()), + TypeKind::Poly => format!("poly{}_t", self.inner_size()), ty => todo!("print_result_c - Unknown type: {:#?}", ty), }, - promote = self.results().c_promotion(), + promote = self.c_promotion(), ) }; format!( r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, - ty = if self.results().is_simd() { - format!("{}(", self.results().c_type()) + ty = if self.is_simd() { + format!("{}(", self.c_type()) } else { String::from("") }, - close = if self.results.is_simd() { ")" } else { "" }, + close = if self.is_simd() { ")" } else { "" }, ) } } From 2ba0a6e48974e3f358c18724ebf673787d72ceea Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 13:26:50 +0200 Subject: [PATCH 151/251] move `print_result_c` into the trait --- .../intrinsic-test/src/arm/intrinsic.rs | 77 +------------------ .../crates/intrinsic-test/src/arm/types.rs | 66 ++++++++++++++++ .../crates/intrinsic-test/src/common/gen_c.rs | 4 +- .../intrinsic-test/src/common/intrinsic.rs | 6 -- .../src/common/intrinsic_helpers.rs | 5 ++ 5 files changed, 75 insertions(+), 83 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs index 7c31fd4d9dd0a..1928a00f4f382 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs @@ -1,7 +1,6 @@ use crate::common::argument::ArgumentList; -use crate::common::indentation::Indentation; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; -use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; +use crate::common::intrinsic_helpers::IntrinsicType; use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] @@ -36,78 +35,4 @@ impl IntrinsicDefinition for Intrinsic { fn name(&self) -> String { self.name.clone() } - - /// Generates a std::cout for the intrinsics results that will match the - /// rust debug output format for the return type. The generated line assumes - /// there is an int i in scope which is the current pass number. - fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { - self.results().print_result_c(indentation, additional) - } -} - -impl ArmIntrinsicType { - /// Generates a std::cout for the intrinsics results that will match the - /// rust debug output format for the return type. The generated line assumes - /// there is an int i in scope which is the current pass number. - fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { - let lanes = if self.num_vectors() > 1 { - (0..self.num_vectors()) - .map(|vector| { - format!( - r#""{ty}(" << {lanes} << ")""#, - ty = self.c_single_vector_type(), - lanes = (0..self.num_lanes()) - .map(move |idx| -> std::string::String { - format!( - "{cast}{lane_fn}(__return_value.val[{vector}], {lane})", - cast = self.c_promotion(), - lane_fn = self.get_lane_function(), - lane = idx, - vector = vector, - ) - }) - .collect::>() - .join(r#" << ", " << "#) - ) - }) - .collect::>() - .join(r#" << ", " << "#) - } else if self.num_lanes() > 1 { - (0..self.num_lanes()) - .map(|idx| -> std::string::String { - format!( - "{cast}{lane_fn}(__return_value, {lane})", - cast = self.c_promotion(), - lane_fn = self.get_lane_function(), - lane = idx - ) - }) - .collect::>() - .join(r#" << ", " << "#) - } else { - format!( - "{promote}cast<{cast}>(__return_value)", - cast = match self.kind() { - TypeKind::Float if self.inner_size() == 16 => "float16_t".to_string(), - TypeKind::Float if self.inner_size() == 32 => "float".to_string(), - TypeKind::Float if self.inner_size() == 64 => "double".to_string(), - TypeKind::Int(Sign::Signed) => format!("int{}_t", self.inner_size()), - TypeKind::Int(Sign::Unsigned) => format!("uint{}_t", self.inner_size()), - TypeKind::Poly => format!("poly{}_t", self.inner_size()), - ty => todo!("print_result_c - Unknown type: {:#?}", ty), - }, - promote = self.c_promotion(), - ) - }; - - format!( - r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, - ty = if self.is_simd() { - format!("{}(", self.c_type()) - } else { - String::from("") - }, - close = if self.is_simd() { ")" } else { "" }, - ) - } } diff --git a/library/stdarch/crates/intrinsic-test/src/arm/types.rs b/library/stdarch/crates/intrinsic-test/src/arm/types.rs index 32f8f106ce26d..e86a2c5189f0b 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/types.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/types.rs @@ -1,5 +1,6 @@ use super::intrinsic::ArmIntrinsicType; use crate::common::cli::Language; +use crate::common::indentation::Indentation; use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; impl IntrinsicTypeDefinition for ArmIntrinsicType { @@ -98,6 +99,71 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { todo!("get_lane_function IntrinsicType: {:#?}", self) } } + + /// Generates a std::cout for the intrinsics results that will match the + /// rust debug output format for the return type. The generated line assumes + /// there is an int i in scope which is the current pass number. + fn print_result_c(&self, indentation: Indentation, additional: &str) -> String { + let lanes = if self.num_vectors() > 1 { + (0..self.num_vectors()) + .map(|vector| { + format!( + r#""{ty}(" << {lanes} << ")""#, + ty = self.c_single_vector_type(), + lanes = (0..self.num_lanes()) + .map(move |idx| -> std::string::String { + format!( + "{cast}{lane_fn}(__return_value.val[{vector}], {lane})", + cast = self.c_promotion(), + lane_fn = self.get_lane_function(), + lane = idx, + vector = vector, + ) + }) + .collect::>() + .join(r#" << ", " << "#) + ) + }) + .collect::>() + .join(r#" << ", " << "#) + } else if self.num_lanes() > 1 { + (0..self.num_lanes()) + .map(|idx| -> std::string::String { + format!( + "{cast}{lane_fn}(__return_value, {lane})", + cast = self.c_promotion(), + lane_fn = self.get_lane_function(), + lane = idx + ) + }) + .collect::>() + .join(r#" << ", " << "#) + } else { + format!( + "{promote}cast<{cast}>(__return_value)", + cast = match self.kind() { + TypeKind::Float if self.inner_size() == 16 => "float16_t".to_string(), + TypeKind::Float if self.inner_size() == 32 => "float".to_string(), + TypeKind::Float if self.inner_size() == 64 => "double".to_string(), + TypeKind::Int(Sign::Signed) => format!("int{}_t", self.inner_size()), + TypeKind::Int(Sign::Unsigned) => format!("uint{}_t", self.inner_size()), + TypeKind::Poly => format!("poly{}_t", self.inner_size()), + ty => todo!("print_result_c - Unknown type: {:#?}", ty), + }, + promote = self.c_promotion(), + ) + }; + + format!( + r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) << {lanes} << "{close}" << std::endl;"#, + ty = if self.is_simd() { + format!("{}(", self.c_type()) + } else { + String::from("") + }, + close = if self.is_simd() { ")" } else { "" }, + ) + } } impl ArmIntrinsicType { diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs index 84755ce525053..bfb77be1d4a24 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs @@ -24,7 +24,9 @@ pub fn generate_c_test_loop( loaded_args = intrinsic.arguments().load_values_c(body_indentation), intrinsic_call = intrinsic.name(), args = intrinsic.arguments().as_call_param_c(), - print_result = intrinsic.print_result_c(body_indentation, additional) + print_result = intrinsic + .results() + .print_result_c(body_indentation, additional) ) } diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs index bc46ccfbac40c..810681337fd5e 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs @@ -1,5 +1,4 @@ use super::argument::ArgumentList; -use super::indentation::Indentation; use super::intrinsic_helpers::{IntrinsicTypeDefinition, TypeKind}; /// An intrinsic @@ -27,11 +26,6 @@ where fn results(&self) -> T; fn name(&self) -> String; - - /// Generates a std::cout for the intrinsics results that will match the - /// rust debug output format for the return type. The generated line assumes - /// there is an int i in scope which is the current pass number. - fn print_result_c(&self, _indentation: Indentation, _additional: &str) -> String; } pub fn format_f16_return_value( diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs index f5e84ca97af21..7bc1015a387c1 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -325,4 +325,9 @@ pub trait IntrinsicTypeDefinition: Deref { /// can be directly defined in `impl` blocks fn c_single_vector_type(&self) -> String; + + /// Generates a std::cout for the intrinsics results that will match the + /// rust debug output format for the return type. The generated line assumes + /// there is an int i in scope which is the current pass number. + fn print_result_c(&self, indentation: Indentation, additional: &str) -> String; } From 1697f36225310391cb96a2c0616f4596d3ba490f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 13:32:19 +0200 Subject: [PATCH 152/251] remove `trait IntrinsicDefinition` --- .../intrinsic-test/src/arm/intrinsic.rs | 16 ------------- .../crates/intrinsic-test/src/common/gen_c.rs | 23 +++++++++--------- .../intrinsic-test/src/common/gen_rust.rs | 24 ++++++++++--------- .../intrinsic-test/src/common/intrinsic.rs | 19 +++------------ 4 files changed, 28 insertions(+), 54 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs index 1928a00f4f382..29343bee4c300 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs @@ -1,5 +1,3 @@ -use crate::common::argument::ArgumentList; -use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::IntrinsicType; use std::ops::{Deref, DerefMut}; @@ -22,17 +20,3 @@ impl DerefMut for ArmIntrinsicType { &mut self.data } } - -impl IntrinsicDefinition for Intrinsic { - fn arguments(&self) -> ArgumentList { - self.arguments.clone() - } - - fn results(&self) -> ArmIntrinsicType { - self.results.clone() - } - - fn name(&self) -> String { - self.name.clone() - } -} diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs index bfb77be1d4a24..20a5f2c63f0e1 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs @@ -1,6 +1,7 @@ +use crate::common::intrinsic::Intrinsic; + use super::argument::Argument; use super::indentation::Indentation; -use super::intrinsic::IntrinsicDefinition; use super::intrinsic_helpers::IntrinsicTypeDefinition; // The number of times each intrinsic will be called. @@ -8,7 +9,7 @@ const PASSES: u32 = 20; pub fn generate_c_test_loop( w: &mut impl std::io::Write, - intrinsic: &dyn IntrinsicDefinition, + intrinsic: &Intrinsic, indentation: Indentation, additional: &str, passes: u32, @@ -21,18 +22,18 @@ pub fn generate_c_test_loop( {body_indentation}auto __return_value = {intrinsic_call}({args});\n\ {print_result}\n\ {indentation}}}", - loaded_args = intrinsic.arguments().load_values_c(body_indentation), - intrinsic_call = intrinsic.name(), - args = intrinsic.arguments().as_call_param_c(), + loaded_args = intrinsic.arguments.load_values_c(body_indentation), + intrinsic_call = intrinsic.name, + args = intrinsic.arguments.as_call_param_c(), print_result = intrinsic - .results() + .results .print_result_c(body_indentation, additional) ) } pub fn generate_c_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>( w: &mut impl std::io::Write, - intrinsic: &dyn IntrinsicDefinition, + intrinsic: &Intrinsic, indentation: Indentation, constraints: &mut (impl Iterator> + Clone), name: String, @@ -65,14 +66,14 @@ pub fn generate_c_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>( // Compiles C test programs using specified compiler pub fn create_c_test_function( w: &mut impl std::io::Write, - intrinsic: &dyn IntrinsicDefinition, + intrinsic: &Intrinsic, ) -> std::io::Result<()> { let indentation = Indentation::default(); - writeln!(w, "int run_{}() {{", intrinsic.name())?; + writeln!(w, "int run_{}() {{", intrinsic.name)?; // Define the arrays of arguments. - let arguments = intrinsic.arguments(); + let arguments = &intrinsic.arguments; arguments.gen_arglists_c(w, indentation.nested(), PASSES)?; generate_c_constraint_blocks( @@ -94,7 +95,7 @@ pub fn write_mod_cpp( notice: &str, architecture: &str, platform_headers: &[&str], - intrinsics: &[impl IntrinsicDefinition], + intrinsics: &[Intrinsic], ) -> std::io::Result<()> { write!(w, "{notice}")?; diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs index 2a02b8fdff1df..240496f9b765e 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs @@ -1,8 +1,10 @@ use itertools::Itertools; use std::process::Command; +use crate::common::intrinsic::Intrinsic; + use super::indentation::Indentation; -use super::intrinsic::{IntrinsicDefinition, format_f16_return_value}; +use super::intrinsic::format_f16_return_value; use super::intrinsic_helpers::IntrinsicTypeDefinition; // The number of times each intrinsic will be called. @@ -100,7 +102,7 @@ pub fn write_lib_rs( notice: &str, cfg: &str, definitions: &str, - intrinsics: &[impl IntrinsicDefinition], + intrinsics: &[Intrinsic], ) -> std::io::Result<()> { write!(w, "{notice}")?; @@ -189,16 +191,16 @@ pub fn compile_rust_programs(toolchain: Option<&str>, target: &str, linker: Opti pub fn generate_rust_test_loop( w: &mut impl std::io::Write, - intrinsic: &dyn IntrinsicDefinition, + intrinsic: &Intrinsic, indentation: Indentation, specializations: &[Vec], passes: u32, ) -> std::io::Result<()> { - let intrinsic_name = intrinsic.name(); + let intrinsic_name = &intrinsic.name; // Each function (and each specialization) has its own type. Erase that type with a cast. let mut coerce = String::from("unsafe fn("); - for _ in intrinsic.arguments().iter().filter(|a| !a.has_constraint()) { + for _ in intrinsic.arguments.iter().filter(|a| !a.has_constraint()) { coerce += "_, "; } coerce += ") -> _"; @@ -248,8 +250,8 @@ pub fn generate_rust_test_loop( }}\n\ }}\n\ }}", - loaded_args = intrinsic.arguments().load_values_rust(indentation3), - args = intrinsic.arguments().as_call_param_rust(), + loaded_args = intrinsic.arguments.load_values_rust(indentation3), + args = intrinsic.arguments.as_call_param_rust(), ) } @@ -277,15 +279,15 @@ fn generate_rust_specializations<'a>( // Top-level function to create complete test program pub fn create_rust_test_module( w: &mut impl std::io::Write, - intrinsic: &dyn IntrinsicDefinition, + intrinsic: &Intrinsic, ) -> std::io::Result<()> { - trace!("generating `{}`", intrinsic.name()); + trace!("generating `{}`", intrinsic.name); let indentation = Indentation::default(); - writeln!(w, "pub fn run_{}() {{", intrinsic.name())?; + writeln!(w, "pub fn run_{}() {{", intrinsic.name)?; // Define the arrays of arguments. - let arguments = intrinsic.arguments(); + let arguments = &intrinsic.arguments; arguments.gen_arglists_rust(w, indentation.nested(), PASSES)?; // Define any const generics as `const` items, then generate the actual test loop. diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs index 810681337fd5e..95276d19b72f9 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs @@ -17,27 +17,14 @@ pub struct Intrinsic { pub arch_tags: Vec, } -pub trait IntrinsicDefinition -where - T: IntrinsicTypeDefinition, -{ - fn arguments(&self) -> ArgumentList; - - fn results(&self) -> T; - - fn name(&self) -> String; -} - -pub fn format_f16_return_value( - intrinsic: &dyn IntrinsicDefinition, -) -> String { +pub fn format_f16_return_value(intrinsic: &Intrinsic) -> String { // the `intrinsic-test` crate compares the output of C and Rust intrinsics. Currently, It uses // a string representation of the output value to compare. In C, f16 values are currently printed // as hexadecimal integers. Since https://github.com/rust-lang/rust/pull/127013, rust does print // them as decimal floating point values. To keep the intrinsics tests working, for now, format // vectors containing f16 values like C prints them. - let return_value = match intrinsic.results().kind() { - TypeKind::Float if intrinsic.results().inner_size() == 16 => "debug_f16(__return_value)", + let return_value = match intrinsic.results.kind() { + TypeKind::Float if intrinsic.results.inner_size() == 16 => "debug_f16(__return_value)", _ => "format_args!(\"{__return_value:.150?}\")", }; From ccec2027272c635aaa8713df0943c85df765570e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 13:35:30 +0200 Subject: [PATCH 153/251] move `build_c_file` and `build_rust_file` into `SupportedArchitectureTest` --- .../crates/intrinsic-test/src/arm/mod.rs | 141 +---------------- .../crates/intrinsic-test/src/common/mod.rs | 145 +++++++++++++++++- 2 files changed, 143 insertions(+), 143 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index 82dc5001adf06..bbf6a7a5a2d62 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -5,19 +5,11 @@ mod intrinsic; mod json_parser; mod types; -use std::fs::File; - -use rayon::prelude::*; - +use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compile_c::CppCompilation; -use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; -use crate::common::gen_rust::{ - compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, write_main_rs, -}; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::{SupportedArchitectureTest, chunk_info}; use intrinsic::ArmIntrinsicType; use json_parser::get_neon_intrinsics; @@ -76,135 +68,4 @@ impl SupportedArchitectureTest for ArmArchitectureTest { fn cpp_compilation(&self) -> Option { compile::build_cpp_compilation(&self.cli_options) } - - fn build_c_file(&self) -> bool { - let c_target = "aarch64"; - - let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); - - let cpp_compiler_wrapped = self.cpp_compilation(); - - std::fs::create_dir_all("c_programs").unwrap(); - self.intrinsics() - .par_chunks(chunk_size) - .enumerate() - .map(|(i, chunk)| { - let c_filename = format!("c_programs/mod_{i}.cpp"); - let mut file = File::create(&c_filename).unwrap(); - write_mod_cpp( - &mut file, - Self::NOTICE, - c_target, - Self::PLATFORM_C_HEADERS, - chunk, - ) - .unwrap(); - - // compile this cpp file into a .o file. - // - // This is done because `cpp_compiler_wrapped` is None when - // the --generate-only flag is passed - if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { - let output = cpp_compiler - .compile_object_file(&format!("mod_{i}.cpp"), &format!("mod_{i}.o"))?; - assert!(output.status.success(), "{output:?}"); - } - - Ok(()) - }) - .collect::>() - .unwrap(); - - let mut file = File::create("c_programs/main.cpp").unwrap(); - write_main_cpp( - &mut file, - c_target, - Self::PLATFORM_C_DEFINITIONS, - self.intrinsics().iter().map(|i| i.name.as_str()), - ) - .unwrap(); - - // This is done because `cpp_compiler_wrapped` is None when - // the --generate-only flag is passed - if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { - // compile this cpp file into a .o file - info!("compiling main.cpp"); - let output = cpp_compiler - .compile_object_file("main.cpp", "intrinsic-test-programs.o") - .unwrap(); - assert!(output.status.success(), "{output:?}"); - - let object_files = (0..chunk_count) - .map(|i| format!("mod_{i}.o")) - .chain(["intrinsic-test-programs.o".to_owned()]); - - let output = cpp_compiler - .link_executable(object_files, "intrinsic-test-programs") - .unwrap(); - assert!(output.status.success(), "{output:?}"); - } - - true - } - - fn build_rust_file(&self) -> bool { - std::fs::create_dir_all("rust_programs/src").unwrap(); - - let architecture = if self.cli_options.target.contains("v7") { - "arm" - } else { - "aarch64" - }; - - let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); - - let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); - write_bin_cargo_toml(&mut cargo, chunk_count).unwrap(); - - let mut main_rs = File::create("rust_programs/src/main.rs").unwrap(); - write_main_rs( - &mut main_rs, - chunk_count, - Self::PLATFORM_RUST_CFGS, - "", - self.intrinsics.iter().map(|i| i.name.as_str()), - ) - .unwrap(); - - let target = &self.cli_options.target; - let toolchain = self.cli_options.toolchain.as_deref(); - let linker = self.cli_options.linker.as_deref(); - - self.intrinsics - .par_chunks(chunk_size) - .enumerate() - .map(|(i, chunk)| { - std::fs::create_dir_all(format!("rust_programs/mod_{i}/src"))?; - - let rust_filename = format!("rust_programs/mod_{i}/src/lib.rs"); - trace!("generating `{rust_filename}`"); - let mut file = File::create(rust_filename)?; - - write_lib_rs( - &mut file, - architecture, - Self::NOTICE, - Self::PLATFORM_RUST_CFGS, - Self::PLATFORM_RUST_DEFINITIONS, - chunk, - )?; - - let toml_filename = format!("rust_programs/mod_{i}/Cargo.toml"); - trace!("generating `{toml_filename}`"); - let mut file = File::create(toml_filename).unwrap(); - - write_lib_cargo_toml(&mut file, &format!("mod_{i}"))?; - - Ok(()) - }) - .collect::>() - .unwrap(); - - compile_rust_programs(toolchain, target, linker) - } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index 13e6c9fe9e28e..b6589ddaef8ef 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -1,7 +1,18 @@ +use std::fs::File; + +use rayon::prelude::*; + use cli::ProcessedCli; use crate::common::{ - compile_c::CppCompilation, intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition, + compile_c::CppCompilation, + gen_c::{write_main_cpp, write_mod_cpp}, + gen_rust::{ + compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, + write_main_rs, + }, + intrinsic::Intrinsic, + intrinsic_helpers::IntrinsicTypeDefinition, }; pub mod argument; @@ -36,8 +47,136 @@ pub trait SupportedArchitectureTest { fn cpp_compilation(&self) -> Option; - fn build_c_file(&self) -> bool; - fn build_rust_file(&self) -> bool; + fn build_c_file(&self) -> bool { + let c_target = "aarch64"; + + let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); + + let cpp_compiler_wrapped = self.cpp_compilation(); + + std::fs::create_dir_all("c_programs").unwrap(); + self.intrinsics() + .par_chunks(chunk_size) + .enumerate() + .map(|(i, chunk)| { + let c_filename = format!("c_programs/mod_{i}.cpp"); + let mut file = File::create(&c_filename).unwrap(); + write_mod_cpp( + &mut file, + Self::NOTICE, + c_target, + Self::PLATFORM_C_HEADERS, + chunk, + ) + .unwrap(); + + // compile this cpp file into a .o file. + // + // This is done because `cpp_compiler_wrapped` is None when + // the --generate-only flag is passed + if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { + let output = cpp_compiler + .compile_object_file(&format!("mod_{i}.cpp"), &format!("mod_{i}.o"))?; + assert!(output.status.success(), "{output:?}"); + } + + Ok(()) + }) + .collect::>() + .unwrap(); + + let mut file = File::create("c_programs/main.cpp").unwrap(); + write_main_cpp( + &mut file, + c_target, + Self::PLATFORM_C_DEFINITIONS, + self.intrinsics().iter().map(|i| i.name.as_str()), + ) + .unwrap(); + + // This is done because `cpp_compiler_wrapped` is None when + // the --generate-only flag is passed + if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { + // compile this cpp file into a .o file + info!("compiling main.cpp"); + let output = cpp_compiler + .compile_object_file("main.cpp", "intrinsic-test-programs.o") + .unwrap(); + assert!(output.status.success(), "{output:?}"); + + let object_files = (0..chunk_count) + .map(|i| format!("mod_{i}.o")) + .chain(["intrinsic-test-programs.o".to_owned()]); + + let output = cpp_compiler + .link_executable(object_files, "intrinsic-test-programs") + .unwrap(); + assert!(output.status.success(), "{output:?}"); + } + + true + } + + fn build_rust_file(&self) -> bool { + std::fs::create_dir_all("rust_programs/src").unwrap(); + + let architecture = if self.cli_options().target.contains("v7") { + "arm" + } else { + "aarch64" + }; + + let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); + + let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); + write_bin_cargo_toml(&mut cargo, chunk_count).unwrap(); + + let mut main_rs = File::create("rust_programs/src/main.rs").unwrap(); + write_main_rs( + &mut main_rs, + chunk_count, + Self::PLATFORM_RUST_CFGS, + "", + self.intrinsics().iter().map(|i| i.name.as_str()), + ) + .unwrap(); + + let target = &self.cli_options().target; + let toolchain = self.cli_options().toolchain.as_deref(); + let linker = self.cli_options().linker.as_deref(); + + self.intrinsics() + .par_chunks(chunk_size) + .enumerate() + .map(|(i, chunk)| { + std::fs::create_dir_all(format!("rust_programs/mod_{i}/src"))?; + + let rust_filename = format!("rust_programs/mod_{i}/src/lib.rs"); + trace!("generating `{rust_filename}`"); + let mut file = File::create(rust_filename)?; + + write_lib_rs( + &mut file, + architecture, + Self::NOTICE, + Self::PLATFORM_RUST_CFGS, + Self::PLATFORM_RUST_DEFINITIONS, + chunk, + )?; + + let toml_filename = format!("rust_programs/mod_{i}/Cargo.toml"); + trace!("generating `{toml_filename}`"); + let mut file = File::create(toml_filename).unwrap(); + + write_lib_cargo_toml(&mut file, &format!("mod_{i}"))?; + + Ok(()) + }) + .collect::>() + .unwrap(); + + compile_rust_programs(toolchain, target, linker) + } fn compare_outputs(&self) -> bool { if self.cli_options().toolchain.is_some() { From 4b549a7330736bad6f7296241c6ce1cdbab4ef60 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 7 Sep 2025 14:10:47 +0200 Subject: [PATCH 154/251] move target-specific definitions into constants --- .../crates/intrinsic-test/src/arm/config.rs | 20 +++++++++++++-- .../crates/intrinsic-test/src/arm/mod.rs | 25 ++++++++++--------- .../crates/intrinsic-test/src/common/gen_c.rs | 13 +++------- .../intrinsic-test/src/common/gen_rust.rs | 3 --- .../crates/intrinsic-test/src/common/mod.rs | 13 ++-------- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/config.rs b/library/stdarch/crates/intrinsic-test/src/arm/config.rs index beaca621378d4..72e997de154ab 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/config.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/config.rs @@ -3,7 +3,15 @@ pub const NOTICE: &str = "\ // test are derived from a JSON specification, published under the same license as the // `intrinsic-test` crate.\n"; -pub const POLY128_OSTREAM_DEF: &str = r#"std::ostream& operator<<(std::ostream& os, poly128_t value) { +pub const POLY128_OSTREAM_DECL: &str = r#" +#ifdef __aarch64__ +std::ostream& operator<<(std::ostream& os, poly128_t value); +#endif +"#; + +pub const POLY128_OSTREAM_DEF: &str = r#" +#ifdef __aarch64__ +std::ostream& operator<<(std::ostream& os, poly128_t value) { std::stringstream temp; do { int n = value % 10; @@ -14,7 +22,9 @@ pub const POLY128_OSTREAM_DEF: &str = r#"std::ostream& operator<<(std::ostream& std::string res(tempstr.rbegin(), tempstr.rend()); os << res; return os; -}"#; +} +#endif +"#; // Format f16 values (and vectors containing them) in a way that is consistent with C. pub const F16_FORMATTING_DEF: &str = r#" @@ -113,4 +123,10 @@ pub const AARCH_CONFIGURATIONS: &str = r#" #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_ftts))] #![feature(fmt_helpers_for_derive)] #![feature(stdarch_neon_f16)] + +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] +use core::arch::aarch64::*; + +#[cfg(target_arch = "arm")] +use core::arch::arm::*; "#; diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index bbf6a7a5a2d62..08dc2d38702cd 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -29,6 +29,19 @@ impl SupportedArchitectureTest for ArmArchitectureTest { &self.intrinsics } + const NOTICE: &str = config::NOTICE; + + const PLATFORM_C_HEADERS: &[&str] = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; + const PLATFORM_C_DEFINITIONS: &str = config::POLY128_OSTREAM_DEF; + const PLATFORM_C_FORWARD_DECLARATIONS: &str = config::POLY128_OSTREAM_DECL; + + const PLATFORM_RUST_DEFINITIONS: &str = config::F16_FORMATTING_DEF; + const PLATFORM_RUST_CFGS: &str = config::AARCH_CONFIGURATIONS; + + fn cpp_compilation(&self) -> Option { + compile::build_cpp_compilation(&self.cli_options) + } + fn create(cli_options: ProcessedCli) -> Self { let a32 = cli_options.target.contains("v7"); let mut intrinsics = get_neon_intrinsics(&cli_options.filename, &cli_options.target) @@ -56,16 +69,4 @@ impl SupportedArchitectureTest for ArmArchitectureTest { cli_options, } } - - const NOTICE: &str = config::NOTICE; - - const PLATFORM_C_HEADERS: &[&str] = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"]; - const PLATFORM_C_DEFINITIONS: &str = config::POLY128_OSTREAM_DEF; - - const PLATFORM_RUST_DEFINITIONS: &str = config::F16_FORMATTING_DEF; - const PLATFORM_RUST_CFGS: &str = config::AARCH_CONFIGURATIONS; - - fn cpp_compilation(&self) -> Option { - compile::build_cpp_compilation(&self.cli_options) - } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs index 20a5f2c63f0e1..28902b3dfe981 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs @@ -93,8 +93,8 @@ pub fn create_c_test_function( pub fn write_mod_cpp( w: &mut impl std::io::Write, notice: &str, - architecture: &str, platform_headers: &[&str], + forward_declarations: &str, intrinsics: &[Intrinsic], ) -> std::io::Result<()> { write!(w, "{notice}")?; @@ -125,12 +125,7 @@ std::ostream& operator<<(std::ostream& os, float16_t value); "# )?; - writeln!(w, "#ifdef __{architecture}__")?; - writeln!( - w, - "std::ostream& operator<<(std::ostream& os, poly128_t value);" - )?; - writeln!(w, "#endif")?; + writeln!(w, "{}", forward_declarations)?; for intrinsic in intrinsics { create_c_test_function(w, intrinsic)?; @@ -141,7 +136,6 @@ std::ostream& operator<<(std::ostream& os, float16_t value); pub fn write_main_cpp<'a>( w: &mut impl std::io::Write, - architecture: &str, arch_specific_definitions: &str, intrinsics: impl Iterator + Clone, ) -> std::io::Result<()> { @@ -170,9 +164,8 @@ std::ostream& operator<<(std::ostream& os, float16_t value) {{ "# )?; - writeln!(w, "#ifdef __{architecture}__")?; + // NOTE: It's assumed that this value contains the required `ifdef`s. writeln!(w, "{arch_specific_definitions }")?; - writeln!(w, "#endif")?; for intrinsic in intrinsics.clone() { writeln!(w, "extern int run_{intrinsic}(void);")?; diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs index 240496f9b765e..312cbee692a56 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs @@ -98,7 +98,6 @@ pub fn write_main_rs<'a>( pub fn write_lib_rs( w: &mut impl std::io::Write, - architecture: &str, notice: &str, cfg: &str, definitions: &str, @@ -117,8 +116,6 @@ pub fn write_lib_rs( writeln!(w, "{cfg}")?; - writeln!(w, "use core_arch::arch::{architecture}::*;")?; - writeln!(w, "{definitions}")?; for intrinsic in intrinsics { diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index b6589ddaef8ef..666b3885c147b 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -41,6 +41,7 @@ pub trait SupportedArchitectureTest { const PLATFORM_C_HEADERS: &[&str]; const PLATFORM_C_DEFINITIONS: &str; + const PLATFORM_C_FORWARD_DECLARATIONS: &str; const PLATFORM_RUST_CFGS: &str; const PLATFORM_RUST_DEFINITIONS: &str; @@ -48,8 +49,6 @@ pub trait SupportedArchitectureTest { fn cpp_compilation(&self) -> Option; fn build_c_file(&self) -> bool { - let c_target = "aarch64"; - let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); let cpp_compiler_wrapped = self.cpp_compilation(); @@ -64,8 +63,8 @@ pub trait SupportedArchitectureTest { write_mod_cpp( &mut file, Self::NOTICE, - c_target, Self::PLATFORM_C_HEADERS, + Self::PLATFORM_C_FORWARD_DECLARATIONS, chunk, ) .unwrap(); @@ -88,7 +87,6 @@ pub trait SupportedArchitectureTest { let mut file = File::create("c_programs/main.cpp").unwrap(); write_main_cpp( &mut file, - c_target, Self::PLATFORM_C_DEFINITIONS, self.intrinsics().iter().map(|i| i.name.as_str()), ) @@ -120,12 +118,6 @@ pub trait SupportedArchitectureTest { fn build_rust_file(&self) -> bool { std::fs::create_dir_all("rust_programs/src").unwrap(); - let architecture = if self.cli_options().target.contains("v7") { - "arm" - } else { - "aarch64" - }; - let (chunk_size, chunk_count) = chunk_info(self.intrinsics().len()); let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); @@ -157,7 +149,6 @@ pub trait SupportedArchitectureTest { write_lib_rs( &mut file, - architecture, Self::NOTICE, Self::PLATFORM_RUST_CFGS, Self::PLATFORM_RUST_DEFINITIONS, From 6da8094b1385b1647178a3ab9dab3c359ef1c38d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 7 Sep 2025 21:49:55 +0800 Subject: [PATCH 155/251] Improve make::struct_ field_list whitespace Example --- **Before this PR**: ```rust struct Variant{ field: u32 } ``` **After this PR**: ```rust struct Variant { field: u32 } ``` --- .../extract_struct_from_enum_variant.rs | 44 +++++++++---------- .../src/handlers/json_is_not_rust.rs | 24 +++++----- .../crates/syntax/src/ast/make.rs | 7 ++- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index c56d0b3de5d6a..79a4c73c698d1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -478,7 +478,7 @@ macro_rules! foo { }; } -struct TheVariant{ the_field: u8 } +struct TheVariant { the_field: u8 } enum TheEnum { TheVariant(TheVariant), @@ -502,7 +502,7 @@ enum Foo { } "#, r#" -struct Bar{ node: Box } +struct Bar { node: Box } enum Foo { Bar(Bar), @@ -519,7 +519,7 @@ enum Foo { } "#, r#" -struct Bar{ node: Box, a: Arc> } +struct Bar { node: Box, a: Arc> } enum Foo { Bar(Bar), @@ -560,7 +560,7 @@ enum A { One(One) }"#, check_assist( extract_struct_from_enum_variant, "enum A { $0One { foo: u32, bar: u32 } }", - r#"struct One{ foo: u32, bar: u32 } + r#"struct One { foo: u32, bar: u32 } enum A { One(One) }"#, ); @@ -571,7 +571,7 @@ enum A { One(One) }"#, check_assist( extract_struct_from_enum_variant, "enum A { $0One { foo: u32 } }", - r#"struct One{ foo: u32 } + r#"struct One { foo: u32 } enum A { One(One) }"#, ); @@ -582,7 +582,7 @@ enum A { One(One) }"#, check_assist( extract_struct_from_enum_variant, r"enum En { Var { a: T$0 } }", - r#"struct Var{ a: T } + r#"struct Var { a: T } enum En { Var(Var) }"#, ); @@ -599,7 +599,7 @@ enum Enum { Variant{ field: u32$0 } }"#, r#" #[derive(Debug)] #[derive(Clone)] -struct Variant{ field: u32 } +struct Variant { field: u32 } #[derive(Debug)] #[derive(Clone)] @@ -618,7 +618,7 @@ enum Enum { } }"#, r#" -struct Variant{ +struct Variant { field: u32 } @@ -642,7 +642,7 @@ mod indenting { }"#, r#" mod indenting { - struct Variant{ + struct Variant { field: u32 } @@ -668,7 +668,7 @@ enum A { } }"#, r#" -struct One{ +struct One { // leading comment /// doc comment #[an_attr] @@ -700,7 +700,7 @@ enum A { } }"#, r#" -struct One{ +struct One { // comment /// doc #[attr] @@ -747,7 +747,7 @@ enum A { /* comment */ // other /// comment -struct One{ +struct One { a: u32 } @@ -789,7 +789,7 @@ enum A { extract_struct_from_enum_variant, "enum A { $0One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }", r#" -struct One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } +struct One { a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } enum A { One(One) }"#, ); @@ -850,7 +850,7 @@ pub enum A { One(One) }"#, extract_struct_from_enum_variant, "pub(in something) enum A { $0One{ a: u32, b: u32 } }", r#" -pub(in something) struct One{ pub(in something) a: u32, pub(in something) b: u32 } +pub(in something) struct One { pub(in something) a: u32, pub(in something) b: u32 } pub(in something) enum A { One(One) }"#, ); @@ -862,7 +862,7 @@ pub(in something) enum A { One(One) }"#, extract_struct_from_enum_variant, "pub(crate) enum A { $0One{ a: u32, b: u32, c: u32 } }", r#" -pub(crate) struct One{ pub(crate) a: u32, pub(crate) b: u32, pub(crate) c: u32 } +pub(crate) struct One { pub(crate) a: u32, pub(crate) b: u32, pub(crate) c: u32 } pub(crate) enum A { One(One) }"#, ); @@ -933,7 +933,7 @@ fn f() { } "#, r#" -struct V{ i: i32, j: i32 } +struct V { i: i32, j: i32 } enum E { V(V) @@ -1027,7 +1027,7 @@ fn f() { "#, r#" //- /main.rs -struct V{ i: i32, j: i32 } +struct V { i: i32, j: i32 } enum E { V(V) @@ -1057,7 +1057,7 @@ fn foo() { } "#, r#" -struct One{ a: u32, b: u32 } +struct One { a: u32, b: u32 } enum A { One(One) } @@ -1114,7 +1114,7 @@ enum X<'a, 'b, 'x> { } "#, r#" -struct A<'a, 'x>{ a: &'a &'x mut () } +struct A<'a, 'x> { a: &'a &'x mut () } enum X<'a, 'b, 'x> { A(A<'a, 'x>), @@ -1136,7 +1136,7 @@ enum X<'b, T, V, const C: usize> { } "#, r#" -struct A<'b, T, const C: usize>{ a: T, b: X<'b>, c: [u8; C] } +struct A<'b, T, const C: usize> { a: T, b: X<'b>, c: [u8; C] } enum X<'b, T, V, const C: usize> { A(A<'b, T, C>), @@ -1158,7 +1158,7 @@ enum X<'a, 'b> { } "#, r#" -struct C{ c: () } +struct C { c: () } enum X<'a, 'b> { A { a: &'a () }, @@ -1180,7 +1180,7 @@ enum En { } "#, r#" -struct A{ a: T } +struct A { a: T } enum En { A(A), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 742d614bc5673..a300997723b4d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -233,7 +233,7 @@ mod tests { } #[derive(Serialize)] - struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } + struct Root1 { bar: f64, bay: i64, baz: (), r#box: bool, foo: String } "#, ); @@ -252,9 +252,9 @@ mod tests { } "#, r#" - struct Value1{ } - struct Bar1{ kind: String, value: Value1 } - struct Root1{ bar: Bar1, foo: String } + struct Value1 { } + struct Bar1 { kind: String, value: Value1 } + struct Root1 { bar: Bar1, foo: String } "#, ); @@ -284,12 +284,12 @@ mod tests { } "#, r#" - struct Address1{ house: i64, street: String } - struct User1{ address: Address1, email: String } - struct AnotherUser1{ user: User1 } - struct Address2{ house: i64, street: String } - struct User2{ address: Address2, email: String } - struct Root1{ another_user: AnotherUser1, user: User2 } + struct Address1 { house: i64, street: String } + struct User1 { address: Address1, email: String } + struct AnotherUser1 { user: User1 } + struct Address2 { house: i64, street: String } + struct User2 { address: Address2, email: String } + struct Root1 { another_user: AnotherUser1, user: User2 } "#, ); @@ -326,9 +326,9 @@ mod tests { use serde::Deserialize; #[derive(Serialize, Deserialize)] - struct OfObject1{ x: i64, y: i64 } + struct OfObject1 { x: i64, y: i64 } #[derive(Serialize, Deserialize)] - struct Root1{ empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } + struct Root1 { empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } "#, ); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 9897fd0941570..051c5835571bc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -1244,14 +1244,17 @@ pub fn struct_( generic_param_list: Option, field_list: ast::FieldList, ) -> ast::Struct { - let semicolon = if matches!(field_list, ast::FieldList::TupleFieldList(_)) { ";" } else { "" }; + let (semicolon, ws) = + if matches!(field_list, ast::FieldList::TupleFieldList(_)) { (";", "") } else { ("", " ") }; let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string()); let visibility = match visibility { None => String::new(), Some(it) => format!("{it} "), }; - ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",)) + ast_from_text(&format!( + "{visibility}struct {strukt_name}{type_params}{ws}{field_list}{semicolon}" + )) } pub fn enum_( From 61af5da8dfc9f5fd6e2d36f8316f7bf5884f5388 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 14 Mar 2025 09:58:46 +0100 Subject: [PATCH 156/251] Implement more features for GenMC mode - Support for atomic fences. - Support for atomic read-modify-write (RMW). - Add tests using RMW and fences. - Add options: - to disable weak memory effects in GenMC mode. - to print GenMC execution graphs. - to print GenMC output message. - Fix GenMC full rebuild issue and run configure step when commit changes. - Do cleanup. Co-authored-by: Ralf Jung --- src/tools/miri/doc/genmc.md | 7 +- src/tools/miri/genmc-sys/build.rs | 37 +++- .../genmc-sys/cpp/include/MiriInterface.hpp | 29 +++ .../cpp/src/MiriInterface/EventHandling.cpp | 66 ++++++ .../genmc-sys/cpp/src/MiriInterface/Setup.cpp | 13 +- src/tools/miri/genmc-sys/src/lib.rs | 77 ++++++- src/tools/miri/src/bin/miri.rs | 23 +-- src/tools/miri/src/concurrency/data_race.rs | 12 +- .../miri/src/concurrency/genmc/config.rs | 60 +++++- src/tools/miri/src/concurrency/genmc/dummy.rs | 8 +- .../miri/src/concurrency/genmc/helper.rs | 54 ++++- src/tools/miri/src/concurrency/genmc/mod.rs | 191 ++++++++++++------ src/tools/miri/src/concurrency/genmc/run.rs | 13 +- .../miri/tests/genmc/fail/loom/buggy_inc.rs | 66 ++++++ .../tests/genmc/fail/loom/buggy_inc.stderr | 13 ++ .../fail/simple/2w2w_weak.relaxed4.stderr | 8 +- .../fail/simple/2w2w_weak.release4.stderr | 8 +- .../miri/tests/genmc/fail/simple/2w2w_weak.rs | 7 +- .../fail/simple/2w2w_weak.sc3_rel1.stderr | 8 +- .../miri/tests/genmc/pass/atomics/rmw_ops.rs | 91 +++++++++ .../tests/genmc/pass/atomics/rmw_ops.stderr | 2 + .../tests/genmc/pass/litmus/2w2w_2sc_scf.rs | 33 +++ .../genmc/pass/litmus/2w2w_2sc_scf.stderr | 2 + .../miri/tests/genmc/pass/litmus/2w2w_4rel.rs | 4 + .../genmc/pass/litmus/2w2w_4rel.sc.stderr | 2 + ...2w2w_4rel.stderr => 2w2w_4rel.weak.stderr} | 0 .../tests/genmc/pass/litmus/IRIW-acq-sc.rs | 2 +- .../miri/tests/genmc/pass/litmus/IRIWish.rs | 66 ++++++ .../tests/genmc/pass/litmus/IRIWish.stderr | 30 +++ .../miri/tests/genmc/pass/litmus/LB_incMPs.rs | 41 ++++ .../tests/genmc/pass/litmus/LB_incMPs.stderr | 2 + .../tests/genmc/pass/litmus/MPU_rels_acq.rs | 42 ++++ .../genmc/pass/litmus/MPU_rels_acq.stderr | 2 + .../miri/tests/genmc/pass/litmus/MP_incMPs.rs | 36 ++++ .../tests/genmc/pass/litmus/MP_incMPs.stderr | 2 + .../tests/genmc/pass/litmus/MP_rels_acqf.rs | 40 ++++ .../genmc/pass/litmus/MP_rels_acqf.stderr | 2 + .../tests/genmc/pass/litmus/SB_2sc_scf.rs | 32 +++ .../tests/genmc/pass/litmus/SB_2sc_scf.stderr | 2 + .../miri/tests/genmc/pass/litmus/Z6_U.rs | 65 ++++++ .../tests/genmc/pass/litmus/Z6_U.sc.stderr | 20 ++ .../tests/genmc/pass/litmus/Z6_U.weak.stderr | 24 +++ .../miri/tests/genmc/pass/litmus/Z6_acq.rs | 38 ++++ .../tests/genmc/pass/litmus/Z6_acq.stderr | 2 + .../miri/tests/genmc/pass/litmus/atomicpo.rs | 32 +++ .../tests/genmc/pass/litmus/atomicpo.stderr | 2 + .../tests/genmc/pass/litmus/cumul-release.rs | 58 ++++++ .../genmc/pass/litmus/cumul-release.stderr | 2 + .../tests/genmc/pass/litmus/fr_w_w_w_reads.rs | 1 - .../miri/tests/genmc/pass/litmus/inc2w.rs | 45 +++++ .../miri/tests/genmc/pass/litmus/inc2w.stderr | 2 + .../genmc/pass/litmus/inc_inc_RR_W_RR.rs | 63 ++++++ .../genmc/pass/litmus/inc_inc_RR_W_RR.stderr | 2 + .../miri/tests/genmc/pass/litmus/riwi.rs | 31 +++ .../miri/tests/genmc/pass/litmus/riwi.stderr | 2 + .../tests/genmc/pass/litmus/viktor-relseq.rs | 36 ++++ .../genmc/pass/litmus/viktor-relseq.stderr | 2 + src/tools/miri/tests/utils/genmc.rs | 7 + 58 files changed, 1431 insertions(+), 136 deletions(-) create mode 100644 src/tools/miri/tests/genmc/fail/loom/buggy_inc.rs create mode 100644 src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr create mode 100644 src/tools/miri/tests/genmc/pass/atomics/rmw_ops.rs create mode 100644 src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr rename src/tools/miri/tests/genmc/pass/litmus/{2w2w_4rel.stderr => 2w2w_4rel.weak.stderr} (100%) create mode 100644 src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/Z6_acq.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/atomicpo.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cumul-release.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/inc2w.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/riwi.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/riwi.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr diff --git a/src/tools/miri/doc/genmc.md b/src/tools/miri/doc/genmc.md index fdbf2defe42dc..8af697be34a61 100644 --- a/src/tools/miri/doc/genmc.md +++ b/src/tools/miri/doc/genmc.md @@ -24,6 +24,9 @@ Note that `cargo miri test` in GenMC mode is currently not supported. ### Supported Parameters - `-Zmiri-genmc`: Enable GenMC mode (not required if any other GenMC options are used). +- `-Zmiri-genmc-print-exec-graphs={none,explored,blocked,all}`: Make GenMC print the execution graph of the program after every explored, every blocked, or after every execution (default: None). +- `-Zmiri-genmc-print-exec-graphs`: Shorthand for suffix `=explored`. +- `-Zmiri-genmc-print-genmc-output`: Print the output that GenMC provides. NOTE: this output is quite verbose and the events in the printed execution graph are hard to map back to the Rust code location they originate from. - `-Zmiri-genmc-log=LOG_LEVEL`: Change the log level for GenMC. Default: `warning`. - `quiet`: Disable logging. - `error`: Print errors. @@ -34,7 +37,9 @@ Note that `cargo miri test` in GenMC mode is currently not supported. - `debug2`: Print the execution graph after every memory access. - `debug3`: Print reads-from values considered by GenMC. - +#### Regular Miri parameters useful for GenMC mode + +- `-Zmiri-disable-weak-memory-emulation`: Disable any weak memory effects (effectively upgrading all atomic orderings in the program to `SeqCst`). This option may reduce the number of explored program executions, but any bugs related to weak memory effects will be missed. This option can help determine if an error is caused by weak memory effects (i.e., if it disappears with this option enabled). diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs index 8eb818a6b265b..8d437c20a0926 100644 --- a/src/tools/miri/genmc-sys/build.rs +++ b/src/tools/miri/genmc-sys/build.rs @@ -30,13 +30,23 @@ mod downloading { /// The GenMC commit we depend on. It must be available on the specified GenMC repository. pub(crate) const GENMC_COMMIT: &str = "af9cc9ccd5d412b16defc35dbf36571c63a19c76"; - pub(crate) fn download_genmc() -> PathBuf { + /// Ensure that a local GenMC repo is present and set to the correct commit. + /// Return the path of the GenMC repo and whether the checked out commit was changed. + pub(crate) fn download_genmc() -> (PathBuf, bool) { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); let commit_oid = Oid::from_str(GENMC_COMMIT).expect("Commit should be valid."); match Repository::open(&genmc_download_path) { Ok(repo) => { assert_repo_unmodified(&repo); + if let Ok(head) = repo.head() + && let Ok(head_commit) = head.peel_to_commit() + && head_commit.id() == commit_oid + { + // Fast path: The expected commit is already checked out. + return (genmc_download_path, false); + } + // Check if the local repository already contains the commit we need, download it otherwise. let commit = update_local_repo(&repo, commit_oid); checkout_commit(&repo, &commit); } @@ -51,7 +61,7 @@ mod downloading { } }; - genmc_download_path + (genmc_download_path, true) } fn get_remote(repo: &Repository) -> Remote<'_> { @@ -71,7 +81,8 @@ mod downloading { // Update remote URL. println!( - "cargo::warning=GenMC repository remote URL has changed from '{remote_url:?}' to '{GENMC_GITHUB_URL}'" + "cargo::warning=GenMC repository remote URL has changed from '{}' to '{GENMC_GITHUB_URL}'", + remote_url.unwrap_or_default() ); repo.remote_set_url("origin", GENMC_GITHUB_URL) .expect("cannot rename url of remote 'origin'"); @@ -175,7 +186,7 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { } /// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs -fn compile_cpp_dependencies(genmc_path: &Path) { +fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) { // Give each step a separate build directory to prevent interference. let out_dir = PathBuf::from(std::env::var("OUT_DIR").as_deref().unwrap()); let genmc_build_dir = out_dir.join("genmc"); @@ -184,15 +195,13 @@ fn compile_cpp_dependencies(genmc_path: &Path) { // Part 1: // Compile the GenMC library using cmake. - let cmakelists_path = genmc_path.join("CMakeLists.txt"); - // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed. // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); - let mut config = cmake::Config::new(cmakelists_path); + let mut config = cmake::Config::new(genmc_path); config - .always_configure(false) // We don't need to reconfigure on subsequent compilation runs. + .always_configure(always_configure) // We force running the configure step when the GenMC commit changed. .out_dir(genmc_build_dir) .profile(GENMC_CMAKE_PROFILE) .define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); @@ -251,7 +260,8 @@ fn compile_cpp_dependencies(genmc_path: &Path) { fn main() { // Select which path to use for the GenMC repo: - let genmc_path = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") { + let (genmc_path, always_configure) = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") + { let genmc_src_path = PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path"); assert!( @@ -261,13 +271,18 @@ fn main() { ); // Rebuild files in the given path change. println!("cargo::rerun-if-changed={}", genmc_src_path.display()); - genmc_src_path + // We disable `always_configure` when working with a local repository, + // since it increases compile times when working on `genmc-sys`. + (genmc_src_path, false) } else { + // Download GenMC if required and ensure that the correct commit is checked out. + // If anything changed in the downloaded repository (e.g., the commit), + // we set `always_configure` to ensure there are no weird configs from previous builds. downloading::download_genmc() }; // Build all required components: - compile_cpp_dependencies(&genmc_path); + compile_cpp_dependencies(&genmc_path, always_configure); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified diff --git a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp index 4484f0b73caec..b076937584326 100644 --- a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp +++ b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp @@ -33,6 +33,7 @@ struct GenmcScalar; struct SchedulingResult; struct LoadResult; struct StoreResult; +struct ReadModifyWriteResult; // GenMC uses `int` for its thread IDs. using ThreadId = int; @@ -90,6 +91,15 @@ struct MiriGenmcShim : private GenMCDriver { MemOrdering ord, GenmcScalar old_val ); + [[nodiscard]] ReadModifyWriteResult handle_read_modify_write( + ThreadId thread_id, + uint64_t address, + uint64_t size, + RMWBinOp rmw_op, + MemOrdering ordering, + GenmcScalar rhs_value, + GenmcScalar old_val + ); [[nodiscard]] StoreResult handle_store( ThreadId thread_id, uint64_t address, @@ -99,6 +109,8 @@ struct MiriGenmcShim : private GenMCDriver { MemOrdering ord ); + void handle_fence(ThreadId thread_id, MemOrdering ord); + /**** Memory (de)allocation ****/ auto handle_malloc(ThreadId thread_id, uint64_t size, uint64_t alignment) -> uint64_t; void handle_free(ThreadId thread_id, uint64_t address); @@ -271,4 +283,21 @@ inline StoreResult from_error(std::unique_ptr error) { } } // namespace StoreResultExt +namespace ReadModifyWriteResultExt { +inline ReadModifyWriteResult +ok(SVal old_value, SVal new_value, bool is_coherence_order_maximal_write) { + return ReadModifyWriteResult { /* error: */ std::unique_ptr(nullptr), + /* old_value: */ GenmcScalarExt::from_sval(old_value), + /* new_value: */ GenmcScalarExt::from_sval(new_value), + is_coherence_order_maximal_write }; +} + +inline ReadModifyWriteResult from_error(std::unique_ptr error) { + return ReadModifyWriteResult { /* error: */ std::move(error), + /* old_value: */ GenmcScalarExt::uninit(), + /* new_value: */ GenmcScalarExt::uninit(), + /* is_coherence_order_maximal_write: */ false }; +} +} // namespace ReadModifyWriteResultExt + #endif /* GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp index 7d8f0b16b49ab..cd28e0d148f58 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp @@ -89,6 +89,72 @@ ); } +void MiriGenmcShim::handle_fence(ThreadId thread_id, MemOrdering ord) { + const auto pos = inc_pos(thread_id); + GenMCDriver::handleFence(pos, ord, EventDeps()); +} + +[[nodiscard]] auto MiriGenmcShim::handle_read_modify_write( + ThreadId thread_id, + uint64_t address, + uint64_t size, + RMWBinOp rmw_op, + MemOrdering ordering, + GenmcScalar rhs_value, + GenmcScalar old_val +) -> ReadModifyWriteResult { + // NOTE: Both the store and load events should get the same `ordering`, it should not be split + // into a load and a store component. This means we can have for example `AcqRel` loads and + // stores, but this is intended for RMW operations. + + // Somewhat confusingly, the GenMC term for RMW read/write labels is + // `FaiRead` and `FaiWrite`. + const auto load_ret = handle_load_reset_if_none( + thread_id, + ordering, + SAddr(address), + ASize(size), + AType::Unsigned, // The type is only used for printing. + rmw_op, + GenmcScalarExt::to_sval(rhs_value), + EventDeps() + ); + if (const auto* err = std::get_if(&load_ret)) + return ReadModifyWriteResultExt::from_error(format_error(*err)); + + const auto* ret_val = std::get_if(&load_ret); + if (nullptr == ret_val) { + ERROR("Unimplemented: read-modify-write returned unexpected result."); + } + const auto read_old_val = *ret_val; + const auto new_value = + executeRMWBinOp(read_old_val, GenmcScalarExt::to_sval(rhs_value), size, rmw_op); + + const auto storePos = inc_pos(thread_id); + const auto store_ret = GenMCDriver::handleStore( + storePos, + ordering, + SAddr(address), + ASize(size), + AType::Unsigned, // The type is only used for printing. + new_value + ); + if (const auto* err = std::get_if(&store_ret)) + return ReadModifyWriteResultExt::from_error(format_error(*err)); + + const auto* store_ret_val = std::get_if(&store_ret); + ERROR_ON(nullptr == store_ret_val, "Unimplemented: RMW store returned unexpected result."); + + // FIXME(genmc,mixed-accesses): Use the value that GenMC returns from handleStore (once + // available). + const auto& g = getExec().getGraph(); + return ReadModifyWriteResultExt::ok( + /* old_value: */ read_old_val, + new_value, + /* is_coherence_order_maximal_write */ g.co_max(SAddr(address))->getPos() == storePos + ); +} + /**** Memory (de)allocation ****/ auto MiriGenmcShim::handle_malloc(ThreadId thread_id, uint64_t size, uint64_t alignment) diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp index 7194ed02da432..5a53fee059216 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp @@ -63,9 +63,12 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel auto conf = std::make_shared(); // Set whether GenMC should print execution graphs after every explored/blocked execution. - // FIXME(genmc): pass these settings from Miri. - conf->printExecGraphs = false; - conf->printBlockedExecs = false; + conf->printExecGraphs = + (params.print_execution_graphs == ExecutiongraphPrinting::Explored || + params.print_execution_graphs == ExecutiongraphPrinting::ExploredAndBlocked); + conf->printBlockedExecs = + (params.print_execution_graphs == ExecutiongraphPrinting::Blocked || + params.print_execution_graphs == ExecutiongraphPrinting::ExploredAndBlocked); // `1024` is the default value that GenMC uses. // If any thread has at least this many events, a warning/tip will be printed. @@ -79,8 +82,8 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel // Miri. conf->warnOnGraphSize = 1024 * 1024; - // We only support the RC11 memory model for Rust. - conf->model = ModelType::RC11; + // We only support the `RC11` memory model for Rust, and `SC` when weak memory emulation is disabled. + conf->model = params.disable_weak_memory_emulation ? ModelType::SC : ModelType::RC11; // This prints the seed that GenMC picks for randomized scheduling during estimation mode. conf->printRandomScheduleSeed = params.print_random_schedule_seed; diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs index 406c90809fcd5..1de4c4eb5e8e9 100644 --- a/src/tools/miri/genmc-sys/src/lib.rs +++ b/src/tools/miri/genmc-sys/src/lib.rs @@ -53,7 +53,13 @@ impl GenmcScalar { impl Default for GenmcParams { fn default() -> Self { - Self { print_random_schedule_seed: false, do_symmetry_reduction: false } + Self { + print_random_schedule_seed: false, + do_symmetry_reduction: false, + // GenMC graphs can be quite large since Miri produces a lot of (non-atomic) events. + print_execution_graphs: ExecutiongraphPrinting::None, + disable_weak_memory_emulation: false, + } } } @@ -91,7 +97,10 @@ mod ffi { struct GenmcParams { pub print_random_schedule_seed: bool, pub do_symmetry_reduction: bool, - // FIXME(GenMC): Add remaining parameters. + pub print_execution_graphs: ExecutiongraphPrinting, + /// Enabling this will set the memory model used by GenMC to "Sequential Consistency" (SC). + /// This will disable any weak memory effects, which reduces the number of program executions that will be explored. + pub disable_weak_memory_emulation: bool, } /// This is mostly equivalent to GenMC `VerbosityLevel`, but the debug log levels are always present (not conditionally compiled based on `ENABLE_GENMC_DEBUG`). @@ -120,6 +129,19 @@ mod ffi { Debug3ReadsFrom, } + #[derive(Debug)] + /// Setting to control which execution graphs GenMC prints after every execution. + enum ExecutiongraphPrinting { + /// Print no graphs. + None, + /// Print graphs of all fully explored executions. + Explored, + /// Print graphs of all blocked executions. + Blocked, + /// Print graphs of all executions. + ExploredAndBlocked, + } + /// This type corresponds to `Option` (or `std::optional`), where `SVal` is the type that GenMC uses for storing values. /// CXX doesn't support `std::optional` currently, so we need to use an extra `bool` to define whether this value is initialized or not. #[derive(Debug, Clone, Copy)] @@ -163,7 +185,21 @@ mod ffi { is_coherence_order_maximal_write: bool, } - /**** Types shared between Miri/Rust and GenMC/C++ through cxx_bridge: ****/ + #[must_use] + #[derive(Debug)] + struct ReadModifyWriteResult { + /// If there was an error, it will be stored in `error`, otherwise it is `None`. + error: UniquePtr, + /// The value that was read by the RMW operation as the left operand. + old_value: GenmcScalar, + /// The value that was produced by the RMW operation. + new_value: GenmcScalar, + /// `true` if the write should also be reflected in Miri's memory representation. + is_coherence_order_maximal_write: bool, + } + + /**** These are GenMC types that we have to copy-paste here since cxx does not support + "importing" externally defined C++ types. ****/ #[derive(Debug)] /// Corresponds to GenMC's type with the same name. @@ -188,6 +224,21 @@ mod ffi { SequentiallyConsistent = 6, } + #[derive(Debug)] + enum RMWBinOp { + Xchg = 0, + Add = 1, + Sub = 2, + And = 3, + Nand = 4, + Or = 5, + Xor = 6, + Max = 7, + Min = 8, + UMax = 9, + UMin = 10, + } + // # Safety // // This block is unsafe to allow defining safe methods inside. @@ -202,9 +253,12 @@ mod ffi { /**** Types shared between Miri/Rust and Miri/C++: ****/ type MiriGenmcShim; - /**** Types shared between Miri/Rust and GenMC/C++: ****/ + /**** Types shared between Miri/Rust and GenMC/C++: + (This tells cxx that the enums defined above are already defined on the C++ side; + it will emit assertions to ensure that the two definitions agree.) ****/ type ActionKind; type MemOrdering; + type RMWBinOp; /// Set the log level for GenMC. /// @@ -249,6 +303,16 @@ mod ffi { memory_ordering: MemOrdering, old_value: GenmcScalar, ) -> LoadResult; + fn handle_read_modify_write( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + address: u64, + size: u64, + rmw_op: RMWBinOp, + ordering: MemOrdering, + rhs_value: GenmcScalar, + old_value: GenmcScalar, + ) -> ReadModifyWriteResult; fn handle_store( self: Pin<&mut MiriGenmcShim>, thread_id: i32, @@ -258,6 +322,11 @@ mod ffi { old_value: GenmcScalar, memory_ordering: MemOrdering, ) -> StoreResult; + fn handle_fence( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + memory_ordering: MemOrdering, + ); /**** Memory (de)allocation ****/ fn handle_malloc( diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index ff05b4b14c79a..731fe283a2195 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -746,24 +746,11 @@ fn main() { many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going }); // Validate settings for data race detection and GenMC mode. - if miri_config.genmc_config.is_some() { - if !miri_config.data_race_detector { - fatal_error!("Cannot disable data race detection in GenMC mode"); - } else if !miri_config.weak_memory_emulation { - fatal_error!("Cannot disable weak memory emulation in GenMC mode"); - } else if !miri_config.native_lib.is_empty() { - fatal_error!("native-lib not supported in GenMC mode."); - } - if miri_config.borrow_tracker.is_some() { - eprintln!( - "warning: borrow tracking has been disabled, it is not (yet) supported in GenMC mode." - ); - miri_config.borrow_tracker = None; - } - // We enable fixed scheduling so Miri doesn't randomly yield before a terminator, which anyway - // would be a NOP in GenMC mode. - miri_config.fixed_scheduling = true; - } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector { + if let Err(err) = GenmcConfig::validate_genmc_mode_settings(&mut miri_config) { + fatal_error!("Invalid settings: {err}"); + } + + if miri_config.weak_memory_emulation && !miri_config.data_race_detector { fatal_error!( "Weak memory emulation cannot be enabled when the data race detector is disabled" ); diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index a7822d0d6fa31..30061a78594aa 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -793,9 +793,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this, place.ptr().addr(), place.layout.size, + atomic_op, place.layout.backend_repr.is_signed(), ord, - atomic_op, rhs.to_scalar(), old.to_scalar(), )?; @@ -901,7 +901,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { can_fail_spuriously, old.to_scalar(), )?; - // The store might be the latest store in coherence order (determined by GenMC). // If it is, we need to update the value in Miri's memory: if let Some(new_value) = new_value { @@ -961,6 +960,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// The closure will only be invoked if data race handling is on. fn release_clock(&self, callback: impl FnOnce(&VClock) -> R) -> Option { let this = self.eval_context_ref(); + // FIXME: make this a proper error instead of ICEing the interpreter. + assert!( + this.machine.data_race.as_genmc_ref().is_none(), + "this operation performs synchronization that is not supported in GenMC mode" + ); Some( this.machine.data_race.as_vclocks_ref()?.release_clock(&this.machine.threads, callback), ) @@ -973,7 +977,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { match &this.machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(_genmc_ctx) => - throw_unsup_format!("acquire_clock is not (yet) supported in GenMC mode."), + throw_unsup_format!( + "this operation performs synchronization that is not supported in GenMC mode" + ), GlobalDataRaceHandler::Vclocks(data_race) => data_race.acquire_clock(clock, &this.machine.threads), } diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs index 66116d5cf23c7..34933d423f064 100644 --- a/src/tools/miri/src/concurrency/genmc/config.rs +++ b/src/tools/miri/src/concurrency/genmc/config.rs @@ -1,4 +1,7 @@ -use genmc_sys::{GenmcParams, LogLevel}; +use genmc_sys::LogLevel; + +use super::GenmcParams; +use crate::{IsolatedOp, MiriConfig, RejectOpWith}; /// Configuration for GenMC mode. /// The `params` field is shared with the C++ side. @@ -7,6 +10,9 @@ use genmc_sys::{GenmcParams, LogLevel}; pub struct GenmcConfig { /// Parameters sent to the C++ side to create a new handle to the GenMC model checker. pub(super) params: GenmcParams, + /// Print the output message that GenMC generates when an error occurs. + /// This error message is currently hard to use, since there is no clear mapping between the events that GenMC sees and the Rust code location where this event was produced. + pub(super) print_genmc_output: bool, /// The log level for GenMC. pub(super) log_level: LogLevel, } @@ -36,9 +42,61 @@ impl GenmcConfig { }; if let Some(log_level) = trimmed_arg.strip_prefix("log=") { genmc_config.log_level = log_level.parse()?; + } else if let Some(trimmed_arg) = trimmed_arg.strip_prefix("print-exec-graphs") { + use genmc_sys::ExecutiongraphPrinting; + genmc_config.params.print_execution_graphs = match trimmed_arg { + "=none" => ExecutiongraphPrinting::None, + // Make GenMC print explored executions. + "" | "=explored" => ExecutiongraphPrinting::Explored, + // Make GenMC print blocked executions. + "=blocked" => ExecutiongraphPrinting::Blocked, + // Make GenMC print all executions. + "=all" => ExecutiongraphPrinting::ExploredAndBlocked, + _ => + return Err(format!( + "Invalid suffix to GenMC argument '-Zmiri-genmc-print-exec-graphs', expected '', '=none', '=explored', '=blocked' or '=all'" + )), + } + } else if trimmed_arg == "print-genmc-output" { + genmc_config.print_genmc_output = true; } else { return Err(format!("Invalid GenMC argument: \"-Zmiri-genmc-{trimmed_arg}\"")); } Ok(()) } + + /// Validate settings for GenMC mode (NOP if GenMC mode disabled). + /// + /// Unsupported configurations return an error. + /// Adjusts Miri settings where required, printing a warnings if the change might be unexpected for the user. + pub fn validate_genmc_mode_settings(miri_config: &mut MiriConfig) -> Result<(), &'static str> { + let Some(genmc_config) = miri_config.genmc_config.as_mut() else { + return Ok(()); + }; + + // Check for disallowed configurations. + if !miri_config.data_race_detector { + return Err("Cannot disable data race detection in GenMC mode"); + } else if !miri_config.native_lib.is_empty() { + return Err("native-lib not supported in GenMC mode."); + } else if miri_config.isolated_op != IsolatedOp::Reject(RejectOpWith::Abort) { + return Err("Cannot disable isolation in GenMC mode"); + } + + // Adjust settings where needed. + if !miri_config.weak_memory_emulation { + genmc_config.params.disable_weak_memory_emulation = true; + } + if miri_config.borrow_tracker.is_some() { + eprintln!( + "warning: borrow tracking has been disabled, it is not (yet) supported in GenMC mode." + ); + miri_config.borrow_tracker = None; + } + // We enable fixed scheduling so Miri doesn't randomly yield before a terminator, which anyway + // would be a NOP in GenMC mode. + miri_config.fixed_scheduling = true; + + Ok(()) + } } diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs index 7c420961ec54a..92b34b83ee0fc 100644 --- a/src/tools/miri/src/concurrency/genmc/dummy.rs +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -94,9 +94,9 @@ impl GenmcCtx { _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, _address: Size, _size: Size, + _atomic_op: AtomicRmwOp, _is_signed: bool, _ordering: AtomicRwOrd, - _atomic_op: AtomicRmwOp, _rhs_scalar: Scalar, _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option)> { @@ -242,4 +242,10 @@ impl GenmcConfig { Err(format!("GenMC is not supported on this target")) } } + + pub fn validate_genmc_mode_settings( + _miri_config: &mut crate::MiriConfig, + ) -> Result<(), &'static str> { + Ok(()) + } } diff --git a/src/tools/miri/src/concurrency/genmc/helper.rs b/src/tools/miri/src/concurrency/genmc/helper.rs index b70ca8faadfed..2a84ca2036676 100644 --- a/src/tools/miri/src/concurrency/genmc/helper.rs +++ b/src/tools/miri/src/concurrency/genmc/helper.rs @@ -1,11 +1,16 @@ -use genmc_sys::MemOrdering; +use genmc_sys::{MemOrdering, RMWBinOp}; use rustc_abi::Size; use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_middle::mir; use rustc_middle::ty::ScalarInt; use tracing::debug; use super::GenmcScalar; -use crate::{AtomicReadOrd, AtomicWriteOrd, MiriInterpCx, Scalar, throw_unsup_format}; +use crate::intrinsics::AtomicRmwOp; +use crate::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MiriInterpCx, Scalar, + throw_unsup_format, +}; /// Maximum size memory access in bytes that GenMC supports. pub(super) const MAX_ACCESS_SIZE: u64 = 8; @@ -95,3 +100,48 @@ impl AtomicWriteOrd { } } } + +impl AtomicFenceOrd { + pub(super) fn to_genmc(self) -> MemOrdering { + match self { + AtomicFenceOrd::Acquire => MemOrdering::Acquire, + AtomicFenceOrd::Release => MemOrdering::Release, + AtomicFenceOrd::AcqRel => MemOrdering::AcquireRelease, + AtomicFenceOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +impl AtomicRwOrd { + pub(super) fn to_genmc(self) -> MemOrdering { + match self { + AtomicRwOrd::Relaxed => MemOrdering::Relaxed, + AtomicRwOrd::Acquire => MemOrdering::Acquire, + AtomicRwOrd::Release => MemOrdering::Release, + AtomicRwOrd::AcqRel => MemOrdering::AcquireRelease, + AtomicRwOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +/// Convert an atomic binary operation to its GenMC counterpart. +pub(super) fn to_genmc_rmw_op(atomic_op: AtomicRmwOp, is_signed: bool) -> RMWBinOp { + match (atomic_op, is_signed) { + (AtomicRmwOp::Min, true) => RMWBinOp::Min, + (AtomicRmwOp::Max, true) => RMWBinOp::Max, + (AtomicRmwOp::Min, false) => RMWBinOp::UMin, + (AtomicRmwOp::Max, false) => RMWBinOp::UMax, + (AtomicRmwOp::MirOp { op, neg }, _is_signed) => + match (op, neg) { + (mir::BinOp::Add, false) => RMWBinOp::Add, + (mir::BinOp::Sub, false) => RMWBinOp::Sub, + (mir::BinOp::BitXor, false) => RMWBinOp::Xor, + (mir::BinOp::BitAnd, false) => RMWBinOp::And, + (mir::BinOp::BitAnd, true) => RMWBinOp::Nand, + (mir::BinOp::BitOr, false) => RMWBinOp::Or, + _ => { + panic!("unsupported atomic operation: bin_op: {op:?}, negate: {neg}"); + } + }, + } +} diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs index 26ce0b9c43ac7..c1da86c673364 100644 --- a/src/tools/miri/src/concurrency/genmc/mod.rs +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -2,7 +2,7 @@ use std::cell::{Cell, RefCell}; use std::sync::Arc; use genmc_sys::{ - GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, MemOrdering, MiriGenmcShim, UniquePtr, + GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, MemOrdering, MiriGenmcShim, RMWBinOp, UniquePtr, create_genmc_driver_handle, }; use rustc_abi::{Align, Size}; @@ -12,7 +12,9 @@ use rustc_middle::{throw_machine_stop, throw_ub_format, throw_unsup_format}; use tracing::{debug, info}; use self::global_allocations::{EvalContextExt as _, GlobalAllocationHandler}; -use self::helper::{MAX_ACCESS_SIZE, genmc_scalar_to_scalar, scalar_to_genmc_scalar}; +use self::helper::{ + MAX_ACCESS_SIZE, genmc_scalar_to_scalar, scalar_to_genmc_scalar, to_genmc_rmw_op, +}; use self::thread_id_map::ThreadIdMap; use crate::concurrency::genmc::helper::split_access; use crate::intrinsics::AtomicRmwOp; @@ -29,6 +31,8 @@ mod run; pub(crate) mod scheduling; mod thread_id_map; +pub use genmc_sys::GenmcParams; + pub use self::config::GenmcConfig; pub use self::run::run_genmc_mode; @@ -126,22 +130,19 @@ impl GenmcCtx { /// Get the number of blocked executions encountered by GenMC. pub fn get_blocked_execution_count(&self) -> u64 { - let mc = self.handle.borrow(); - mc.as_ref().unwrap().get_blocked_execution_count() + self.handle.borrow().get_blocked_execution_count() } /// Get the number of explored executions encountered by GenMC. pub fn get_explored_execution_count(&self) -> u64 { - let mc = self.handle.borrow(); - mc.as_ref().unwrap().get_explored_execution_count() + self.handle.borrow().get_explored_execution_count() } /// Check if GenMC encountered an error that wasn't immediately returned during execution. /// Returns a string representation of the error if one occurred. pub fn try_get_error(&self) -> Option { - let mc = self.handle.borrow(); - mc.as_ref() - .unwrap() + self.handle + .borrow() .get_error_string() .as_ref() .map(|error| error.to_string_lossy().to_string()) @@ -150,9 +151,8 @@ impl GenmcCtx { /// Check if GenMC encountered an error that wasn't immediately returned during execution. /// Returns a string representation of the error if one occurred. pub fn get_result_message(&self) -> String { - let mc = self.handle.borrow(); - mc.as_ref() - .unwrap() + self.handle + .borrow() .get_result_message() .as_ref() .map(|error| error.to_string_lossy().to_string()) @@ -163,8 +163,7 @@ impl GenmcCtx { /// /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. pub fn is_exploration_done(&self) -> bool { - let mut mc = self.handle.borrow_mut(); - mc.as_mut().unwrap().is_exploration_done() + self.handle.borrow_mut().pin_mut().is_exploration_done() } /// Select whether data race free actions should be allowed. This function should be used carefully! @@ -196,8 +195,7 @@ impl GenmcCtx { // Reset per-execution state. self.exec_state.reset(); // Inform GenMC about the new execution. - let mut mc = self.handle.borrow_mut(); - mc.as_mut().unwrap().handle_execution_start(); + self.handle.borrow_mut().pin_mut().handle_execution_start(); } /// Inform GenMC that the program's execution has ended. @@ -214,13 +212,11 @@ impl GenmcCtx { /// /// To get the all messages (warnings, errors) that GenMC produces, use the `get_result_message` method. fn handle_execution_end(&self) -> Option { - let mut mc = self.handle.borrow_mut(); - let result = mc.as_mut().unwrap().handle_execution_end(); + let result = self.handle.borrow_mut().pin_mut().handle_execution_end(); result.as_ref().map(|msg| msg.to_string_lossy().to_string())?; // GenMC currently does not return an error value immediately in all cases. // We manually query for any errors here to ensure we don't miss any. - drop(mc); // `try_get_error` needs access to the `RefCell`. self.try_get_error() } @@ -282,11 +278,17 @@ impl GenmcCtx { /// Inform GenMC about an atomic fence. pub(crate) fn atomic_fence<'tcx>( &self, - _machine: &MiriMachine<'tcx>, - _ordering: AtomicFenceOrd, + machine: &MiriMachine<'tcx>, + ordering: AtomicFenceOrd, ) -> InterpResult<'tcx> { assert!(!self.get_alloc_data_races(), "atomic fence with data race checking disabled."); - throw_unsup_format!("FIXME(genmc): Add support for atomic fences.") + + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_genmc_tid(curr_thread); + + self.handle.borrow_mut().pin_mut().handle_fence(genmc_tid, ordering.to_genmc()); + interp_ok(()) } /// Inform GenMC about an atomic read-modify-write operation. @@ -296,20 +298,24 @@ impl GenmcCtx { /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_rmw_op<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _is_signed: bool, - _ordering: AtomicRwOrd, - _atomic_op: AtomicRmwOp, - _rhs_scalar: Scalar, - _old_value: Scalar, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + atomic_op: AtomicRmwOp, + is_signed: bool, + ordering: AtomicRwOrd, + rhs_scalar: Scalar, + old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!( - !self.get_alloc_data_races(), - "atomic read-modify-write operation with data race checking disabled." - ); - throw_unsup_format!("FIXME(genmc): Add support for atomic RMW.") + self.handle_atomic_rmw_op( + ecx, + address, + size, + ordering, + to_genmc_rmw_op(atomic_op, is_signed), + scalar_to_genmc_scalar(ecx, rhs_scalar)?, + scalar_to_genmc_scalar(ecx, old_value)?, + ) } /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. @@ -317,18 +323,22 @@ impl GenmcCtx { /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_exchange<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _rhs_scalar: Scalar, - _ordering: AtomicRwOrd, - _old_value: Scalar, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + rhs_scalar: Scalar, + ordering: AtomicRwOrd, + old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!( - !self.get_alloc_data_races(), - "atomic swap operation with data race checking disabled." - ); - throw_unsup_format!("FIXME(genmc): Add support for atomic swap.") + self.handle_atomic_rmw_op( + ecx, + address, + size, + ordering, + /* genmc_rmw_op */ RMWBinOp::Xchg, + scalar_to_genmc_scalar(ecx, rhs_scalar)?, + scalar_to_genmc_scalar(ecx, old_value)?, + ) } /// Inform GenMC about an atomic compare-exchange operation. @@ -493,9 +503,11 @@ impl GenmcCtx { // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte let genmc_size = size.bytes().max(1); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut().unwrap(); - let chosen_address = pinned_mc.handle_malloc(genmc_tid, genmc_size, alignment.bytes()); + let chosen_address = self.handle.borrow_mut().pin_mut().handle_malloc( + genmc_tid, + genmc_size, + alignment.bytes(), + ); // Non-global addresses should not be in the global address space or null. assert_ne!(0, chosen_address, "GenMC malloc returned nullptr."); @@ -530,9 +542,7 @@ impl GenmcCtx { let curr_thread = machine.threads.active_thread(); let genmc_tid = thread_infos.get_genmc_tid(curr_thread); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut().unwrap(); - pinned_mc.handle_free(genmc_tid, address.bytes()); + self.handle.borrow_mut().pin_mut().handle_free(genmc_tid, address.bytes()); interp_ok(()) } @@ -554,9 +564,7 @@ impl GenmcCtx { let genmc_parent_tid = thread_infos.get_genmc_tid(curr_thread_id); let genmc_new_tid = thread_infos.add_thread(new_thread_id); - let mut mc = self.handle.borrow_mut(); - mc.as_mut().unwrap().handle_thread_create(genmc_new_tid, genmc_parent_tid); - + self.handle.borrow_mut().pin_mut().handle_thread_create(genmc_new_tid, genmc_parent_tid); interp_ok(()) } @@ -571,8 +579,7 @@ impl GenmcCtx { let genmc_curr_tid = thread_infos.get_genmc_tid(active_thread_id); let genmc_child_tid = thread_infos.get_genmc_tid(child_thread_id); - let mut mc = self.handle.borrow_mut(); - mc.as_mut().unwrap().handle_thread_join(genmc_curr_tid, genmc_child_tid); + self.handle.borrow_mut().pin_mut().handle_thread_join(genmc_curr_tid, genmc_child_tid); interp_ok(()) } @@ -585,9 +592,8 @@ impl GenmcCtx { let genmc_tid = thread_infos.get_genmc_tid(curr_thread_id); debug!("GenMC: thread {curr_thread_id:?} ({genmc_tid:?}) finished."); - let mut mc = self.handle.borrow_mut(); // NOTE: Miri doesn't support return values for threads, but GenMC expects one, so we return 0 - mc.as_mut().unwrap().handle_thread_finish(genmc_tid, /* ret_val */ 0); + self.handle.borrow_mut().pin_mut().handle_thread_finish(genmc_tid, /* ret_val */ 0); } /// Handle a call to `libc::exit` or the exit of the main thread. @@ -618,8 +624,7 @@ impl GenmcCtx { let thread_infos = self.exec_state.thread_id_manager.borrow(); let genmc_tid = thread_infos.get_genmc_tid(thread); - let mut mc = self.handle.borrow_mut(); - mc.as_mut().unwrap().handle_thread_kill(genmc_tid); + self.handle.borrow_mut().pin_mut().handle_thread_kill(genmc_tid); } else { assert_eq!(thread, ThreadId::MAIN_THREAD); } @@ -669,9 +674,7 @@ impl GenmcCtx { addr = address.bytes() ); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut().unwrap(); - let load_result = pinned_mc.handle_load( + let load_result = self.handle.borrow_mut().pin_mut().handle_load( genmc_tid, address.bytes(), size.bytes(), @@ -722,9 +725,7 @@ impl GenmcCtx { addr = address.bytes() ); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut().unwrap(); - let store_result = pinned_mc.handle_store( + let store_result = self.handle.borrow_mut().pin_mut().handle_store( genmc_tid, address.bytes(), size.bytes(), @@ -741,6 +742,62 @@ impl GenmcCtx { interp_ok(store_result.is_coherence_order_maximal_write) } + /// Inform GenMC about an atomic read-modify-write operation. + /// This includes atomic swap (also often called "exchange"), but does *not* + /// include compare-exchange (see `RMWBinOp` for full list of operations). + /// Returns the previous value at that memory location, and optionally the value that should be written back to Miri's memory. + fn handle_atomic_rmw_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + genmc_rmw_op: RMWBinOp, + genmc_rhs_scalar: GenmcScalar, + genmc_old_value: GenmcScalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!( + !self.get_alloc_data_races(), + "atomic read-modify-write operation with data race checking disabled." + ); + assert_ne!(0, size.bytes()); + assert!( + size.bytes() <= MAX_ACCESS_SIZE, + "GenMC currently does not support atomic accesses larger than {} bytes (got {} bytes)", + MAX_ACCESS_SIZE, + size.bytes() + ); + + let curr_thread_id = ecx.machine.threads.active_thread(); + let genmc_tid = self.exec_state.thread_id_manager.borrow().get_genmc_tid(curr_thread_id); + debug!( + "GenMC: atomic_rmw_op, thread: {curr_thread_id:?} ({genmc_tid:?}) (op: {genmc_rmw_op:?}, rhs value: {genmc_rhs_scalar:?}), address: {address:?}, size: {size:?}, ordering: {ordering:?}", + ); + let rmw_result = self.handle.borrow_mut().pin_mut().handle_read_modify_write( + genmc_tid, + address.bytes(), + size.bytes(), + genmc_rmw_op, + ordering.to_genmc(), + genmc_rhs_scalar, + genmc_old_value, + ); + + if let Some(error) = rmw_result.error.as_ref() { + // FIXME(genmc): error handling + throw_ub_format!("{}", error.to_string_lossy()); + } + + let old_value_scalar = genmc_scalar_to_scalar(ecx, rmw_result.old_value, size)?; + + let new_value_scalar = if rmw_result.is_coherence_order_maximal_write { + Some(genmc_scalar_to_scalar(ecx, rmw_result.new_value, size)?) + } else { + None + }; + interp_ok((old_value_scalar, new_value_scalar)) + } + /**** Blocking functionality ****/ /// Handle a user thread getting blocked. diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs index 62553297a2024..24d13e6375b11 100644 --- a/src/tools/miri/src/concurrency/genmc/run.rs +++ b/src/tools/miri/src/concurrency/genmc/run.rs @@ -18,6 +18,8 @@ pub fn run_genmc_mode<'tcx>( eval_entry: impl Fn(Rc) -> Option, tcx: TyCtxt<'tcx>, ) -> Option { + let genmc_config = config.genmc_config.as_ref().unwrap(); + // There exists only one `global_state` per full run in GenMC mode. // It is shared by all `GenmcCtx` in this run. // FIXME(genmc): implement multithreading once GenMC supports it. @@ -32,8 +34,15 @@ pub fn run_genmc_mode<'tcx>( genmc_ctx.prepare_next_execution(); // Execute the program until completion to get the return value, or return if an error happens: - // FIXME(genmc): add an option to allow the user to see the GenMC output message when the verification is done. - let return_code = eval_entry(genmc_ctx.clone())?; + let Some(return_code) = eval_entry(genmc_ctx.clone()) else { + // If requested, print the output GenMC produced: + if genmc_config.print_genmc_output { + eprintln!("== raw GenMC output ========================="); + eprintln!("{}", genmc_ctx.get_result_message()); + eprintln!("== end of raw GenMC output =================="); + } + return None; + }; // We inform GenMC that the execution is complete. If there was an error, we print it. if let Some(error) = genmc_ctx.handle_execution_end() { diff --git a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.rs b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.rs new file mode 100644 index 0000000000000..508eae756f320 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.rs @@ -0,0 +1,66 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright (c) 2019 Carl Lerche + +// This is the test `checks_fail` from loom/test/smoke.rs adapted for Miri-GenMC. +// https://github.com/tokio-rs/loom/blob/dbf32b04bae821c64be44405a0bb72ca08741558/tests/smoke.rs + +// This test checks that an incorrect implementation of an incrementing counter is detected. +// The counter behaves wrong if two threads try to increment at the same time (increments can be lost). + +#![no_main] + +#[cfg(not(any(non_genmc_std, genmc_std)))] +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +struct BuggyInc { + num: AtomicUsize, +} + +impl BuggyInc { + const fn new() -> BuggyInc { + BuggyInc { num: AtomicUsize::new(0) } + } + + fn inc(&self) { + // The bug is here: + // Another thread can increment `self.num` between the next two lines, + // which is then overridden by this thread. + let curr = self.num.load(Acquire); + self.num.store(curr + 1, Release); + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + static BUGGY_INC: BuggyInc = BuggyInc::new(); + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + BUGGY_INC.num.store(0, Relaxed); + + let ids = [ + spawn_pthread_closure(|| { + BUGGY_INC.inc(); + }), + spawn_pthread_closure(|| { + BUGGY_INC.inc(); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // We check that we can detect the incorrect counter implementation: + if 2 != BUGGY_INC.num.load(Relaxed) { + std::process::abort(); //~ ERROR: abnormal termination + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr new file mode 100644 index 0000000000000..5a8948ff9b4b8 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: the program aborted execution + --> tests/genmc/fail/loom/buggy_inc.rs:LL:CC + | +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/loom/buggy_inc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr index e2b114df652f8..cbfb6ec833eb0 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr @@ -1,11 +1,9 @@ -error: Undefined Behavior: entering unreachable code +error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr index e2b114df652f8..cbfb6ec833eb0 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr @@ -1,11 +1,9 @@ -error: Undefined Behavior: entering unreachable code +error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs index dea2b5f952e7e..baf3584966ec8 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.rs @@ -7,7 +7,7 @@ // When using any combination of orderings except using all 4 `SeqCst`, the memory model allows the program to result in (X, Y) == (1, 1). // The "pass" variants only check that we get the expected number of executions (3 for all SC, 4 otherwise), // and a valid outcome every execution, but do not check that we get all allowed results. -// This "fail" variant ensures we can explore the execution resulting in (1, 1), an incorrect unsafe assumption that the result (1, 1) is impossible. +// This "fail" variant ensures we can explore the execution resulting in (1, 1), with an incorrect assumption that the result (1, 1) is impossible. // // Miri without GenMC is unable to produce this program execution and thus detect the incorrect assumption, even with `-Zmiri-many-seeds`. // @@ -61,11 +61,10 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { // Join so we can read the final values. join_pthreads(ids); - // We mark the result (1, 1) as unreachable, which is incorrect. + // We incorrectly assume that the result (1, 1) as unreachable. let result = (X.load(Relaxed), Y.load(Relaxed)); if result == (1, 1) { - // FIXME(genmc): Use `std::process::abort()` once backtraces for that are improved (https://github.com/rust-lang/rust/pull/146118) - std::hint::unreachable_unchecked(); //~ ERROR: entering unreachable code + std::process::abort(); //~ ERROR: abnormal termination } 0 diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr index e2b114df652f8..cbfb6ec833eb0 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr @@ -1,11 +1,9 @@ -error: Undefined Behavior: entering unreachable code +error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_weak.rs:LL:CC diff --git a/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.rs b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.rs new file mode 100644 index 0000000000000..f48466e8ce10c --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.rs @@ -0,0 +1,91 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// This test check for correct handling of atomic read-modify-write operations for all integer sizes. +// Atomic max and min should return the previous value, and store the result in the atomic. +// Atomic addition and subtraction should have wrapping semantics. +// `and`, `nand`, `or`, `xor` should behave like their non-atomic counterparts. + +// FIXME(genmc): add 128 bit atomics for platforms that support it, once GenMC gets 128 bit atomic support + +#![no_main] + +use std::sync::atomic::*; + +const ORD: Ordering = Ordering::SeqCst; + +fn assert_eq(x: T, y: T) { + if x != y { + std::process::abort(); + } +} + +macro_rules! test_rmw_edge_cases { + ($int:ty, $atomic:ty) => {{ + let x = <$atomic>::new(123); + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + x.store(123, ORD); + + // MAX, ADD + assert_eq(123, x.fetch_max(0, ORD)); // `max` keeps existing value + assert_eq(123, x.fetch_max(<$int>::MAX, ORD)); // `max` stores the new value + assert_eq(<$int>::MAX, x.fetch_add(10, ORD)); // `fetch_add` should be wrapping + assert_eq(<$int>::MAX.wrapping_add(10), x.load(ORD)); + + // MIN, SUB + x.store(42, ORD); + assert_eq(42, x.fetch_min(<$int>::MAX, ORD)); // `min` keeps existing value + assert_eq(42, x.fetch_min(<$int>::MIN, ORD)); // `min` stores the new value + assert_eq(<$int>::MIN, x.fetch_sub(10, ORD)); // `fetch_sub` should be wrapping + assert_eq(<$int>::MIN.wrapping_sub(10), x.load(ORD)); + + // Small enough pattern to work for all integer sizes. + let pattern = 0b01010101; + + // AND + x.store(!0, ORD); + assert_eq(!0, x.fetch_and(pattern, ORD)); + assert_eq(!0 & pattern, x.load(ORD)); + + // NAND + x.store(!0, ORD); + assert_eq(!0, x.fetch_nand(pattern, ORD)); + assert_eq(!(!0 & pattern), x.load(ORD)); + + // OR + x.store(!0, ORD); + assert_eq(!0, x.fetch_or(pattern, ORD)); + assert_eq(!0 | pattern, x.load(ORD)); + + // XOR + x.store(!0, ORD); + assert_eq(!0, x.fetch_xor(pattern, ORD)); + assert_eq(!0 ^ pattern, x.load(ORD)); + + // SWAP + x.store(!0, ORD); + assert_eq(!0, x.swap(pattern, ORD)); + assert_eq(pattern, x.load(ORD)); + + // Check correct behavior of atomic min/max combined with overflowing add/sub. + x.store(10, ORD); + assert_eq(10, x.fetch_add(<$int>::MAX, ORD)); // definitely overflows, so new value of x is smaller than 10 + assert_eq(<$int>::MAX.wrapping_add(10), x.fetch_max(10, ORD)); // new value of x should be 10 + // assert_eq(10, x.load(ORD)); // FIXME(genmc,#4572): enable this check once GenMC correctly handles min/max truncation. + }}; +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + test_rmw_edge_cases!(u8, AtomicU8); + test_rmw_edge_cases!(u16, AtomicU16); + test_rmw_edge_cases!(u32, AtomicU32); + test_rmw_edge_cases!(u64, AtomicU64); + test_rmw_edge_cases!(usize, AtomicUsize); + test_rmw_edge_cases!(i8, AtomicI8); + test_rmw_edge_cases!(i16, AtomicI16); + test_rmw_edge_cases!(i32, AtomicI32); + test_rmw_edge_cases!(i64, AtomicI64); + test_rmw_edge_cases!(isize, AtomicIsize); + + 0 +} diff --git a/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr new file mode 100644 index 0000000000000..3b22247ee44cb --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.rs b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.rs new file mode 100644 index 0000000000000..3b3fca02285d6 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.rs @@ -0,0 +1,33 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "2+2W+2sc+scf". +// It tests correct handling of SeqCst fences combined with relaxed accesses. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X.store(1, SeqCst); + Y.store(2, SeqCst); + }); + spawn_pthread_closure(|| { + Y.store(1, Relaxed); + std::sync::atomic::fence(SeqCst); + X.store(2, Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs index bbe9995dea0b2..f47f5a11c5c96 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.rs @@ -1,9 +1,13 @@ +//@revisions: weak sc //@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@[sc]compile-flags: -Zmiri-disable-weak-memory-emulation // Translated from GenMC's test "2+2W". // // The pass tests "2w2w_3sc_1rel.rs", "2w2w_4rel" and "2w2w_4sc" and the fail test "2w2w_weak.rs" are related. // Check "2w2w_weak.rs" for a more detailed description. +// +// The `sc` variant of this test checks that without weak memory emulation, only 3 instead of 4 executions are explored (like the `2w2w_4sc.rs` test). #![no_main] diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr similarity index 100% rename from src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.stderr rename to src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs index 79e7c7feb7aac..1ec62ff21342d 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows -// Translated from GenMC's "IRIW-acq-sc" test. +// Translated from GenMC's "litmus/IRIW-acq-sc" test. #![no_main] diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs new file mode 100644 index 0000000000000..163556dcc8975 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs @@ -0,0 +1,66 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/IRIWish" test. +// This test prints the values read by the different threads to check that we get all the values we expect. + +// NOTE: the order of the lines in the output may change with changes to GenMC. +// Before blessing the new output, ensure that only the order of lines in the output changed, and none of the outputs are missing. + +// NOTE: GenMC supports instruction caching and does not need replay completed threads. +// This means that an identical test in GenMC may output fewer lines (disable instruction caching to see all results). + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; +#[path = "../../../utils/mod.rs"] +mod utils; + +use std::fmt::Write; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; +use crate::utils::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut results = [1234; 5]; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Relaxed); + }), + spawn_pthread_closure(|| { + let r1 = X.load(Relaxed); + Y.store(r1, Release); + results[0] = r1; + }), + spawn_pthread_closure(|| { + results[1] = X.load(Relaxed); + std::sync::atomic::fence(AcqRel); + results[2] = Y.load(Relaxed); + }), + spawn_pthread_closure(|| { + results[3] = Y.load(Relaxed); + std::sync::atomic::fence(AcqRel); + results[4] = X.load(Relaxed); + }), + ]; + join_pthreads(ids); + + // Print the values to check that we get all of them: + if writeln!(MiriStderr, "{results:?}").is_err() { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr new file mode 100644 index 0000000000000..4fc77b63f3803 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr @@ -0,0 +1,30 @@ +[1, 1, 1, 1, 1] +[1, 1, 1, 0, 1] +[1, 1, 1, 0, 0] +[1, 1, 0, 1, 1] +[1, 1, 0, 0, 1] +[1, 1, 0, 0, 0] +[1, 0, 1, 1, 1] +[1, 0, 1, 0, 1] +[1, 0, 1, 0, 0] +[1, 0, 0, 1, 1] +[1, 0, 0, 0, 1] +[1, 0, 0, 0, 0] +[0, 1, 0, 0, 1] +[0, 1, 0, 0, 0] +[0, 1, 0, 0, 1] +[0, 1, 0, 0, 0] +[0, 1, 0, 0, 1] +[0, 1, 0, 0, 0] +[0, 1, 0, 0, 1] +[0, 1, 0, 0, 0] +[0, 0, 0, 0, 1] +[0, 0, 0, 0, 0] +[0, 0, 0, 0, 1] +[0, 0, 0, 0, 0] +[0, 0, 0, 0, 1] +[0, 0, 0, 0, 0] +[0, 0, 0, 0, 1] +[0, 0, 0, 0, 0] +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 28 diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.rs b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.rs new file mode 100644 index 0000000000000..e43d92fc6c55a --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.rs @@ -0,0 +1,41 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/LB+incMPs" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static W: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X.load(Acquire); + Z.fetch_add(1, AcqRel); + }); + spawn_pthread_closure(|| { + Z.fetch_add(1, AcqRel); + Y.store(1, Release); + }); + spawn_pthread_closure(|| { + Y.load(Acquire); + W.fetch_add(1, AcqRel); + }); + spawn_pthread_closure(|| { + W.fetch_add(1, AcqRel); + X.store(1, Release); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr new file mode 100644 index 0000000000000..c879e95a17085 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 15 diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.rs b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.rs new file mode 100644 index 0000000000000..b36c8a288f426 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/MPU+rels+acq" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU+rels+acq/mpu+rels+acq.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::genmc::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + spawn_pthread_closure(|| { + X.store(1, Relaxed); + + Y.store(0, Release); + Y.store(1, Relaxed); + }); + spawn_pthread_closure(|| { + Y.fetch_add(1, Relaxed); + }); + spawn_pthread_closure(|| { + if Y.load(Acquire) > 1 { + X.store(2, Relaxed); + } + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr new file mode 100644 index 0000000000000..c5e34b00642aa --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 13 diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.rs b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.rs new file mode 100644 index 0000000000000..a08b7de27d13c --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.rs @@ -0,0 +1,36 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/MP+incMP" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + Y.load(Acquire); + Z.fetch_add(1, AcqRel); + }); + spawn_pthread_closure(|| { + Z.fetch_add(1, AcqRel); + X.load(Acquire); + }); + spawn_pthread_closure(|| { + X.store(1, Release); + Y.store(1, Release); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr new file mode 100644 index 0000000000000..2be9a6c7fbded --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 7 diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.rs b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.rs new file mode 100644 index 0000000000000..cf9f5f2dbfa34 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/MP+rels+acqf" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MP+rels+acqf/mp+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::genmc::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + spawn_pthread_closure(|| { + X.store(1, Relaxed); + + Y.store(0, Release); + Y.store(1, Relaxed); + }); + spawn_pthread_closure(|| { + if Y.load(Relaxed) != 0 { + std::sync::atomic::fence(Acquire); + let _x = X.load(Relaxed); + } + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.rs b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.rs new file mode 100644 index 0000000000000..ffc44de1bc7cf --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/SB+2sc+scf" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X.store(1, SeqCst); + Y.load(SeqCst); + }); + spawn_pthread_closure(|| { + Y.store(1, Relaxed); + std::sync::atomic::fence(SeqCst); + X.load(Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs new file mode 100644 index 0000000000000..ac5c3724254d6 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs @@ -0,0 +1,65 @@ +//@revisions: weak sc +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@[sc]compile-flags: -Zmiri-disable-weak-memory-emulation + +// Translated from GenMC's "litmus/Z6.U" test. +// +// The `sc` variant of this test checks that we get fewer executions when weak memory emulation is disabled. + +// NOTE: the order of the lines in the output may change with changes to GenMC. +// Before blessing the new output, ensure that only the order of lines in the output changed, and none of the outputs are missing. + +// NOTE: GenMC supports instruction caching and does not need replay completed threads. +// This means that an identical test in GenMC may output fewer lines (disable instruction caching to see all results). + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; +#[path = "../../../utils/mod.rs"] +mod utils; + +use std::fmt::Write; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; +use crate::utils::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, SeqCst); + Y.store(1, Release); + }), + spawn_pthread_closure(|| { + Y.fetch_add(1, SeqCst); + a = Y.load(Relaxed); + }), + spawn_pthread_closure(|| { + Y.store(3, SeqCst); + b = X.load(SeqCst); + }), + ]; + join_pthreads(ids); + + // Print the values to check that we get all of them: + if writeln!(MiriStderr, "a={a}, b={b}, X={}, Y={}", X.load(Relaxed), Y.load(Relaxed)) + .is_err() + { + std::process::abort(); + } + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr new file mode 100644 index 0000000000000..8dd2fbe1b9757 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr @@ -0,0 +1,20 @@ +a=2, b=1, X=1, Y=3 +a=4, b=1, X=1, Y=4 +a=3, b=1, X=1, Y=3 +a=2, b=1, X=1, Y=2 +a=2, b=0, X=1, Y=2 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +a=4, b=1, X=1, Y=1 +a=4, b=0, X=1, Y=1 +a=1, b=1, X=1, Y=3 +a=3, b=1, X=1, Y=3 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +a=3, b=1, X=1, Y=1 +a=3, b=0, X=1, Y=1 +a=1, b=1, X=1, Y=3 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 18 diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr new file mode 100644 index 0000000000000..65622575de21d --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr @@ -0,0 +1,24 @@ +a=2, b=1, X=1, Y=3 +a=4, b=1, X=1, Y=4 +a=4, b=0, X=1, Y=4 +a=3, b=1, X=1, Y=3 +a=2, b=1, X=1, Y=2 +a=2, b=0, X=1, Y=2 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +a=4, b=1, X=1, Y=1 +a=4, b=0, X=1, Y=1 +a=1, b=1, X=1, Y=3 +a=1, b=0, X=1, Y=3 +a=3, b=1, X=1, Y=3 +a=3, b=0, X=1, Y=3 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +a=3, b=1, X=1, Y=1 +a=3, b=0, X=1, Y=1 +a=1, b=1, X=1, Y=3 +a=1, b=0, X=1, Y=3 +a=1, b=1, X=1, Y=1 +a=1, b=0, X=1, Y=1 +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 22 diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.rs b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.rs new file mode 100644 index 0000000000000..b00f3a59ce672 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.rs @@ -0,0 +1,38 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/Z6+acq" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X.store(1, Relaxed); + std::sync::atomic::fence(SeqCst); + Y.store(1, Relaxed); + }); + spawn_pthread_closure(|| { + Y.load(Acquire); + Z.store(1, Relaxed); + }); + spawn_pthread_closure(|| { + Z.store(2, Relaxed); + std::sync::atomic::fence(SeqCst); + X.load(Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr new file mode 100644 index 0000000000000..2be9a6c7fbded --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 7 diff --git a/src/tools/miri/tests/genmc/pass/litmus/atomicpo.rs b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.rs new file mode 100644 index 0000000000000..75be89893dab8 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/atomicpo". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + X.store(1, Relaxed); + std::sync::atomic::fence(AcqRel); + Y.store(1, Relaxed); + }); + spawn_pthread_closure(|| { + Y.swap(1, Relaxed); + X.swap(1, Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr new file mode 100644 index 0000000000000..0667962f99c88 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/src/tools/miri/tests/genmc/pass/litmus/cumul-release.rs b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.rs new file mode 100644 index 0000000000000..2387976a8ca61 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.rs @@ -0,0 +1,58 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/cumul-release". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + Z.store(0, Relaxed); + + unsafe { + let mut a = 1234; + let mut b = 1234; + let mut c = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Relaxed); + Y.store(1, Release); + }), + spawn_pthread_closure(|| { + a = Y.load(Relaxed); + Z.store(a, Relaxed); + }), + spawn_pthread_closure(|| { + b = Z.load(Relaxed); + std::sync::atomic::fence(AcqRel); + c = X.load(Relaxed); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + if !matches!( + (a, b, c), + (0, 0, 0) | (0, 0, 1) | (1, 0, 0) | (1, 0, 1) | (1, 1, 0) | (1, 1, 1) + ) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr new file mode 100644 index 0000000000000..00394048ec5c6 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 8 diff --git a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs index 9a08d517b7c60..796ffbf97f96b 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.rs @@ -38,7 +38,6 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { result[3] = X.load(Relaxed); }), ]; - // Join so we can read the final values. join_pthreads(ids); diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc2w.rs b/src/tools/miri/tests/genmc/pass/litmus/inc2w.rs new file mode 100644 index 0000000000000..fd8574c4f7c78 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/inc2w.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/inc2w". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + let ids = [ + spawn_pthread_closure(|| { + X.fetch_add(1, Relaxed); + }), + spawn_pthread_closure(|| { + X.store(4, Release); + }), + spawn_pthread_closure(|| { + X.fetch_add(2, Relaxed); + }), + ]; + // Join so we can read the final values. + join_pthreads(ids); + + // Check that we don't get any unexpected values: + let x = X.load(Relaxed); + if !matches!(x, 4..=7) { + std::process::abort(); + } + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr b/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr new file mode 100644 index 0000000000000..be75e68fde77d --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.rs b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.rs new file mode 100644 index 0000000000000..40ca486318598 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.rs @@ -0,0 +1,63 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::ffi::c_void; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +static mut A: u64 = 0; +static mut B: u64 = 0; +static mut C: u64 = 0; +static mut D: u64 = 0; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4, thread_5]; + let ids = unsafe { spawn_pthreads_no_params(thread_order) }; + unsafe { join_pthreads(ids) }; + + if unsafe { A == 42 && B == 2 && C == 1 && D == 42 } { + std::process::abort(); + } + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Relaxed); + std::ptr::null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Relaxed); + std::ptr::null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + unsafe { + A = X.load(Relaxed); + B = X.load(Relaxed); + } + std::ptr::null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + X.store(42, Relaxed); + std::ptr::null_mut() +} + +pub extern "C" fn thread_5(_value: *mut c_void) -> *mut c_void { + unsafe { + C = X.load(Relaxed); + D = X.load(Relaxed); + } + std::ptr::null_mut() +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr new file mode 100644 index 0000000000000..b5f8cd15b683f --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 600 diff --git a/src/tools/miri/tests/genmc/pass/litmus/riwi.rs b/src/tools/miri/tests/genmc/pass/litmus/riwi.rs new file mode 100644 index 0000000000000..49564c8e4fe0a --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/riwi.rs @@ -0,0 +1,31 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/riwi" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + Y.load(Relaxed); + X.fetch_add(1, Relaxed); + }); + spawn_pthread_closure(|| { + X.fetch_add(1, Relaxed); + Y.store(1, Release); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr b/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr new file mode 100644 index 0000000000000..115b1986ce557 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs new file mode 100644 index 0000000000000..a193dcf0683ea --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs @@ -0,0 +1,36 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/viktor-relseq" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static LOCK: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + spawn_pthread_closure(|| { + LOCK.fetch_add(1, Acquire); + LOCK.fetch_add(1, Relaxed); + }); + spawn_pthread_closure(|| { + LOCK.fetch_add(1, Relaxed); + LOCK.fetch_add(1, Relaxed); + }); + spawn_pthread_closure(|| { + LOCK.fetch_add(1, Release); + }); + spawn_pthread_closure(|| { + LOCK.fetch_add(1, Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr new file mode 100644 index 0000000000000..d63ac5199d5d4 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 180 diff --git a/src/tools/miri/tests/utils/genmc.rs b/src/tools/miri/tests/utils/genmc.rs index fb6334bd06086..29b3181992b11 100644 --- a/src/tools/miri/tests/utils/genmc.rs +++ b/src/tools/miri/tests/utils/genmc.rs @@ -51,6 +51,13 @@ pub unsafe fn join_pthread(thread_id: pthread_t) { } } +/// Spawn `N` threads using `pthread_create` without any arguments, abort the process on any errors. +pub unsafe fn spawn_pthreads_no_params( + functions: [extern "C" fn(*mut c_void) -> *mut c_void; N], +) -> [pthread_t; N] { + functions.map(|func| spawn_pthread(func, std::ptr::null_mut())) +} + // Join the `N` given pthreads, abort the process on any errors. pub unsafe fn join_pthreads(thread_ids: [pthread_t; N]) { let _ = thread_ids.map(|id| join_pthread(id)); From 344b4ac427999c382f575308af3569b2148485a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Sep 2025 07:55:10 +0200 Subject: [PATCH 157/251] print proper error when using unsupported synchronization primitive with GenMC --- src/tools/miri/src/alloc_addresses/mod.rs | 2 + src/tools/miri/src/concurrency/data_race.rs | 22 +++--- src/tools/miri/src/concurrency/init_once.rs | 10 +-- src/tools/miri/src/concurrency/sync.rs | 68 ++++++------------- .../miri/src/shims/unix/linux_like/epoll.rs | 2 +- .../miri/src/shims/unix/linux_like/eventfd.rs | 2 +- src/tools/miri/src/shims/unix/macos/sync.rs | 4 +- src/tools/miri/src/shims/unix/sync.rs | 16 ++--- .../miri/src/shims/unix/unnamed_socket.rs | 2 +- 9 files changed, 52 insertions(+), 76 deletions(-) diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 5d94a1f4138a6..f011ee717850d 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -498,6 +498,8 @@ impl<'tcx> MiriMachine<'tcx> { // Also remember this address for future reuse. let thread = self.threads.active_thread(); global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || { + // We already excluded GenMC above. We cannot use `self.release_clock` as + // `self.alloc_addresses` is borrowed. if let Some(data_race) = self.data_race.as_vclocks_ref() { data_race.release_clock(&self.threads, |clock| clock.clone()) } else { diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 30061a78594aa..de60e80b9f7eb 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -958,16 +958,20 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// with this program point. /// /// The closure will only be invoked if data race handling is on. - fn release_clock(&self, callback: impl FnOnce(&VClock) -> R) -> Option { + fn release_clock( + &self, + callback: impl FnOnce(&VClock) -> R, + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); - // FIXME: make this a proper error instead of ICEing the interpreter. - assert!( - this.machine.data_race.as_genmc_ref().is_none(), - "this operation performs synchronization that is not supported in GenMC mode" - ); - Some( - this.machine.data_race.as_vclocks_ref()?.release_clock(&this.machine.threads, callback), - ) + interp_ok(match &this.machine.data_race { + GlobalDataRaceHandler::None => None, + GlobalDataRaceHandler::Genmc(_genmc_ctx) => + throw_unsup_format!( + "this operation performs synchronization that is not supported in GenMC mode" + ), + GlobalDataRaceHandler::Vclocks(data_race) => + Some(data_race.release_clock(&this.machine.threads, callback)), + }) } /// Acquire the given clock into the current thread, establishing synchronization with diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 3fb3d890419f7..daea20b3779b2 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -96,10 +96,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Complete; // Each complete happens-before the end of the wait - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race - .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); - } + this.release_clock(|clock| init_once.clock.clone_from(clock))?; // Wake up everyone. // need to take the queue to avoid having `this` be borrowed multiple times @@ -125,10 +122,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Uninitialized; // Each complete happens-before the end of the wait - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race - .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); - } + this.release_clock(|clock| init_once.clock.clone_from(clock))?; // Wake up one waiting thread, so they can go ahead and try to init this. if let Some(waiter) = init_once.waiters.pop_front() { diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 179094db0febd..15d486c27e36a 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -204,7 +204,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest))); } else { // We can have it right now! - this.mutex_lock(&mutex_ref); + this.mutex_lock(&mutex_ref)?; // Don't forget to write the return value. this.write_scalar(retval, &dest)?; } @@ -338,7 +338,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Lock by setting the mutex owner and increasing the lock count. - fn mutex_lock(&mut self, mutex_ref: &MutexRef) { + fn mutex_lock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread = this.active_thread(); let mut mutex = mutex_ref.0.borrow_mut(); @@ -352,9 +352,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.strict_add(1); - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock(&mutex.clock, &this.machine.threads); - } + this.acquire_clock(&mutex.clock)?; + interp_ok(()) } /// Try unlocking by decreasing the lock count and returning the old lock @@ -377,11 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The mutex is completely unlocked. Try transferring ownership // to another thread. - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.release_clock(&this.machine.threads, |clock| { - mutex.clock.clone_from(clock) - }); - } + this.release_clock(|clock| mutex.clock.clone_from(clock))?; let thread_id = mutex.queue.pop_front(); // We need to drop our mutex borrow before unblock_thread // because it will be borrowed again in the unblock callback. @@ -425,7 +420,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(unblock, UnblockKind::Ready); assert!(mutex_ref.owner().is_none()); - this.mutex_lock(&mutex_ref); + this.mutex_lock(&mutex_ref)?; if let Some((retval, dest)) = retval_dest { this.write_scalar(retval, &dest)?; @@ -439,7 +434,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Read-lock the lock by adding the `reader` the list of threads that own /// this lock. - fn rwlock_reader_lock(&mut self, rwlock_ref: &RwLockRef) { + fn rwlock_reader_lock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread = this.active_thread(); trace!("rwlock_reader_lock: now also held (one more time) by {:?}", thread); @@ -447,9 +442,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert!(!rwlock.is_write_locked(), "the lock is write locked"); let count = rwlock.readers.entry(thread).or_insert(0); *count = count.strict_add(1); - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); - } + this.acquire_clock(&rwlock.clock_unlocked)?; + interp_ok(()) } /// Try read-unlock the lock for the current threads and potentially give the lock to a new owner. @@ -472,12 +466,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock } - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - // Add this to the shared-release clock of all concurrent readers. - data_race.release_clock(&this.machine.threads, |clock| { - rwlock.clock_current_readers.join(clock) - }); - } + // Add this to the shared-release clock of all concurrent readers. + this.release_clock(|clock| rwlock.clock_current_readers.join(clock))?; // The thread was a reader. If the lock is not held any more, give it to a writer. if rwlock.is_locked().not() { @@ -521,7 +511,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); - this.rwlock_reader_lock(&rwlock_ref); + this.rwlock_reader_lock(&rwlock_ref)?; this.write_scalar(retval, &dest)?; interp_ok(()) } @@ -531,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Lock by setting the writer that owns the lock. #[inline] - fn rwlock_writer_lock(&mut self, rwlock_ref: &RwLockRef) { + fn rwlock_writer_lock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread = this.active_thread(); trace!("rwlock_writer_lock: now held by {:?}", thread); @@ -539,9 +529,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut rwlock = rwlock_ref.0.borrow_mut(); assert!(!rwlock.is_locked(), "the rwlock is already locked"); rwlock.writer = Some(thread); - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); - } + this.acquire_clock(&rwlock.clock_unlocked)?; + interp_ok(()) } /// Try to unlock an rwlock held by the current thread. @@ -559,11 +548,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { rwlock.writer = None; trace!("rwlock_writer_unlock: unlocked by {:?}", thread); // Record release clock for next lock holder. - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.release_clock(&this.machine.threads, |clock| { - rwlock.clock_unlocked.clone_from(clock) - }); - } + this.release_clock(|clock| rwlock.clock_unlocked.clone_from(clock))?; // The thread was a writer. // @@ -613,7 +598,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); - this.rwlock_writer_lock(&rwlock_ref); + this.rwlock_writer_lock(&rwlock_ref)?; this.write_scalar(retval, &dest)?; interp_ok(()) } @@ -663,12 +648,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match unblock { UnblockKind::Ready => { // The condvar was signaled. Make sure we get the clock for that. - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock( + this.acquire_clock( &condvar_ref.0.borrow().clock, - &this.machine.threads, - ); - } + )?; // Try to acquire the mutex. // The timeout only applies to the first wait (until the signal), not for mutex acquisition. this.condvar_reacquire_mutex(mutex_ref, retval_succ, dest) @@ -695,9 +677,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut condvar = condvar_ref.0.borrow_mut(); // Each condvar signal happens-before the end of the condvar wake - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.release_clock(&this.machine.threads, |clock| condvar.clock.clone_from(clock)); - } + this.release_clock(|clock| condvar.clock.clone_from(clock))?; let Some(waiter) = condvar.waiters.pop_front() else { return interp_ok(false); }; @@ -736,9 +716,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { UnblockKind::Ready => { let futex = futex_ref.0.borrow(); // Acquire the clock of the futex. - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.acquire_clock(&futex.clock, &this.machine.threads); - } + this.acquire_clock(&futex.clock)?; }, UnblockKind::TimedOut => { // Remove the waiter from the futex. @@ -766,9 +744,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut futex = futex_ref.0.borrow_mut(); // Each futex-wake happens-before the end of the futex wait - if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { - data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock)); - } + this.release_clock(|clock| futex.clock.clone_from(clock))?; // Remove `count` of the threads in the queue that match any of the bits in the bitset. // We collect all of them before unblocking because the unblock callback may access the diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index aac880feda40e..3133c149293db 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -608,7 +608,7 @@ fn check_and_update_one_event_interest<'tcx>( // If we are tracking data races, remember the current clock so we can sync with it later. ecx.release_clock(|clock| { event_instance.clock.clone_from(clock); - }); + })?; // Triggers the notification by inserting it to the ready list. ready_list.insert(epoll_key, event_instance); interp_ok(true) diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 54cc571884dc8..5d4f207d365e1 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -199,7 +199,7 @@ fn eventfd_write<'tcx>( // Future `read` calls will synchronize with this write, so update the FD clock. ecx.release_clock(|clock| { eventfd.clock.borrow_mut().join(clock); - }); + })?; // Store new counter value. eventfd.counter.set(new_count); diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs index 05616dd5a4287..c4ddff7805ed2 100644 --- a/src/tools/miri/src/shims/unix/macos/sync.rs +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -296,7 +296,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.mutex_enqueue_and_block(mutex_ref, None); } else { - this.mutex_lock(&mutex_ref); + this.mutex_lock(&mutex_ref)?; } interp_ok(()) @@ -321,7 +321,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // reentrancy. this.write_scalar(Scalar::from_bool(false), dest)?; } else { - this.mutex_lock(&mutex_ref); + this.mutex_lock(&mutex_ref)?; this.write_scalar(Scalar::from_bool(true), dest)?; } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 5ad4fd501a607..cefd8b81ac180 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -498,14 +498,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock), MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"), MutexKind::Recursive => { - this.mutex_lock(&mutex.mutex_ref); + this.mutex_lock(&mutex.mutex_ref)?; 0 } } } } else { // The mutex is unlocked. Let's lock it. - this.mutex_lock(&mutex.mutex_ref); + this.mutex_lock(&mutex.mutex_ref)?; 0 }; this.write_scalar(Scalar::from_i32(ret), dest)?; @@ -525,14 +525,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MutexKind::Default | MutexKind::Normal | MutexKind::ErrorCheck => this.eval_libc_i32("EBUSY"), MutexKind::Recursive => { - this.mutex_lock(&mutex.mutex_ref); + this.mutex_lock(&mutex.mutex_ref)?; 0 } } } } else { // The mutex is unlocked. Let's lock it. - this.mutex_lock(&mutex.mutex_ref); + this.mutex_lock(&mutex.mutex_ref)?; 0 })) } @@ -600,7 +600,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest.clone(), ); } else { - this.rwlock_reader_lock(&rwlock.rwlock_ref); + this.rwlock_reader_lock(&rwlock.rwlock_ref)?; this.write_null(dest)?; } @@ -615,7 +615,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if rwlock.rwlock_ref.is_write_locked() { interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) } else { - this.rwlock_reader_lock(&rwlock.rwlock_ref); + this.rwlock_reader_lock(&rwlock.rwlock_ref)?; interp_ok(Scalar::from_i32(0)) } } @@ -648,7 +648,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest.clone(), ); } else { - this.rwlock_writer_lock(&rwlock.rwlock_ref); + this.rwlock_writer_lock(&rwlock.rwlock_ref)?; this.write_null(dest)?; } @@ -663,7 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if rwlock.rwlock_ref.is_locked() { interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) } else { - this.rwlock_writer_lock(&rwlock.rwlock_ref); + this.rwlock_writer_lock(&rwlock.rwlock_ref)?; interp_ok(Scalar::from_i32(0)) } } diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 0585f3ba7471d..81703d6e176bf 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -259,7 +259,7 @@ fn anonsocket_write<'tcx>( // Remember this clock so `read` can synchronize with us. ecx.release_clock(|clock| { writebuf.clock.join(clock); - }); + })?; // Do full write / partial write based on the space available. let write_size = len.min(available_space); let actual_write_size = ecx.write_to_host(&mut writebuf.buf, write_size, ptr)?.unwrap(); From deca4895ca0412ea1a646310c0026d66b1230b9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Sep 2025 11:57:19 +0200 Subject: [PATCH 158/251] Prepare for merging from rust-lang/rust This updates the rust-version file to a09fbe2c8372643a27a8082236120f95ed4e6bba. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index a51d86c3d6f15..5b3139b25092b 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -b3cfb8faf84c5f3b7909479a9f9b6a3290d5f4d7 +a09fbe2c8372643a27a8082236120f95ed4e6bba From 24ce839fb953d1172a19479edcb2f75877cf153e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Sep 2025 12:00:36 +0200 Subject: [PATCH 159/251] clippy --- src/tools/miri/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 7d2f1c083687c..254495637da42 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -308,7 +308,7 @@ where Some(if return_nan { ecx.generate_nan(&[base]) } else { one }) } - _ => return None, + _ => None, } } From 94ab2b9f15b3c5ffe139d17fdae98cc2adff883d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 11:57:49 +0200 Subject: [PATCH 160/251] move math intrinsics to their own file --- src/tools/miri/src/intrinsics/math.rs | 311 ++++++++++++++++++++++++++ src/tools/miri/src/intrinsics/mod.rs | 291 +----------------------- 2 files changed, 315 insertions(+), 287 deletions(-) create mode 100644 src/tools/miri/src/intrinsics/math.rs diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs new file mode 100644 index 0000000000000..21d4a92e7d288 --- /dev/null +++ b/src/tools/miri/src/intrinsics/math.rs @@ -0,0 +1,311 @@ +use rand::Rng; +use rustc_apfloat::{self, Float, Round}; +use rustc_middle::mir; +use rustc_middle::ty::{self, FloatTy}; + +use self::helpers::{ToHost, ToSoft}; +use super::check_intrinsic_arg_count; +use crate::*; + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn emulate_math_intrinsic( + &mut self, + intrinsic_name: &str, + _generic_args: ty::GenericArgsRef<'tcx>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + + match intrinsic_name { + // Operations we can do with soft-floats. + "sqrtf32" => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + "sqrtf64" => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + + "fmaf32" => { + let [a, b, c] = check_intrinsic_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; + let c = this.read_scalar(c)?.to_f32()?; + let res = a.mul_add(b, c).value; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + "fmaf64" => { + let [a, b, c] = check_intrinsic_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; + let c = this.read_scalar(c)?.to_f64()?; + let res = a.mul_add(b, c).value; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + + "fmuladdf32" => { + let [a, b, c] = check_intrinsic_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; + let c = this.read_scalar(c)?.to_f32()?; + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); + let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + "fmuladdf64" => { + let [a, b, c] = check_intrinsic_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; + let c = this.read_scalar(c)?.to_f64()?; + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); + let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; + let res = this.adjust_nan(res, &[a, b, c]); + this.write_scalar(res, dest)?; + } + + #[rustfmt::skip] + | "fadd_fast" + | "fsub_fast" + | "fmul_fast" + | "fdiv_fast" + | "frem_fast" + => { + let [a, b] = check_intrinsic_arg_count(args)?; + let a = this.read_immediate(a)?; + let b = this.read_immediate(b)?; + let op = match intrinsic_name { + "fadd_fast" => mir::BinOp::Add, + "fsub_fast" => mir::BinOp::Sub, + "fmul_fast" => mir::BinOp::Mul, + "fdiv_fast" => mir::BinOp::Div, + "frem_fast" => mir::BinOp::Rem, + _ => bug!(), + }; + let float_finite = |x: &ImmTy<'tcx>| -> InterpResult<'tcx, bool> { + let ty::Float(fty) = x.layout.ty.kind() else { + bug!("float_finite: non-float input type {}", x.layout.ty) + }; + interp_ok(match fty { + FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(), + FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(), + FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(), + FloatTy::F128 => x.to_scalar().to_f128()?.is_finite(), + }) + }; + match (float_finite(&a)?, float_finite(&b)?) { + (false, false) => throw_ub_format!( + "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", + ), + (false, _) => throw_ub_format!( + "`{intrinsic_name}` intrinsic called with non-finite value as first parameter", + ), + (_, false) => throw_ub_format!( + "`{intrinsic_name}` intrinsic called with non-finite value as second parameter", + ), + _ => {} + } + let res = this.binary_op(op, &a, &b)?; + // This cannot be a NaN so we also don't have to apply any non-determinism. + // (Also, `binary_op` already called `generate_nan` if needed.) + if !float_finite(&res)? { + throw_ub_format!("`{intrinsic_name}` intrinsic produced non-finite value as result"); + } + // Apply a relative error of 4ULP to simulate non-deterministic precision loss + // due to optimizations. + let res = math::apply_random_float_error_to_imm(this, res, 4)?; + this.write_immediate(*res, dest)?; + } + + "float_to_int_unchecked" => { + let [val] = check_intrinsic_arg_count(args)?; + let val = this.read_immediate(val)?; + + let res = this + .float_to_int_checked(&val, dest.layout, Round::TowardZero)? + .ok_or_else(|| { + err_ub_format!( + "`float_to_int_unchecked` intrinsic called on {val} which cannot be represented in target type `{:?}`", + dest.layout.ty + ) + })?; + + this.write_immediate(*res, dest)?; + } + + // Operations that need host floats. + #[rustfmt::skip] + | "sinf32" + | "cosf32" + | "expf32" + | "exp2f32" + | "logf32" + | "log10f32" + | "log2f32" + => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + + let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let host = f.to_host(); + let res = match intrinsic_name { + "sinf32" => host.sin(), + "cosf32" => host.cos(), + "expf32" => host.exp(), + "exp2f32" => host.exp2(), + "logf32" => host.ln(), + "log10f32" => host.log10(), + "log2f32" => host.log2(), + _ => bug!(), + }; + let res = res.to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, + res, + 4, + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(intrinsic_name, res) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + + #[rustfmt::skip] + | "sinf64" + | "cosf64" + | "expf64" + | "exp2f64" + | "logf64" + | "log10f64" + | "log2f64" + => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + + let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let host = f.to_host(); + let res = match intrinsic_name { + "sinf64" => host.sin(), + "cosf64" => host.cos(), + "expf64" => host.exp(), + "exp2f64" => host.exp2(), + "logf64" => host.ln(), + "log10f64" => host.log10(), + "log2f64" => host.log2(), + _ => bug!(), + }; + let res = res.to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp( + this, + res, + 4, + ); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(intrinsic_name, res) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + + "powf32" => { + let [f1, f2] = check_intrinsic_arg_count(args)?; + let f1 = this.read_scalar(f1)?.to_f32()?; + let f2 = this.read_scalar(f2)?.to_f32()?; + + let res = + math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; + } + "powf64" => { + let [f1, f2] = check_intrinsic_arg_count(args)?; + let f1 = this.read_scalar(f1)?.to_f64()?; + let f2 = this.read_scalar(f2)?.to_f64()?; + + let res = + math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f1.to_host().powf(f2.to_host()).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; + } + + "powif32" => { + let [f, i] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + let i = this.read_scalar(i)?.to_i32()?; + + let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f.to_host().powi(i).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + "powif64" => { + let [f, i] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + let i = this.read_scalar(i)?.to_i32()?; + + let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { + // Using host floats (but it's fine, this operation does not have guaranteed precision). + let res = f.to_host().powi(i).to_soft(); + + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + math::apply_random_float_error_ulp(this, res, 4) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + + _ => return interp_ok(EmulateItemResult::NotSupported), + } + + interp_ok(EmulateItemResult::NeedsReturn) + } +} diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 8d323ec169df3..a80b939d84ea9 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -1,6 +1,7 @@ #![warn(clippy::arithmetic_side_effects)] mod atomic; +mod math; mod simd; pub use self::atomic::AtomicRmwOp; @@ -8,13 +9,11 @@ pub use self::atomic::AtomicRmwOp; #[rustfmt::skip] // prevent `use` reordering use rand::Rng; use rustc_abi::Size; -use rustc_apfloat::{self, Float, Round}; -use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy}; +use rustc_middle::{mir, ty}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; -use self::helpers::{ToHost, ToSoft}; +use self::math::EvalContextExt as _; use self::simd::EvalContextExt as _; use crate::*; @@ -179,288 +178,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } - "sqrtf32" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "sqrtf64" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - - #[rustfmt::skip] - | "sinf32" - | "cosf32" - | "expf32" - | "exp2f32" - | "logf32" - | "log10f32" - | "log2f32" - => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - - let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf32" => host.sin(), - "cosf32" => host.cos(), - "expf32" => host.exp(), - "exp2f32" => host.exp2(), - "logf32" => host.ln(), - "log10f32" => host.log10(), - "log2f32" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp( - this, - res, - 4, - ); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(intrinsic_name, res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - - #[rustfmt::skip] - | "sinf64" - | "cosf64" - | "expf64" - | "exp2f64" - | "logf64" - | "log10f64" - | "log2f64" - => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - - let res = math::fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let host = f.to_host(); - let res = match intrinsic_name { - "sinf64" => host.sin(), - "cosf64" => host.cos(), - "expf64" => host.exp(), - "exp2f64" => host.exp2(), - "logf64" => host.ln(), - "log10f64" => host.log10(), - "log2f64" => host.log2(), - _ => bug!(), - }; - let res = res.to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp( - this, - res, - 4, - ); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(intrinsic_name, res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - - "fmaf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmaf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - - "fmuladdf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmuladdf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - - "powf32" => { - let [f1, f2] = check_intrinsic_arg_count(args)?; - let f1 = this.read_scalar(f1)?.to_f32()?; - let f2 = this.read_scalar(f2)?.to_f32()?; - - let res = - math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - "powf64" => { - let [f1, f2] = check_intrinsic_arg_count(args)?; - let f1 = this.read_scalar(f1)?.to_f64()?; - let f2 = this.read_scalar(f2)?.to_f64()?; - - let res = - math::fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f1.to_host().powf(f2.to_host()).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - - "powif32" => { - let [f, i] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - let i = this.read_scalar(i)?.to_i32()?; - - let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "powif64" => { - let [f, i] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - let i = this.read_scalar(i)?.to_i32()?; - - let res = math::fixed_powi_value(this, f, i).unwrap_or_else(|| { - // Using host floats (but it's fine, this operation does not have guaranteed precision). - let res = f.to_host().powi(i).to_soft(); - - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - math::apply_random_float_error_ulp(this, res, 4) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - - #[rustfmt::skip] - | "fadd_fast" - | "fsub_fast" - | "fmul_fast" - | "fdiv_fast" - | "frem_fast" - => { - let [a, b] = check_intrinsic_arg_count(args)?; - let a = this.read_immediate(a)?; - let b = this.read_immediate(b)?; - let op = match intrinsic_name { - "fadd_fast" => mir::BinOp::Add, - "fsub_fast" => mir::BinOp::Sub, - "fmul_fast" => mir::BinOp::Mul, - "fdiv_fast" => mir::BinOp::Div, - "frem_fast" => mir::BinOp::Rem, - _ => bug!(), - }; - let float_finite = |x: &ImmTy<'tcx>| -> InterpResult<'tcx, bool> { - let ty::Float(fty) = x.layout.ty.kind() else { - bug!("float_finite: non-float input type {}", x.layout.ty) - }; - interp_ok(match fty { - FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(), - FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(), - FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(), - FloatTy::F128 => x.to_scalar().to_f128()?.is_finite(), - }) - }; - match (float_finite(&a)?, float_finite(&b)?) { - (false, false) => throw_ub_format!( - "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", - ), - (false, _) => throw_ub_format!( - "`{intrinsic_name}` intrinsic called with non-finite value as first parameter", - ), - (_, false) => throw_ub_format!( - "`{intrinsic_name}` intrinsic called with non-finite value as second parameter", - ), - _ => {} - } - let res = this.binary_op(op, &a, &b)?; - // This cannot be a NaN so we also don't have to apply any non-determinism. - // (Also, `binary_op` already called `generate_nan` if needed.) - if !float_finite(&res)? { - throw_ub_format!("`{intrinsic_name}` intrinsic produced non-finite value as result"); - } - // Apply a relative error of 4ULP to simulate non-deterministic precision loss - // due to optimizations. - let res = math::apply_random_float_error_to_imm(this, res, 4)?; - this.write_immediate(*res, dest)?; - } - - "float_to_int_unchecked" => { - let [val] = check_intrinsic_arg_count(args)?; - let val = this.read_immediate(val)?; - - let res = this - .float_to_int_checked(&val, dest.layout, Round::TowardZero)? - .ok_or_else(|| { - err_ub_format!( - "`float_to_int_unchecked` intrinsic called on {val} which cannot be represented in target type `{:?}`", - dest.layout.ty - ) - })?; - - this.write_immediate(*res, dest)?; - } - // Other "breakpoint" => { let [] = check_intrinsic_arg_count(args)?; @@ -472,7 +189,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Make these a NOP, so we get the better Miri-native error messages. } - _ => return interp_ok(EmulateItemResult::NotSupported), + _ => return this.emulate_math_intrinsic(intrinsic_name, generic_args, args, dest), } interp_ok(EmulateItemResult::NeedsReturn) From e00051299aa7a355307baeeac0bd593c71e8019e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 12:11:04 +0200 Subject: [PATCH 161/251] extract core operation name instead of listing all function name variants --- src/tools/miri/src/math.rs | 43 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 254495637da42..f89abbaba4805 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -210,61 +210,70 @@ where let pi_over_2 = (pi / two).value; let pi_over_4 = (pi_over_2 / two).value; - Some(match (intrinsic_name, args) { + // Remove `f32`/`f64` suffix, if any. + let name = intrinsic_name + .strip_suffix("f32") + .or_else(|| intrinsic_name.strip_suffix("f64")) + .unwrap_or(intrinsic_name); + // Also strip trailing `f` (indicates "float"), with an exception for "erf" to avoid + // removing that `f`. + let name = if name == "erf" { name } else { name.strip_suffix("f").unwrap_or(name) }; + Some(match (name, args) { // cos(±0) and cosh(±0)= 1 - ("cosf32" | "cosf64" | "coshf" | "cosh", [input]) if input.is_zero() => one, + ("cos" | "cosh", [input]) if input.is_zero() => one, // e^0 = 1 - ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one, + ("exp" | "exp2", [input]) if input.is_zero() => one, // tanh(±INF) = ±1 - ("tanhf" | "tanh", [input]) if input.is_infinite() => one.copy_sign(*input), + ("tanh", [input]) if input.is_infinite() => one.copy_sign(*input), // atan(±INF) = ±π/2 - ("atanf" | "atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input), + ("atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input), // erf(±INF) = ±1 - ("erff" | "erf", [input]) if input.is_infinite() => one.copy_sign(*input), + ("erf", [input]) if input.is_infinite() => one.copy_sign(*input), // erfc(-INF) = 2 - ("erfcf" | "erfc", [input]) if input.is_neg_infinity() => (one + one).value, + ("erfc", [input]) if input.is_neg_infinity() => (one + one).value, // hypot(x, ±0) = abs(x), if x is not a NaN. - ("_hypotf" | "hypotf" | "_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => + // `_hypot` is the Windows name for this. + ("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => x.abs(), // atan2(±0,−0) = ±π. // atan2(±0, y) = ±π for y < 0. // Must check for non NaN because `y.is_negative()` also applies to NaN. - ("atan2f" | "atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => + ("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => pi.copy_sign(*x), // atan2(±x,−∞) = ±π for finite x > 0. - ("atan2f" | "atan2", [x, y]) + ("atan2", [x, y]) if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() => pi.copy_sign(*x), // atan2(x, ±0) = −π/2 for x < 0. // atan2(x, ±0) = Ï€/2 for x > 0. - ("atan2f" | "atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x), + ("atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x), //atan2(±∞, −∞) = ±3Ï€/4 - ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() => + ("atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() => (pi_over_4 * three).value.copy_sign(*x), //atan2(±∞, +∞) = ±π/4 - ("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => + ("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => pi_over_4.copy_sign(*x), // atan2(±∞, y) returns ±π/2 for finite y. - ("atan2f" | "atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) => + ("atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) => pi_over_2.copy_sign(*x), // (-1)^(±INF) = 1 - ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one, + ("pow", [base, exp]) if *base == -one && exp.is_infinite() => one, // 1^y = 1 for any y, even a NaN - ("powf32" | "powf64", [base, exp]) if *base == one => { + ("pow", [base, exp]) if *base == one => { let rng = this.machine.rng.get_mut(); // SNaN exponents get special treatment: they might return 1, or a NaN. let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random(); @@ -273,7 +282,7 @@ where } // x^(±0) = 1 for any x, even a NaN - ("powf32" | "powf64", [base, exp]) if exp.is_zero() => { + ("pow", [base, exp]) if exp.is_zero() => { let rng = this.machine.rng.get_mut(); // SNaN bases get special treatment: they might return 1, or a NaN. let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random(); From 84e1950065525589f2d22860aa64c36f171fc782 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Jul 2025 12:20:43 +0200 Subject: [PATCH 162/251] move math foreign_items into their own file --- src/tools/miri/src/math.rs | 12 +- src/tools/miri/src/shims/foreign_items.rs | 238 ++------------------- src/tools/miri/src/shims/math.rs | 247 ++++++++++++++++++++++ src/tools/miri/src/shims/mod.rs | 1 + 4 files changed, 266 insertions(+), 232 deletions(-) create mode 100644 src/tools/miri/src/shims/math.rs diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index f89abbaba4805..401e6dd7aab84 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -239,18 +239,15 @@ where // hypot(x, ±0) = abs(x), if x is not a NaN. // `_hypot` is the Windows name for this. - ("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => - x.abs(), + ("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => x.abs(), // atan2(±0,−0) = ±π. // atan2(±0, y) = ±π for y < 0. // Must check for non NaN because `y.is_negative()` also applies to NaN. - ("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => - pi.copy_sign(*x), + ("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => pi.copy_sign(*x), // atan2(±x,−∞) = ±π for finite x > 0. - ("atan2", [x, y]) - if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() => + ("atan2", [x, y]) if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() => pi.copy_sign(*x), // atan2(x, ±0) = −π/2 for x < 0. @@ -262,8 +259,7 @@ where (pi_over_4 * three).value.copy_sign(*x), //atan2(±∞, +∞) = ±π/4 - ("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => - pi_over_4.copy_sign(*x), + ("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => pi_over_4.copy_sign(*x), // atan2(±∞, y) returns ±π/2 for finite y. ("atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) => diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 10e28178177b2..eca8cccf5efc4 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -3,7 +3,6 @@ use std::io::Write; use std::path::Path; use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size}; -use rustc_apfloat::Float; use rustc_ast::expand::allocator::alloc_error_handler_name; use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; @@ -15,7 +14,6 @@ use rustc_middle::{mir, ty}; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; use crate::helpers::EvalContextExt as _; @@ -818,225 +816,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr_dest, dest)?; } - // math functions (note that there are also intrinsics for some other functions) - #[rustfmt::skip] - | "cbrtf" - | "coshf" - | "sinhf" - | "tanf" - | "tanhf" - | "acosf" - | "asinf" - | "atanf" - | "log1pf" - | "expm1f" - | "tgammaf" - | "erff" - | "erfcf" - => { - let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; - let f = this.read_scalar(f)?.to_f32()?; - - let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let f_host = f.to_host(); - let res = match link_name.as_str() { - "cbrtf" => f_host.cbrt(), - "coshf" => f_host.cosh(), - "sinhf" => f_host.sinh(), - "tanf" => f_host.tan(), - "tanhf" => f_host.tanh(), - "acosf" => f_host.acos(), - "asinf" => f_host.asin(), - "atanf" => f_host.atan(), - "log1pf" => f_host.ln_1p(), - "expm1f" => f_host.exp_m1(), - "tgammaf" => f_host.gamma(), - "erff" => f_host.erf(), - "erfcf" => f_host.erfc(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(link_name.as_str(), res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] - | "_hypotf" - | "hypotf" - | "atan2f" - | "fdimf" - => { - let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; - let f1 = this.read_scalar(f1)?.to_f32()?; - let f2 = this.read_scalar(f2)?.to_f32()?; - - let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]) - .unwrap_or_else(|| { - let res = match link_name.as_str() { - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // Using host floats (but it's fine, these operations do not have guaranteed precision). - "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), - "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), - #[allow(deprecated)] - "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(), - _ => bug!(), - }; - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(link_name.as_str(), res) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] - | "cbrt" - | "cosh" - | "sinh" - | "tan" - | "tanh" - | "acos" - | "asin" - | "atan" - | "log1p" - | "expm1" - | "tgamma" - | "erf" - | "erfc" - => { - let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; - let f = this.read_scalar(f)?.to_f64()?; - - let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { - // Using host floats (but it's fine, these operations do not have - // guaranteed precision). - let f_host = f.to_host(); - let res = match link_name.as_str() { - "cbrt" => f_host.cbrt(), - "cosh" => f_host.cosh(), - "sinh" => f_host.sinh(), - "tan" => f_host.tan(), - "tanh" => f_host.tanh(), - "acos" => f_host.acos(), - "asin" => f_host.asin(), - "atan" => f_host.atan(), - "log1p" => f_host.ln_1p(), - "expm1" => f_host.exp_m1(), - "tgamma" => f_host.gamma(), - "erf" => f_host.erf(), - "erfc" => f_host.erfc(), - _ => bug!(), - }; - let res = res.to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(link_name.as_str(), res) - }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] - | "_hypot" - | "hypot" - | "atan2" - | "fdim" - => { - let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; - let f1 = this.read_scalar(f1)?.to_f64()?; - let f2 = this.read_scalar(f2)?.to_f64()?; - - let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { - let res = match link_name.as_str() { - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - // Using host floats (but it's fine, these operations do not have guaranteed precision). - "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), - "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), - #[allow(deprecated)] - "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(), - _ => bug!(), - }; - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - math::clamp_float_value(link_name.as_str(), res) - }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] - | "_ldexp" - | "ldexp" - | "scalbn" - => { - let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; - // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - let x = this.read_scalar(x)?.to_f64()?; - let exp = this.read_scalar(exp)?.to_i32()?; - - let res = x.scalbn(exp); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; - } - "lgammaf_r" => { - let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let x = this.read_scalar(x)?.to_f32()?; - let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; - - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let (res, sign) = x.to_host().ln_gamma(); - this.write_int(sign, &signp)?; - - let res = res.to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - let res = math::clamp_float_value(link_name.as_str(), res); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; - } - "lgamma_r" => { - let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let x = this.read_scalar(x)?.to_f64()?; - let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; - - // Using host floats (but it's fine, these operations do not have guaranteed precision). - let (res, sign) = x.to_host().ln_gamma(); - this.write_int(sign, &signp)?; - - let res = res.to_soft(); - // Apply a relative error of 4ULP to introduce some non-determinism - // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); - // Clamp the result to the guaranteed range of this function according to the C standard, - // if any. - let res = math::clamp_float_value(link_name.as_str(), res); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; - } - // LLVM intrinsics "llvm.prefetch" => { let [p, rw, loc, ty] = @@ -1118,8 +897,18 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - // Platform-specific shims - _ => + // Fallback to shims in submodules. + _ => { + // Math shims + #[expect(irrefutable_let_patterns)] + if let res = shims::math::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + )? && !matches!(res, EmulateItemResult::NotSupported) + { + return interp_ok(res); + } + + // Platform-specific shims return match this.tcx.sess.target.os.as_ref() { _ if this.target_os_is_unix() => shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner( @@ -1134,7 +923,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this, link_name, abi, args, dest, ), _ => interp_ok(EmulateItemResult::NotSupported), - }, + }; + } }; // We only fall through to here if we did *not* hit the `_` arm above, // i.e., if we actually emulated the function with one of the shims. diff --git a/src/tools/miri/src/shims/math.rs b/src/tools/miri/src/shims/math.rs new file mode 100644 index 0000000000000..576e76494bcb7 --- /dev/null +++ b/src/tools/miri/src/shims/math.rs @@ -0,0 +1,247 @@ +use rustc_abi::CanonAbi; +use rustc_apfloat::Float; +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::callconv::FnAbi; + +use self::helpers::{ToHost, ToSoft}; +use crate::*; + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn emulate_foreign_item_inner( + &mut self, + link_name: Symbol, + abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + + // math functions (note that there are also intrinsics for some other functions) + match link_name.as_str() { + // math functions (note that there are also intrinsics for some other functions) + #[rustfmt::skip] + | "cbrtf" + | "coshf" + | "sinhf" + | "tanf" + | "tanhf" + | "acosf" + | "asinf" + | "atanf" + | "log1pf" + | "expm1f" + | "tgammaf" + | "erff" + | "erfcf" + => { + let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let f = this.read_scalar(f)?.to_f32()?; + + let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let f_host = f.to_host(); + let res = match link_name.as_str() { + "cbrtf" => f_host.cbrt(), + "coshf" => f_host.cosh(), + "sinhf" => f_host.sinh(), + "tanf" => f_host.tan(), + "tanhf" => f_host.tanh(), + "acosf" => f_host.acos(), + "asinf" => f_host.asin(), + "atanf" => f_host.atan(), + "log1pf" => f_host.ln_1p(), + "expm1f" => f_host.exp_m1(), + "tgammaf" => f_host.gamma(), + "erff" => f_host.erf(), + "erfcf" => f_host.erfc(), + _ => bug!(), + }; + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + #[rustfmt::skip] + | "_hypotf" + | "hypotf" + | "atan2f" + | "fdimf" + => { + let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let f1 = this.read_scalar(f1)?.to_f32()?; + let f2 = this.read_scalar(f2)?.to_f32()?; + + let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]) + .unwrap_or_else(|| { + let res = match link_name.as_str() { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) + // Using host floats (but it's fine, these operations do not have guaranteed precision). + "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), + #[allow(deprecated)] + "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(), + _ => bug!(), + }; + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; + } + #[rustfmt::skip] + | "cbrt" + | "cosh" + | "sinh" + | "tan" + | "tanh" + | "acos" + | "asin" + | "atan" + | "log1p" + | "expm1" + | "tgamma" + | "erf" + | "erfc" + => { + let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let f = this.read_scalar(f)?.to_f64()?; + + let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + // Using host floats (but it's fine, these operations do not have + // guaranteed precision). + let f_host = f.to_host(); + let res = match link_name.as_str() { + "cbrt" => f_host.cbrt(), + "cosh" => f_host.cosh(), + "sinh" => f_host.sinh(), + "tan" => f_host.tan(), + "tanh" => f_host.tanh(), + "acos" => f_host.acos(), + "asin" => f_host.asin(), + "atan" => f_host.atan(), + "log1p" => f_host.ln_1p(), + "expm1" => f_host.exp_m1(), + "tgamma" => f_host.gamma(), + "erf" => f_host.erf(), + "erfc" => f_host.erfc(), + _ => bug!(), + }; + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } + #[rustfmt::skip] + | "_hypot" + | "hypot" + | "atan2" + | "fdim" + => { + let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let f1 = this.read_scalar(f1)?.to_f64()?; + let f2 = this.read_scalar(f2)?.to_f64()?; + + let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { + let res = match link_name.as_str() { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) + // Using host floats (but it's fine, these operations do not have guaranteed precision). + "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), + #[allow(deprecated)] + "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(), + _ => bug!(), + }; + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + math::clamp_float_value(link_name.as_str(), res) + }); + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; + } + #[rustfmt::skip] + | "_ldexp" + | "ldexp" + | "scalbn" + => { + let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. + let x = this.read_scalar(x)?.to_f64()?; + let exp = this.read_scalar(exp)?.to_i32()?; + + let res = x.scalbn(exp); + let res = this.adjust_nan(res, &[x]); + this.write_scalar(res, dest)?; + } + "lgammaf_r" => { + let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let x = this.read_scalar(x)?.to_f32()?; + let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; + + // Using host floats (but it's fine, these operations do not have guaranteed precision). + let (res, sign) = x.to_host().ln_gamma(); + this.write_int(sign, &signp)?; + + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + let res = math::clamp_float_value(link_name.as_str(), res); + let res = this.adjust_nan(res, &[x]); + this.write_scalar(res, dest)?; + } + "lgamma_r" => { + let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let x = this.read_scalar(x)?.to_f64()?; + let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; + + // Using host floats (but it's fine, these operations do not have guaranteed precision). + let (res, sign) = x.to_host().ln_gamma(); + this.write_int(sign, &signp)?; + + let res = res.to_soft(); + // Apply a relative error of 4ULP to introduce some non-determinism + // simulating imprecise implementations and optimizations. + let res = math::apply_random_float_error_ulp(this, res, 4); + // Clamp the result to the guaranteed range of this function according to the C standard, + // if any. + let res = math::clamp_float_value(link_name.as_str(), res); + let res = this.adjust_nan(res, &[x]); + this.write_scalar(res, dest)?; + } + + _ => return interp_ok(EmulateItemResult::NotSupported), + } + + interp_ok(EmulateItemResult::NeedsReturn) + } +} diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 7f594d4fdd6bc..7f7bc3b1cf720 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -4,6 +4,7 @@ mod aarch64; mod alloc; mod backtrace; mod files; +mod math; #[cfg(all(unix, feature = "native-lib"))] mod native_lib; mod unix; From a21866a563836da1c47c1088f0e6085514c9595a Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Mon, 8 Sep 2025 15:56:56 +0100 Subject: [PATCH 163/251] Remove support for register_attr This was removed in rustc in 2022: https://github.com/rust-lang/rust/pull/101123 Closes #20525. --- .../crates/hir-def/src/nameres.rs | 9 ----- .../hir-def/src/nameres/attr_resolution.rs | 9 +---- .../crates/hir-def/src/nameres/collector.rs | 6 --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 38 ++++--------------- .../crates/hir/src/source_analyzer.rs | 3 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 6 +-- .../src/handlers/macro_error.rs | 5 +-- 7 files changed, 14 insertions(+), 62 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index bf6fc15b7d199..7d5e627964eb1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -192,8 +192,6 @@ struct DefMapCrateData { exported_derives: FxHashMap>, fn_proc_macro_mapping: FxHashMap, - /// Custom attributes registered with `#![register_attr]`. - registered_attrs: Vec, /// Custom tool modules registered with `#![register_tool]`. registered_tools: Vec, /// Unstable features of Rust enabled with `#![feature(A, B)]`. @@ -212,7 +210,6 @@ impl DefMapCrateData { Self { exported_derives: FxHashMap::default(), fn_proc_macro_mapping: FxHashMap::default(), - registered_attrs: Vec::new(), registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(), unstable_features: FxHashSet::default(), rustc_coherence_is_core: false, @@ -227,7 +224,6 @@ impl DefMapCrateData { let Self { exported_derives, fn_proc_macro_mapping, - registered_attrs, registered_tools, unstable_features, rustc_coherence_is_core: _, @@ -238,7 +234,6 @@ impl DefMapCrateData { } = self; exported_derives.shrink_to_fit(); fn_proc_macro_mapping.shrink_to_fit(); - registered_attrs.shrink_to_fit(); registered_tools.shrink_to_fit(); unstable_features.shrink_to_fit(); } @@ -529,10 +524,6 @@ impl DefMap { &self.data.registered_tools } - pub fn registered_attrs(&self) -> &[Symbol] { - &self.data.registered_attrs - } - pub fn is_unstable_feature_enabled(&self, feature: &Symbol) -> bool { self.data.unstable_features.contains(feature) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs index e7e96804ae737..2f56d608fcbf4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs @@ -90,13 +90,8 @@ impl DefMap { return true; } - if segments.len() == 1 { - if find_builtin_attr_idx(name).is_some() { - return true; - } - if self.data.registered_attrs.iter().any(pred) { - return true; - } + if segments.len() == 1 && find_builtin_attr_idx(name).is_some() { + return true; } } false diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 0f84728dcb4a8..a2ce538356515 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -298,12 +298,6 @@ impl<'db> DefCollector<'db> { ); crate_data.unstable_features.extend(features); } - () if *attr_name == sym::register_attr => { - if let Some(ident) = attr.single_ident_value() { - crate_data.registered_attrs.push(ident.sym.clone()); - cov_mark::hit!(register_attr); - } - } () if *attr_name == sym::register_tool => { if let Some(ident) = attr.single_ident_value() { crate_data.registered_tools.push(ident.sym.clone()); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 6610375451dd0..6eb8a8bf60fd1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4060,49 +4060,25 @@ impl DeriveHelper { } } -// FIXME: Wrong name? This is could also be a registered attribute #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BuiltinAttr { - krate: Option, idx: u32, } impl BuiltinAttr { - // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs? - pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option { - if let builtin @ Some(_) = Self::builtin(name) { - return builtin; - } - let idx = crate_def_map(db, krate.id) - .registered_attrs() - .iter() - .position(|it| it.as_str() == name)? as u32; - Some(BuiltinAttr { krate: Some(krate.id), idx }) - } - fn builtin(name: &str) -> Option { hir_expand::inert_attr_macro::find_builtin_attr_idx(&Symbol::intern(name)) - .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) + .map(|idx| BuiltinAttr { idx: idx as u32 }) } - pub fn name(&self, db: &dyn HirDatabase) -> Name { - match self.krate { - Some(krate) => Name::new_symbol_root( - crate_def_map(db, krate).registered_attrs()[self.idx as usize].clone(), - ), - None => Name::new_symbol_root(Symbol::intern( - hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name, - )), - } + pub fn name(&self) -> Name { + Name::new_symbol_root(Symbol::intern( + hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name, + )) } - pub fn template(&self, _: &dyn HirDatabase) -> Option { - match self.krate { - Some(_) => None, - None => { - Some(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].template) - } - } + pub fn template(&self) -> Option { + Some(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].template) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index dbc2539a9b91c..539b25387aef0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1062,8 +1062,7 @@ impl<'db> SourceAnalyzer<'db> { // in this case we have to check for inert/builtin attributes and tools and prioritize // resolution of attributes over other namespaces if let Some(name_ref) = path.as_single_name_ref() { - let builtin = - BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text()); + let builtin = BuiltinAttr::builtin(&name_ref.text()); if builtin.is_some() { return builtin.map(|it| (PathResolution::BuiltinAttr(it), None)); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 61a21ccf2f775..44ff9d6006d66 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -259,8 +259,8 @@ impl Definition { Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db), Definition::BuiltinAttr(it) => { - let name = it.name(db); - let AttributeTemplate { word, list, name_value_str } = it.template(db)?; + let name = it.name(); + let AttributeTemplate { word, list, name_value_str } = it.template()?; let mut docs = "Valid forms are:".to_owned(); if word { format_to!(docs, "\n - #\\[{}]", name.display(db, display_target.edition)); @@ -348,7 +348,7 @@ impl Definition { Definition::Label(it) => it.name(db).display(db, display_target.edition).to_string(), Definition::ExternCrateDecl(it) => it.display(db, display_target).to_string(), Definition::BuiltinAttr(it) => { - format!("#[{}]", it.name(db).display(db, display_target.edition)) + format!("#[{}]", it.name().display(db, display_target.edition)) } Definition::ToolModule(it) => { it.name(db).display(db, display_target.edition).to_string() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index c39e00e178f81..6a1ecae651501 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -144,16 +144,13 @@ macro_rules! concat { () => {} } } #[test] - fn register_attr_and_tool() { - cov_mark::check!(register_attr); + fn register_tool() { cov_mark::check!(register_tool); check_diagnostics( r#" #![register_tool(tool)] -#![register_attr(attr)] #[tool::path] -#[attr] struct S; "#, ); From bb5b153b7bccab4347d1a4deead6dcc9ca400a34 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Mon, 8 Sep 2025 11:12:57 -0400 Subject: [PATCH 164/251] feat: support navigation on primitives --- .../rust-analyzer/crates/ide-db/src/defs.rs | 2 +- .../crates/ide/src/goto_definition.rs | 27 +++++++++++++++++-- .../crates/ide/src/hover/render.rs | 15 +---------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 61a21ccf2f775..43d4611b18ac1 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -363,7 +363,7 @@ impl Definition { } } -fn find_std_module( +pub fn find_std_module( famous_defs: &FamousDefs<'_, '_>, name: &str, edition: Edition, diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index f768d4b68f469..002f5b3fe8f44 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -6,12 +6,13 @@ use crate::{ navigation_target::{self, ToNav}, }; use hir::{ - AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym, + AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, PathResolution, + Semantics, sym, }; use ide_db::{ RootDatabase, SymbolKind, base_db::{AnchoredPath, SourceDatabase}, - defs::{Definition, IdentClass}, + defs::{Definition, IdentClass, find_std_module}, famous_defs::FamousDefs, helpers::pick_best_token, }; @@ -90,6 +91,9 @@ pub(crate) fn goto_definition( if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) { return Some(navs); } + if let Some(navs) = find_definition_for_builtin_types(sema, &token.value, edition) { + return Some(navs); + } let parent = token.value.parent()?; @@ -204,6 +208,25 @@ fn find_definition_for_known_blanket_dual_impls( Some(def_to_nav(sema.db, def)) } +// If the token is a builtin type search the definition from the rustdoc module shims. +fn find_definition_for_builtin_types( + sema: &Semantics<'_, RootDatabase>, + original_token: &SyntaxToken, + edition: Edition, +) -> Option> { + let path = original_token.parent_ancestors().find_map(ast::Path::cast)?; + let res = sema.resolve_path(&path)?; + let PathResolution::Def(ModuleDef::BuiltinType(builtin)) = res else { + return None; + }; + + let fd = FamousDefs(sema, sema.scope(path.syntax())?.krate()); + let primitive_mod = format!("prim_{}", builtin.name().display(fd.0.db, edition)); + let doc_owner = find_std_module(&fd, &primitive_mod, edition)?; + + Some(def_to_nav(sema.db, doc_owner.into())) +} + fn try_lookup_include_path( sema: &Semantics<'_, RootDatabase>, token: InFile, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 290ee80984edc..2adafbb7af6f7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -10,7 +10,7 @@ use hir::{ }; use ide_db::{ RootDatabase, - defs::Definition, + defs::{Definition, find_std_module}, documentation::{DocsRangeMap, HasDocs}, famous_defs::FamousDefs, generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, @@ -1160,19 +1160,6 @@ fn markup( } } -fn find_std_module( - famous_defs: &FamousDefs<'_, '_>, - name: &str, - edition: Edition, -) -> Option { - let db = famous_defs.0.db; - let std_crate = famous_defs.std()?; - let std_root_module = std_crate.root_module(); - std_root_module.children(db).find(|module| { - module.name(db).is_some_and(|module| module.display(db, edition).to_string() == name) - }) -} - fn render_memory_layout( config: Option, layout: impl FnOnce() -> Result, From 224428d8fd5f4d2ad28b833d6e4502d4d7952f9b Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Mon, 8 Sep 2025 16:45:58 +0100 Subject: [PATCH 165/251] Clarify intro in README and manual The first sentence a new user should see should ideally answer the questions: * What is rust-analyzer? * Why might I want to use it? The vast majority of users will be interested in using rust-analyzer inside their favourite editor. We should clarify that rust-analyzer is an LSP implementation and that it supports all the classic IDE features. Whilst it's also true that rust-analyzer is modular and organised into libraries, the first impression should (I think) focus on an overview and the primary use case. --- src/tools/rust-analyzer/README.md | 17 +++++++++++++-- .../rust-analyzer/docs/book/src/README.md | 21 ++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md index 4360dea4a113c..cb3a41eec5a62 100644 --- a/src/tools/rust-analyzer/README.md +++ b/src/tools/rust-analyzer/README.md @@ -4,8 +4,21 @@ alt="rust-analyzer logo">

-rust-analyzer is a modular compiler frontend for the Rust language. -It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust. +rust-analyzer is a language server that provides IDE functionality for +writing Rust programs. You can use it with any editor that supports +the [Language Server +Protocol](https://microsoft.github.io/language-server-protocol/) (VS +Code, Vim, Emacs, Zed, etc). + +rust-analyzer features include go-to-definition, find-all-references, +refactorings and code completion. rust-analyzer also supports +integrated formatting (with rustfmt) and integrated diagnostics (with +rustc and clippy). + +Internally, rust-analyzer is structured as a set of libraries for +analyzing Rust code. See +[Architecture](https://rust-analyzer.github.io/book/contributing/architecture.html) +in the manual. ## Quick Start diff --git a/src/tools/rust-analyzer/docs/book/src/README.md b/src/tools/rust-analyzer/docs/book/src/README.md index 71f34e0346646..060bcf0cea399 100644 --- a/src/tools/rust-analyzer/docs/book/src/README.md +++ b/src/tools/rust-analyzer/docs/book/src/README.md @@ -1,13 +1,20 @@ # rust-analyzer -At its core, rust-analyzer is a **library** for semantic analysis of -Rust code as it changes over time. This manual focuses on a specific -usage of the library -- running it as part of a server that implements +rust-analyzer is a language server that provides IDE functionality for +writing Rust programs. You can use it with any editor that supports the [Language Server -Protocol](https://microsoft.github.io/language-server-protocol/) (LSP). -The LSP allows various code editors, like VS Code, Emacs or Vim, to -implement semantic features like completion or goto definition by -talking to an external language server process. +Protocol](https://microsoft.github.io/language-server-protocol/) (VS +Code, Vim, Emacs, Zed, etc). + +rust-analyzer features include go-to-definition, find-all-references, +refactorings and code completion. rust-analyzer also supports +integrated formatting (with rustfmt) and integrated diagnostics (with +rustc and clippy). + +Internally, rust-analyzer is structured as a set of libraries for +analyzing Rust code. See +[Architecture](https://rust-analyzer.github.io/book/contributing/architecture.html) +for more details. To improve this document, send a pull request: [https://github.com/rust-lang/rust-analyzer](https://github.com/rust-lang/rust-analyzer/blob/master/docs/book/README.md) From a6a53ace86ad7ff23b6d84379391099862f3bd1a Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Mon, 8 Sep 2025 14:10:25 -0400 Subject: [PATCH 166/251] impl TryToNav for BuiltinType instead --- .../crates/ide-db/src/famous_defs.rs | 4 +++ .../crates/ide/src/goto_definition.rs | 27 ++-------------- .../crates/ide/src/navigation_target.rs | 31 ++++++++++++++++--- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index 8e687385086fc..8eea2b81bab6d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -210,6 +210,10 @@ impl FamousDefs<'_, '_> { fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option { let krate = self.1; let db = self.0.db; + if krate.origin(db) == CrateOrigin::Lang(origin) { + return Some(krate); + } + let res = krate .dependencies(db) .into_iter() diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 002f5b3fe8f44..f768d4b68f469 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -6,13 +6,12 @@ use crate::{ navigation_target::{self, ToNav}, }; use hir::{ - AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, PathResolution, - Semantics, sym, + AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym, }; use ide_db::{ RootDatabase, SymbolKind, base_db::{AnchoredPath, SourceDatabase}, - defs::{Definition, IdentClass, find_std_module}, + defs::{Definition, IdentClass}, famous_defs::FamousDefs, helpers::pick_best_token, }; @@ -91,9 +90,6 @@ pub(crate) fn goto_definition( if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) { return Some(navs); } - if let Some(navs) = find_definition_for_builtin_types(sema, &token.value, edition) { - return Some(navs); - } let parent = token.value.parent()?; @@ -208,25 +204,6 @@ fn find_definition_for_known_blanket_dual_impls( Some(def_to_nav(sema.db, def)) } -// If the token is a builtin type search the definition from the rustdoc module shims. -fn find_definition_for_builtin_types( - sema: &Semantics<'_, RootDatabase>, - original_token: &SyntaxToken, - edition: Edition, -) -> Option> { - let path = original_token.parent_ancestors().find_map(ast::Path::cast)?; - let res = sema.resolve_path(&path)?; - let PathResolution::Def(ModuleDef::BuiltinType(builtin)) = res else { - return None; - }; - - let fd = FamousDefs(sema, sema.scope(path.syntax())?.krate()); - let primitive_mod = format!("prim_{}", builtin.name().display(fd.0.db, edition)); - let doc_owner = find_std_module(&fd, &primitive_mod, edition)?; - - Some(def_to_nav(sema.db, doc_owner.into())) -} - fn try_lookup_include_path( sema: &Semantics<'_, RootDatabase>, token: InFile, diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 1b6a4b726e831..641bde5e2b82a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -5,14 +5,15 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use hir::{ - AssocItem, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId, InFile, - LocalSource, ModuleSource, db::ExpandDatabase, symbols::FileSymbol, + AssocItem, Crate, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId, + InFile, LocalSource, ModuleSource, Semantics, db::ExpandDatabase, symbols::FileSymbol, }; use ide_db::{ FileId, FileRange, RootDatabase, SymbolKind, - base_db::salsa, - defs::Definition, + base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb, salsa}, + defs::{Definition, find_std_module}, documentation::{Documentation, HasDocs}, + famous_defs::FamousDefs, }; use span::Edition; use stdx::never; @@ -262,8 +263,8 @@ impl TryToNav for Definition { Definition::TypeAlias(it) => it.try_to_nav(db), Definition::ExternCrateDecl(it) => it.try_to_nav(db), Definition::InlineAsmOperand(it) => it.try_to_nav(db), + Definition::BuiltinType(it) => it.try_to_nav(db), Definition::BuiltinLifetime(_) - | Definition::BuiltinType(_) | Definition::TupleField(_) | Definition::ToolModule(_) | Definition::InlineAsmRegOrRegClass(_) @@ -746,6 +747,26 @@ impl TryToNav for hir::InlineAsmOperand { } } +impl TryToNav for hir::BuiltinType { + fn try_to_nav(&self, db: &RootDatabase) -> Option> { + let sema = Semantics::new(db); + + let krate = db + .all_crates() + .iter() + .copied() + .find(|&krate| matches!(krate.data(db).origin, CrateOrigin::Lang(LangCrateOrigin::Std))) + .map(Crate::from)?; + let edition = krate.edition(db); + + let fd = FamousDefs(&sema, krate); + let primitive_mod = format!("prim_{}", self.name().display(fd.0.db, edition)); + let doc_owner = find_std_module(&fd, &primitive_mod, edition)?; + + Some(doc_owner.to_nav(db)) + } +} + #[derive(Debug)] pub struct UpmappingResult { /// The macro call site. From fc4450b1f1dedd1328bc9dabad55afc3fda872b7 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Mon, 8 Sep 2025 14:33:25 -0400 Subject: [PATCH 167/251] add test --- .../crates/ide/src/goto_definition.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index f768d4b68f469..d50d7f602fcb8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -3944,6 +3944,20 @@ fn main() { _ => {} } } +"#, + ); + } + + #[test] + fn goto_builtin_type() { + check( + r#" +//- /main.rs crate:main deps:std +const _: &str$0 = ""; } + +//- /libstd.rs crate:std +mod prim_str {} +// ^^^^^^^^ "#, ); } From 2ffa8510a7f29af51b976d98584d7330eadbeee7 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Mon, 8 Sep 2025 15:59:46 -0400 Subject: [PATCH 168/251] make TryToNav take Semantics instead of RootDatabase --- .../crates/ide/src/call_hierarchy.rs | 10 +- .../crates/ide/src/doc_links/tests.rs | 2 +- .../crates/ide/src/goto_declaration.rs | 10 +- .../crates/ide/src/goto_definition.rs | 20 +- .../crates/ide/src/goto_implementation.rs | 6 +- .../crates/ide/src/goto_type_definition.rs | 2 +- .../crates/ide/src/highlight_related.rs | 2 +- .../rust-analyzer/crates/ide/src/hover.rs | 34 +-- .../crates/ide/src/hover/render.rs | 12 +- .../crates/ide/src/inlay_hints.rs | 6 +- .../crates/ide/src/inlay_hints/bounds.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 2 +- .../crates/ide/src/navigation_target.rs | 196 ++++++++++++------ .../crates/ide/src/references.rs | 2 +- .../rust-analyzer/crates/ide/src/runnables.rs | 15 +- .../crates/ide/src/static_index.rs | 4 +- .../crates/ide/src/test_explorer.rs | 2 +- 17 files changed, 203 insertions(+), 124 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index 7a0405939d10c..f42cead3501d1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -67,7 +67,7 @@ pub(crate) fn incoming_calls( let def = ast::Fn::cast(node).and_then(|fn_| sema.to_def(&fn_))?; // We should return def before check if it is a test, so that we // will not continue to search for outer fn in nested fns - def.try_to_nav(sema.db).map(|nav| (def, nav)) + def.try_to_nav(sema).map(|nav| (def, nav)) }); if let Some((def, nav)) = def_nav { @@ -122,10 +122,10 @@ pub(crate) fn outgoing_calls( if exclude_tests && it.is_test(db) { return None; } - it.try_to_nav(db) + it.try_to_nav(&sema) } - hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(db), - hir::CallableKind::TupleStruct(it) => it.try_to_nav(db), + hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(&sema), + hir::CallableKind::TupleStruct(it) => it.try_to_nav(&sema), _ => None, } .zip(Some(sema.original_range(expr.syntax()))) @@ -136,7 +136,7 @@ pub(crate) fn outgoing_calls( return None; } function - .try_to_nav(db) + .try_to_nav(&sema) .zip(Some(sema.original_range(expr.name_ref()?.syntax()))) } }?; diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index b004c07576748..11518d1fbf306 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -68,7 +68,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr) .unwrap_or_else(|| panic!("Failed to resolve {link}")) }); - def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link)) + def.try_to_nav(sema).unwrap().into_iter().zip(iter::repeat(link)) }) .map(|(nav_target, link)| { let range = diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs index 267e8ff7128be..686dbe2412933 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs @@ -38,14 +38,14 @@ pub(crate) fn goto_declaration( ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? { NameRefClass::Definition(it, _) => Some(it), NameRefClass::FieldShorthand { field_ref, .. } => - return field_ref.try_to_nav(db), + return field_ref.try_to_nav(&sema), NameRefClass::ExternCrateShorthand { decl, .. } => - return decl.try_to_nav(db), + return decl.try_to_nav(&sema), }, ast::Name(name) => match NameClass::classify(&sema, &name)? { NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), NameClass::PatFieldShorthand { field_ref, .. } => - return field_ref.try_to_nav(db), + return field_ref.try_to_nav(&sema), }, _ => None } @@ -57,14 +57,14 @@ pub(crate) fn goto_declaration( Definition::Const(c) => c.as_assoc_item(db), Definition::TypeAlias(ta) => ta.as_assoc_item(db), Definition::Function(f) => f.as_assoc_item(db), - Definition::ExternCrateDecl(it) => return it.try_to_nav(db), + Definition::ExternCrateDecl(it) => return it.try_to_nav(&sema), _ => None, }?; let trait_ = assoc.implemented_trait(db)?; let name = Some(assoc.name(db)?); let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; - item.try_to_nav(db) + item.try_to_nav(&sema) }) .flatten() .collect(); diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index d50d7f602fcb8..2dcb13d9e7aa1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -62,7 +62,7 @@ pub(crate) fn goto_definition( })?; if let Some(doc_comment) = token_as_doc_comment(&original_token) { return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| { - let nav = def.try_to_nav(db)?; + let nav = def.try_to_nav(sema)?; Some(RangeInfo::new(link_range, nav.collect())) }); } @@ -73,7 +73,7 @@ pub(crate) fn goto_definition( return Some(RangeInfo::new( range, match resolution { - Some(res) => def_to_nav(db, Definition::from(res)), + Some(res) => def_to_nav(sema, Definition::from(res)), None => vec![], }, )); @@ -121,7 +121,7 @@ pub(crate) fn goto_definition( .collect(); } try_filter_trait_item_definition(sema, &def) - .unwrap_or_else(|| def_to_nav(sema.db, def)) + .unwrap_or_else(|| def_to_nav(sema, def)) }) .collect(), ) @@ -160,7 +160,7 @@ fn find_definition_for_known_blanket_dual_impls( t_f, [return_type.type_arguments().next()?], ) - .map(|f| def_to_nav(sema.db, f.into())); + .map(|f| def_to_nav(sema, f.into())); } hir::AssocItemContainer::Impl(_) => return None, }; @@ -201,7 +201,7 @@ fn find_definition_for_known_blanket_dual_impls( // succeed let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?; let def = Definition::from(f); - Some(def_to_nav(sema.db, def)) + Some(def_to_nav(sema, def)) } fn try_lookup_include_path( @@ -246,7 +246,7 @@ fn try_lookup_macro_def_in_macro_use( for mod_def in krate.root_module().declarations(sema.db) { if let ModuleDef::Macro(mac) = mod_def && mac.name(sema.db).as_str() == token.text() - && let Some(nav) = mac.try_to_nav(sema.db) + && let Some(nav) = mac.try_to_nav(sema) { return Some(nav.call_site); } @@ -278,7 +278,7 @@ fn try_filter_trait_item_definition( .items(db) .iter() .filter(|itm| discriminant(*itm) == discriminant_value) - .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) + .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten()) .map(|it| it.collect()) } } @@ -347,7 +347,7 @@ fn nav_for_exit_points( match_ast! { match node { ast::Fn(fn_) => { - let mut nav = sema.to_def(&fn_)?.try_to_nav(db)?; + let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?; // For async token, we navigate to itself, which triggers // VSCode to find the references let focus_token = if matches!(token_kind, T![async]) { @@ -564,8 +564,8 @@ fn nav_for_break_points( Some(navs) } -fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec { - def.try_to_nav(db).map(|it| it.collect()).unwrap_or_default() +fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec { + def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default() } fn expr_to_nav( diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 4f172621908c5..875403c4e32a4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -86,7 +86,7 @@ pub(crate) fn goto_implementation( fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type<'_>) -> Vec { Impl::all_for_type(sema.db, ty) .into_iter() - .filter_map(|imp| imp.try_to_nav(sema.db)) + .filter_map(|imp| imp.try_to_nav(sema)) .flatten() .collect() } @@ -97,7 +97,7 @@ fn impls_for_trait( ) -> Vec { Impl::all_for_trait(sema.db, trait_) .into_iter() - .filter_map(|imp| imp.try_to_nav(sema.db)) + .filter_map(|imp| imp.try_to_nav(sema)) .flatten() .collect() } @@ -114,7 +114,7 @@ fn impls_for_trait_item( let itm_name = itm.name(sema.db)?; (itm_name == fun_name).then_some(*itm) })?; - item.try_to_nav(sema.db) + item.try_to_nav(sema) }) .flatten() .collect() diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index b80e81d39c6df..ffd144a827e34 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -30,7 +30,7 @@ pub(crate) fn goto_type_definition( let mut res = Vec::new(); let mut push = |def: Definition| { - if let Some(navs) = def.try_to_nav(db) { + if let Some(navs) = def.try_to_nav(&sema) { for nav in navs { if !res.contains(&nav) { res.push(nav); diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index af1557f5a9a16..04ce5a7567f3c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -277,7 +277,7 @@ fn highlight_references( Definition::Module(module) => { NavigationTarget::from_module_to_decl(sema.db, module) } - def => match def.try_to_nav(sema.db) { + def => match def.try_to_nav(sema) { Some(it) => it, None => continue, }, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 44c98a43f6944..3f52303d74e48 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -85,10 +85,11 @@ pub enum HoverAction { impl HoverAction { fn goto_type_from_targets( - db: &RootDatabase, + sema: &Semantics<'_, RootDatabase>, targets: Vec, edition: Edition, ) -> Option { + let db = sema.db; let targets = targets .into_iter() .filter_map(|it| { @@ -99,7 +100,7 @@ impl HoverAction { it.name(db).map(|name| name.display(db, edition).to_string()), edition, ), - nav: it.try_to_nav(db)?.call_site(), + nav: it.try_to_nav(sema)?.call_site(), }) }) .collect::>(); @@ -467,10 +468,10 @@ pub(crate) fn hover_for_definition( HoverResult { markup: render::process_markup(sema.db, def, &markup, range_map, config), actions: [ - show_fn_references_action(sema.db, def), - show_implementations_action(sema.db, def), + show_fn_references_action(sema, def), + show_implementations_action(sema, def), runnable_action(sema, def, file_id), - goto_type_action_for_def(sema.db, def, ¬able_traits, subst_types, edition), + goto_type_action_for_def(sema, def, ¬able_traits, subst_types, edition), ] .into_iter() .flatten() @@ -505,7 +506,10 @@ fn notable_traits<'db>( .collect::>() } -fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { +fn show_implementations_action( + sema: &Semantics<'_, RootDatabase>, + def: Definition, +) -> Option { fn to_action(nav_target: NavigationTarget) -> HoverAction { HoverAction::Implementation(FilePosition { file_id: nav_target.file_id, @@ -515,19 +519,22 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { - return it.try_to_nav(db).map(UpmappingResult::call_site).map(to_action); + return it.try_to_nav(sema).map(UpmappingResult::call_site).map(to_action); } Definition::Adt(it) => Some(it), - Definition::SelfType(it) => it.self_ty(db).as_adt(), + Definition::SelfType(it) => it.self_ty(sema.db).as_adt(), _ => None, }?; - adt.try_to_nav(db).map(UpmappingResult::call_site).map(to_action) + adt.try_to_nav(sema).map(UpmappingResult::call_site).map(to_action) } -fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option { +fn show_fn_references_action( + sema: &Semantics<'_, RootDatabase>, + def: Definition, +) -> Option { match def { Definition::Function(it) => { - it.try_to_nav(db).map(UpmappingResult::call_site).map(|nav_target| { + it.try_to_nav(sema).map(UpmappingResult::call_site).map(|nav_target| { HoverAction::Reference(FilePosition { file_id: nav_target.file_id, offset: nav_target.focus_or_full_range().start(), @@ -560,12 +567,13 @@ fn runnable_action( } fn goto_type_action_for_def( - db: &RootDatabase, + sema: &Semantics<'_, RootDatabase>, def: Definition, notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], subst_types: Option)>>, edition: Edition, ) -> Option { + let db = sema.db; let mut targets: Vec = Vec::new(); let mut push_new_def = |item: hir::ModuleDef| { if !targets.contains(&item) { @@ -612,7 +620,7 @@ fn goto_type_action_for_def( } } - HoverAction::goto_type_from_targets(db, targets, edition) + HoverAction::goto_type_from_targets(sema, targets, edition) } fn walk_and_push_ty( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 2adafbb7af6f7..451260640f844 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -128,7 +128,7 @@ pub(super) fn try_expr( }; walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); walk_and_push_ty(sema.db, &body_ty, &mut push_new_def); - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema, targets, edition) { res.actions.push(actions); } @@ -210,7 +210,7 @@ pub(super) fn deref_expr( ) .into() }; - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema, targets, edition) { res.actions.push(actions); } @@ -323,7 +323,7 @@ pub(super) fn struct_rest_pat( Markup::fenced_block(&s) }; - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema, targets, edition) { res.actions.push(actions); } res @@ -1030,7 +1030,7 @@ fn type_info( }; desc.into() }; - if let Some(actions) = HoverAction::goto_type_from_targets(db, targets, edition) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema, targets, edition) { res.actions.push(actions); } Some(res) @@ -1098,7 +1098,7 @@ fn closure_ty( format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,); let mut res = HoverResult::default(); - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema, targets, edition) { res.actions.push(actions); } res.markup = markup.into(); @@ -1302,7 +1302,7 @@ fn keyword_hints( KeywordHint { description, keyword_mod, - actions: HoverAction::goto_type_from_targets(sema.db, targets, edition) + actions: HoverAction::goto_type_from_targets(sema, targets, edition) .into_iter() .collect(), } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index cc44ae8fc8b9e..507af41d84461 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -672,7 +672,7 @@ impl fmt::Debug for InlayHintLabelPart { #[derive(Debug)] struct InlayHintLabelBuilder<'a> { - db: &'a RootDatabase, + sema: &'a Semantics<'a, RootDatabase>, result: InlayHintLabel, last_part: String, resolve: bool, @@ -694,7 +694,7 @@ impl HirWrite for InlayHintLabelBuilder<'_> { LazyProperty::Lazy } else { LazyProperty::Computed({ - let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; + let Some(location) = ModuleDef::from(def).try_to_nav(self.sema) else { return }; let location = location.call_site(); FileRange { file_id: location.file_id, range: location.focus_or_full_range() } }) @@ -782,7 +782,7 @@ fn label_of_ty( } let mut label_builder = InlayHintLabelBuilder { - db: sema.db, + sema, last_part: String::new(), location: None, result: InlayHintLabel::default(), 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 f0003dae3f36f..4abd67b91f5ec 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 @@ -44,7 +44,7 @@ pub(super) fn hints( text: "Sized".to_owned(), linked_location: sized_trait.and_then(|it| { config.lazy_location_opt(|| { - it.try_to_nav(sema.db).map(|it| { + it.try_to_nav(sema).map(|it| { let n = it.call_site(); FileRange { file_id: n.file_id, diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index cddf5f04f2442..3a6b3247d65c6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -483,7 +483,7 @@ impl Analysis { salsa::attach(&self.db, || { symbols .into_iter() - .filter_map(|s| s.try_to_nav(&self.db)) + .filter_map(|s| s.try_to_nav(&Semantics::new(&self.db))) .take(limit) .map(UpmappingResult::call_site) .collect::>() diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 641bde5e2b82a..46ff16f972625 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -83,14 +83,20 @@ pub(crate) trait ToNav { } pub trait TryToNav { - fn try_to_nav(&self, db: &RootDatabase) -> Option>; + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option>; } impl TryToNav for Either { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - Either::Left(it) => it.try_to_nav(db), - Either::Right(it) => it.try_to_nav(db), + Either::Left(it) => it.try_to_nav(sema), + Either::Right(it) => it.try_to_nav(sema), } } } @@ -185,7 +191,11 @@ impl NavigationTarget { } impl TryToNav for FileSymbol { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let edition = self.def.module(db).map(|it| it.krate().edition(db)).unwrap_or(Edition::CURRENT); let display_target = self.def.krate(db).to_display_target(db); @@ -244,49 +254,55 @@ impl TryToNav for FileSymbol { } impl TryToNav for Definition { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - Definition::Local(it) => Some(it.to_nav(db)), - Definition::Label(it) => it.try_to_nav(db), - Definition::Module(it) => Some(it.to_nav(db)), - Definition::Crate(it) => Some(it.to_nav(db)), - Definition::Macro(it) => it.try_to_nav(db), - Definition::Field(it) => it.try_to_nav(db), - Definition::SelfType(it) => it.try_to_nav(db), - Definition::GenericParam(it) => it.try_to_nav(db), - Definition::Function(it) => it.try_to_nav(db), - Definition::Adt(it) => it.try_to_nav(db), - Definition::Variant(it) => it.try_to_nav(db), - Definition::Const(it) => it.try_to_nav(db), - Definition::Static(it) => it.try_to_nav(db), - Definition::Trait(it) => it.try_to_nav(db), - Definition::TypeAlias(it) => it.try_to_nav(db), - Definition::ExternCrateDecl(it) => it.try_to_nav(db), - Definition::InlineAsmOperand(it) => it.try_to_nav(db), - Definition::BuiltinType(it) => it.try_to_nav(db), + Definition::Local(it) => Some(it.to_nav(sema.db)), + Definition::Label(it) => it.try_to_nav(sema), + Definition::Module(it) => Some(it.to_nav(sema.db)), + Definition::Crate(it) => Some(it.to_nav(sema.db)), + Definition::Macro(it) => it.try_to_nav(sema), + Definition::Field(it) => it.try_to_nav(sema), + Definition::SelfType(it) => it.try_to_nav(sema), + Definition::GenericParam(it) => it.try_to_nav(sema), + Definition::Function(it) => it.try_to_nav(sema), + Definition::Adt(it) => it.try_to_nav(sema), + Definition::Variant(it) => it.try_to_nav(sema), + Definition::Const(it) => it.try_to_nav(sema), + Definition::Static(it) => it.try_to_nav(sema), + Definition::Trait(it) => it.try_to_nav(sema), + Definition::TypeAlias(it) => it.try_to_nav(sema), + Definition::ExternCrateDecl(it) => it.try_to_nav(sema), + Definition::InlineAsmOperand(it) => it.try_to_nav(sema), + Definition::BuiltinType(it) => it.try_to_nav(sema), Definition::BuiltinLifetime(_) | Definition::TupleField(_) | Definition::ToolModule(_) | Definition::InlineAsmRegOrRegClass(_) | Definition::BuiltinAttr(_) => None, // FIXME: The focus range should be set to the helper declaration - Definition::DeriveHelper(it) => it.derive().try_to_nav(db), + Definition::DeriveHelper(it) => it.derive().try_to_nav(sema), } } } impl TryToNav for hir::ModuleDef { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - hir::ModuleDef::Module(it) => Some(it.to_nav(db)), - hir::ModuleDef::Function(it) => it.try_to_nav(db), - hir::ModuleDef::Adt(it) => it.try_to_nav(db), - hir::ModuleDef::Variant(it) => it.try_to_nav(db), - hir::ModuleDef::Const(it) => it.try_to_nav(db), - hir::ModuleDef::Static(it) => it.try_to_nav(db), - hir::ModuleDef::Trait(it) => it.try_to_nav(db), - hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), - hir::ModuleDef::Macro(it) => it.try_to_nav(db), + hir::ModuleDef::Module(it) => Some(it.to_nav(sema.db)), + hir::ModuleDef::Function(it) => it.try_to_nav(sema), + hir::ModuleDef::Adt(it) => it.try_to_nav(sema), + hir::ModuleDef::Variant(it) => it.try_to_nav(sema), + hir::ModuleDef::Const(it) => it.try_to_nav(sema), + hir::ModuleDef::Static(it) => it.try_to_nav(sema), + hir::ModuleDef::Trait(it) => it.try_to_nav(sema), + hir::ModuleDef::TypeAlias(it) => it.try_to_nav(sema), + hir::ModuleDef::Macro(it) => it.try_to_nav(sema), hir::ModuleDef::BuiltinType(_) => None, } } @@ -369,7 +385,11 @@ where D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay + HasCrate, D::Ast: ast::HasName, { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let src = self.source(db)?; Some( NavigationTarget::from_named( @@ -423,7 +443,11 @@ impl ToNav for hir::Crate { } impl TryToNav for hir::Impl { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = self.source(db)?; let derive_path = self.as_builtin_derive_path(db); @@ -447,7 +471,11 @@ impl TryToNav for hir::Impl { } impl TryToNav for hir::ExternCrateDecl { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let src = self.source(db)?; let InFile { file_id, value } = src; let focus = value @@ -479,7 +507,11 @@ impl TryToNav for hir::ExternCrateDecl { } impl TryToNav for hir::Field { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let src = self.source(db)?; let krate = self.parent_def(db).module(db).krate(); @@ -512,7 +544,11 @@ impl TryToNav for hir::Field { } impl TryToNav for hir::Macro { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let src = self.source(db)?; let name_owner: &dyn ast::HasName = match &src.value { Either::Left(it) => it, @@ -533,31 +569,40 @@ impl TryToNav for hir::Macro { } impl TryToNav for hir::Adt { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - hir::Adt::Struct(it) => it.try_to_nav(db), - hir::Adt::Union(it) => it.try_to_nav(db), - hir::Adt::Enum(it) => it.try_to_nav(db), + hir::Adt::Struct(it) => it.try_to_nav(sema), + hir::Adt::Union(it) => it.try_to_nav(sema), + hir::Adt::Enum(it) => it.try_to_nav(sema), } } } impl TryToNav for hir::AssocItem { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - AssocItem::Function(it) => it.try_to_nav(db), - AssocItem::Const(it) => it.try_to_nav(db), - AssocItem::TypeAlias(it) => it.try_to_nav(db), + AssocItem::Function(it) => it.try_to_nav(sema), + AssocItem::Const(it) => it.try_to_nav(sema), + AssocItem::TypeAlias(it) => it.try_to_nav(sema), } } } impl TryToNav for hir::GenericParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { match self { - hir::GenericParam::TypeParam(it) => it.try_to_nav(db), - hir::GenericParam::ConstParam(it) => it.try_to_nav(db), - hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db), + hir::GenericParam::TypeParam(it) => it.try_to_nav(sema), + hir::GenericParam::ConstParam(it) => it.try_to_nav(sema), + hir::GenericParam::LifetimeParam(it) => it.try_to_nav(sema), } } } @@ -606,7 +651,11 @@ impl ToNav for hir::Local { } impl TryToNav for hir::Label { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = self.source(db)?; // Labels can't be keywords, so no escaping needed. let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); @@ -628,7 +677,11 @@ impl TryToNav for hir::Label { } impl TryToNav for hir::TypeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = self.merge().source(db)?; let edition = self.module(db).krate().edition(db); let name = self.name(db).display_no_db(edition).to_smolstr(); @@ -665,13 +718,20 @@ impl TryToNav for hir::TypeParam { } impl TryToNav for hir::TypeOrConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { - self.split(db).try_to_nav(db) + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + self.split(sema.db).try_to_nav(sema) } } impl TryToNav for hir::LifetimeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = self.source(db)?; // Lifetimes cannot be keywords, so not escaping needed. let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); @@ -693,7 +753,11 @@ impl TryToNav for hir::LifetimeParam { } impl TryToNav for hir::ConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = self.merge().source(db)?; let edition = self.module(db).krate().edition(db); let name = self.name(db).display_no_db(edition).to_smolstr(); @@ -723,7 +787,11 @@ impl TryToNav for hir::ConstParam { } impl TryToNav for hir::InlineAsmOperand { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let InFile { file_id, value } = &self.source(db)?; let file_id = *file_id; Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( @@ -748,9 +816,11 @@ impl TryToNav for hir::InlineAsmOperand { } impl TryToNav for hir::BuiltinType { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { - let sema = Semantics::new(db); - + fn try_to_nav( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option> { + let db = sema.db; let krate = db .all_crates() .iter() @@ -759,7 +829,7 @@ impl TryToNav for hir::BuiltinType { .map(Crate::from)?; let edition = krate.edition(db); - let fd = FamousDefs(&sema, krate); + let fd = FamousDefs(sema, krate); let primitive_mod = format!("prim_{}", self.name().display(fd.0.db, edition)); let doc_owner = find_std_module(&fd, &primitive_mod, edition)?; diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index dc509b3858389..0189939eac310 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -138,7 +138,7 @@ pub(crate) fn find_all_refs( Definition::Module(module) => { Some(NavigationTarget::from_module_to_decl(sema.db, module)) } - def => def.try_to_nav(sema.db), + def => def.try_to_nav(sema), } .map(|nav| { let (nav, extra_ref) = match nav.def_site { diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 6d33ddcde0479..6ad9c7884db93 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -158,15 +158,15 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { Definition::SelfType(impl_) => runnable_impl(&sema, &impl_), _ => None, }; - add_opt(runnable.or_else(|| module_def_doctest(sema.db, def)), Some(def)); + add_opt(runnable.or_else(|| module_def_doctest(&sema, def)), Some(def)); if let Definition::SelfType(impl_) = def { impl_.items(db).into_iter().for_each(|assoc| { let runnable = match assoc { hir::AssocItem::Function(it) => { - runnable_fn(&sema, it).or_else(|| module_def_doctest(sema.db, it.into())) + runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into())) } - hir::AssocItem::Const(it) => module_def_doctest(sema.db, it.into()), - hir::AssocItem::TypeAlias(it) => module_def_doctest(sema.db, it.into()), + hir::AssocItem::Const(it) => module_def_doctest(&sema, it.into()), + hir::AssocItem::TypeAlias(it) => module_def_doctest(&sema, it.into()), }; add_opt(runnable, Some(assoc.into())) }); @@ -410,7 +410,7 @@ pub(crate) fn runnable_impl( return None; } let cfg = attrs.cfg(); - let nav = def.try_to_nav(sema.db)?.call_site(); + let nav = def.try_to_nav(sema)?.call_site(); let ty = def.self_ty(sema.db); let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.generic_parameters(sema.db, display_target).peekable(); @@ -486,7 +486,8 @@ fn runnable_mod_outline_definition( }) } -fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { +fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Option { + let db = sema.db; let attrs = match def { Definition::Module(it) => it.attrs(db), Definition::Function(it) => it.attrs(db), @@ -540,7 +541,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { let mut nav = match def { Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def), - def => def.try_to_nav(db)?, + def => def.try_to_nav(sema)?, } .call_site(); nav.focus_range = None; diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 8c3275df1baab..8214b4d1de22f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -243,7 +243,7 @@ impl StaticIndex<'_> { edition, display_target, )), - definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map( + definition: def.try_to_nav(&sema).map(UpmappingResult::call_site).map( |it| FileRange { file_id: it.file_id, range: it.focus_or_full_range() }, ), references: vec![], @@ -261,7 +261,7 @@ impl StaticIndex<'_> { let token = self.tokens.get_mut(id).unwrap(); token.references.push(ReferenceData { range: FileRange { range, file_id }, - is_definition: match def.try_to_nav(self.db).map(UpmappingResult::call_site) { + is_definition: match def.try_to_nav(&sema).map(UpmappingResult::call_site) { Some(it) => it.file_id == file_id && it.focus_or_full_range() == range, None => false, }, diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs index 06cbd50e946ac..bd60ffe559120 100644 --- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs +++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs @@ -94,7 +94,7 @@ fn discover_tests_in_module( if !f.is_test(db) { continue; } - let nav = f.try_to_nav(db).map(|r| r.call_site); + let nav = f.try_to_nav(&sema).map(|r| r.call_site); let fn_name = f.name(db).as_str().to_owned(); r.push(TestItem { id: format!("{prefix_id}::{fn_name}"), From 17943cc47a42472fed79d92cdabeff55f021d6e3 Mon Sep 17 00:00:00 2001 From: Ifeanyi Orizu Date: Mon, 8 Sep 2025 13:29:06 -0500 Subject: [PATCH 169/251] Skip flycheck for workspace if it is already being checked --- .../src/handlers/notification.rs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index e193ff77743d1..fb743e73c74a4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -303,11 +303,11 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let world = state.snapshot(); let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once(); let may_flycheck_workspace = state.config.flycheck_workspace(None); - let mut updated = false; + let mut workspace_check_triggered = false; let task = move || -> std::result::Result<(), Cancelled> { + let saved_file = vfs_path.as_path().map(|p| p.to_owned()); if invocation_strategy_once { - let saved_file = vfs_path.as_path().map(|p| p.to_owned()); - world.flycheck[0].restart_workspace(saved_file); + world.flycheck[0].restart_workspace(saved_file.clone()); } let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { @@ -330,6 +330,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { tracing::debug!(?target, "flycheck target"); // we have a specific non-library target, attempt to only check that target, nothing // else will be affected + let mut package_workspace_idx = None; if let Some((target, root, package)) = target { // trigger a package check if we have a non-library target as that can't affect // anything else in the workspace OR if we're not allowed to check the workspace as @@ -345,6 +346,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { _ => false, }); if let Some(idx) = workspace { + package_workspace_idx = Some(idx); world.flycheck[idx].restart_for_package(package, target); } } @@ -381,8 +383,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { tracing::debug!(?crate_root_paths, "flycheck crate roots"); // Find all workspaces that have at least one target containing the saved file - let workspace_ids = - world.workspaces.iter().enumerate().filter(|(_, ws)| match &ws.kind { + let workspace_ids = world + .workspaces + .iter() + .enumerate() + .filter(|&(idx, _)| match package_workspace_idx { + Some(pkg_idx) => idx != pkg_idx, + None => true, + }) + .filter(|&(_, ws)| match &ws.kind { project_model::ProjectWorkspaceKind::Cargo { cargo, .. } | project_model::ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), @@ -399,20 +408,18 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { project_model::ProjectWorkspaceKind::DetachedFile { .. } => false, }); - let saved_file = vfs_path.as_path().map(|p| p.to_owned()); - // Find and trigger corresponding flychecks 'flychecks: for flycheck in world.flycheck.iter() { for (id, _) in workspace_ids.clone() { if id == flycheck.id() { - updated = true; + workspace_check_triggered = true; flycheck.restart_workspace(saved_file.clone()); continue 'flychecks; } } } // No specific flycheck was triggered, so let's trigger all of them. - if !updated { + if !workspace_check_triggered && package_workspace_idx.is_none() { for flycheck in world.flycheck.iter() { flycheck.restart_workspace(saved_file.clone()); } From e8206d0b88cf48d692c059a913d7124375448934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 9 Sep 2025 08:37:02 +0200 Subject: [PATCH 170/251] Update documentation about how to build the RA book --- src/tools/rust-analyzer/docs/book/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/docs/book/README.md b/src/tools/rust-analyzer/docs/book/README.md index 0a3161f3af38d..11f7e8f98ca56 100644 --- a/src/tools/rust-analyzer/docs/book/README.md +++ b/src/tools/rust-analyzer/docs/book/README.md @@ -8,6 +8,7 @@ To run the documentation site locally: ```shell cargo install mdbook +cargo install mdbook-toc cargo xtask codegen cd docs/book mdbook serve From a1a1ed25f2749de58c24a618460cb3d4279b1d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 9 Sep 2025 09:12:09 +0200 Subject: [PATCH 171/251] Add a FAQ entry about RA and Cargo interaction --- src/tools/rust-analyzer/docs/book/src/faq.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tools/rust-analyzer/docs/book/src/faq.md b/src/tools/rust-analyzer/docs/book/src/faq.md index c87203309011b..8c143ab949357 100644 --- a/src/tools/rust-analyzer/docs/book/src/faq.md +++ b/src/tools/rust-analyzer/docs/book/src/faq.md @@ -5,3 +5,12 @@ rust-analyzer fails to resolve `None`, and thinks you are binding to a variable named `None`. That's usually a sign of a corrupted sysroot. Try removing and re-installing it: `rustup component remove rust-src` then `rustup component install rust-src`. + +### Rust Analyzer and Cargo compete over the build lock + +Rust Analyzer invokes Cargo in the background, and it can thus block manually executed +`cargo` commands from making progress (or vice-versa). In some cases, this can also cause +unnecessary recompilations caused by cache thrashing. To avoid this, you can configure +Rust Analyzer to use a [different target directory](./configuration.md#cargo.targetDir). +This will allow both the IDE and Cargo to make progress independently, at the cost of +increased disk space usage caused by the duplicated artifact directories. From 2079d1126bcfb5ed125009f3ccfc67ebd7995d56 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 7 Sep 2025 15:05:11 +0800 Subject: [PATCH 172/251] Fix LifetimeParam::lifetime_bounds invalid implement Lifetime node example: ``` LIFETIME_PARAM@15..21 LIFETIME@15..17 LIFETIME_IDENT@15..17 "'a" COLON@17..18 ":" WHITESPACE@18..19 " " TYPE_BOUND_LIST@19..21 TYPE_BOUND@19..21 LIFETIME@19..21 LIFETIME_IDENT@19..21 "'b" ``` --- .../rust-analyzer/crates/syntax/src/ast/node_ext.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 42b0f5cf2da1c..af741d100f680 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -12,8 +12,8 @@ use rowan::{GreenNodeData, GreenTokenData}; use crate::{ NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, T, TokenText, ast::{ - self, AstNode, AstToken, HasAttrs, HasGenericArgs, HasGenericParams, HasName, SyntaxNode, - support, + self, AstNode, AstToken, HasAttrs, HasGenericArgs, HasGenericParams, HasName, + HasTypeBounds, SyntaxNode, support, }, ted, }; @@ -912,11 +912,10 @@ impl ast::Visibility { impl ast::LifetimeParam { pub fn lifetime_bounds(&self) -> impl Iterator { - self.syntax() - .children_with_tokens() - .filter_map(|it| it.into_token()) - .skip_while(|x| x.kind() != T![:]) - .filter(|it| it.kind() == T![lifetime_ident]) + self.type_bound_list() + .into_iter() + .flat_map(|it| it.bounds()) + .filter_map(|it| it.lifetime()?.lifetime_ident_token()) } } From a69ac553992de87fd5192621a09a21a58887b164 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 9 Sep 2025 10:38:20 +0300 Subject: [PATCH 173/251] Resolve paths to snapshot test libraries absolutely That is, resolve them globally, not from the test's location. This *should* result in more robust resolution; for example, previously the code failed to detect the presence of snapshot testing if the snapshot library was renamed in the dependency or was an indirect dependency. --- .../crates/ide/src/hover/tests.rs | 71 +++++++++++++++++++ .../rust-analyzer/crates/ide/src/runnables.rs | 37 ++++------ 2 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 6f1bbad6ba169..58d8a7edbe042 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -10569,6 +10569,77 @@ macro_rules! str { ); } +#[test] +fn test_runnables_with_snapshot_tests_indirect_dep() { + check_actions( + r#" +//- /lib.rs crate:foo deps:utils +use utils::expect_test::expect; + +#[test] +fn test$0() { + let actual = "new25"; + expect!["new25"].assert_eq(&actual); +} + +//- /expect-test/lib.rs crate:expect_test +struct Expect; + +impl Expect { + fn assert_eq(&self, actual: &str) {} +} + +#[macro_export] +macro_rules! expect { + ($e:expr) => Expect; // dummy +} + +//- /utils/lib.rs crate:utils deps:expect_test +pub use expect_test; + "#, + expect![[r#" + [ + Reference( + FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 44, + }, + ), + Runnable( + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 33..121, + focus_range: 44..48, + name: "test", + kind: Function, + }, + kind: Test { + test_id: Path( + "test", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + update_test: UpdateTest { + expect_test: true, + insta: false, + snapbox: false, + }, + }, + ), + ] + "#]], + ); +} + #[test] fn drop_glue() { check( diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 6ad9c7884db93..ec13ba0fde340 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -4,8 +4,8 @@ use arrayvec::ArrayVec; use ast::HasName; use cfg::{CfgAtom, CfgExpr}; use hir::{ - AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics, - Symbol, db::HirDatabase, sym, + AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, Semantics, Symbol, db::HirDatabase, + sym, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ @@ -352,8 +352,7 @@ pub(crate) fn runnable_fn( .call_site(); let file_range = fn_source.syntax().original_file_range_with_macro_call_input(sema.db); - let update_test = - UpdateTest::find_snapshot_macro(sema, &fn_source.file_syntax(sema.db), file_range); + let update_test = UpdateTest::find_snapshot_macro(sema, file_range); let cfg = def.attrs(sema.db).cfg(); Some(Runnable { use_name_in_title: false, nav, kind, cfg, update_test }) @@ -388,7 +387,7 @@ pub(crate) fn runnable_mod( file_id: module_source.file_id.original_file(sema.db), range: module_syntax.text_range(), }; - let update_test = UpdateTest::find_snapshot_macro(sema, &module_syntax, file_range); + let update_test = UpdateTest::find_snapshot_macro(sema, file_range); Some(Runnable { use_name_in_title: false, @@ -428,8 +427,7 @@ pub(crate) fn runnable_impl( let impl_source = sema.source(*def)?; let impl_syntax = impl_source.syntax(); let file_range = impl_syntax.original_file_range_with_macro_call_input(sema.db); - let update_test = - UpdateTest::find_snapshot_macro(sema, &impl_syntax.file_syntax(sema.db), file_range); + let update_test = UpdateTest::find_snapshot_macro(sema, file_range); Some(Runnable { use_name_in_title: false, @@ -475,7 +473,7 @@ fn runnable_mod_outline_definition( file_id: mod_source.file_id.original_file(sema.db), range: mod_syntax.text_range(), }; - let update_test = UpdateTest::find_snapshot_macro(sema, &mod_syntax, file_range); + let update_test = UpdateTest::find_snapshot_macro(sema, file_range); Some(Runnable { use_name_in_title: false, @@ -641,7 +639,7 @@ pub struct UpdateTest { pub snapbox: bool, } -static SNAPSHOT_TEST_MACROS: OnceLock>> = OnceLock::new(); +static SNAPSHOT_TEST_MACROS: OnceLock>> = OnceLock::new(); impl UpdateTest { const EXPECT_CRATE: &str = "expect_test"; @@ -665,22 +663,17 @@ impl UpdateTest { const SNAPBOX_CRATE: &str = "snapbox"; const SNAPBOX_MACROS: &[&str] = &["assert_data_eq", "file", "str"]; - fn find_snapshot_macro( - sema: &Semantics<'_, RootDatabase>, - scope: &SyntaxNode, - file_range: hir::FileRange, - ) -> Self { + fn find_snapshot_macro(sema: &Semantics<'_, RootDatabase>, file_range: hir::FileRange) -> Self { fn init<'a>( krate_name: &'a str, paths: &[&str], - map: &mut FxHashMap<&'a str, Vec>, + map: &mut FxHashMap<&'a str, Vec<[Symbol; 2]>>, ) { let mut res = Vec::with_capacity(paths.len()); - let krate = Name::new_symbol_root(Symbol::intern(krate_name)); + let krate = Symbol::intern(krate_name); for path in paths { - let segments = [krate.clone(), Name::new_symbol_root(Symbol::intern(path))]; - let mod_path = ModPath::from_segments(PathKind::Abs, segments); - res.push(mod_path); + let segments = [krate.clone(), Symbol::intern(path)]; + res.push(segments); } map.insert(krate_name, res); } @@ -694,11 +687,9 @@ impl UpdateTest { }); let search_scope = SearchScope::file_range(file_range); - let find_macro = |paths: &[ModPath]| { + let find_macro = |paths: &[[Symbol; 2]]| { for path in paths { - let Some(items) = sema.resolve_mod_path(scope, path) else { - continue; - }; + let items = hir::resolve_absolute_path(sema.db, path.iter().cloned()); for item in items { if let hir::ItemInNs::Macros(makro) = item && Definition::Macro(makro) From 74a8f7451e75a789a4f656682465b4a2f6b559d2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 9 Sep 2025 13:31:05 +0300 Subject: [PATCH 174/251] Expand target info to include the architecture And make it easier to expand it more in the future, if needed. --- .../rust-analyzer/crates/base-db/src/input.rs | 4 +- .../rust-analyzer/crates/base-db/src/lib.rs | 7 ++- .../crates/base-db/src/target.rs | 50 +++++++++++++++++++ .../hir-def/src/nameres/tests/incremental.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 3 +- .../crates/hir-ty/src/layout/target.rs | 8 +-- .../crates/hir-ty/src/layout/tests.rs | 11 ++-- .../crates/hir-ty/src/mir/eval.rs | 3 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 2 +- .../crates/project-model/src/lib.rs | 2 +- .../crates/project-model/src/tests.rs | 7 ++- .../{target_data_layout.rs => target_data.rs} | 41 +++++++++++++-- .../crates/project-model/src/workspace.rs | 38 +++++++------- .../cargo_hello_world_project_model.txt | 10 ++-- ...project_model_with_selective_overrides.txt | 10 ++-- ..._project_model_with_wildcard_overrides.txt | 10 ++-- .../output/rust_project_cfg_groups.txt | 8 +-- ...rust_project_hello_world_project_model.txt | 4 +- .../rust-analyzer/src/cli/rustc_tests.rs | 7 ++- .../rust-analyzer/tests/slow-tests/support.rs | 2 + .../crates/test-fixture/src/lib.rs | 18 +++++-- .../crates/test-utils/src/fixture.rs | 19 ++++++- 22 files changed, 188 insertions(+), 78 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/base-db/src/target.rs rename src/tools/rust-analyzer/crates/project-model/src/toolchain_info/{target_data_layout.rs => target_data.rs} (72%) diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 0bf4fbdfbd691..cac74778a26b0 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -295,8 +295,6 @@ impl CrateDisplayName { } } -pub type TargetLayoutLoadResult = Result, Arc>; - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ReleaseChannel { Stable, @@ -929,7 +927,7 @@ mod tests { use super::{CrateGraphBuilder, CrateName, CrateOrigin, Edition::Edition2018, Env, FileId}; fn empty_ws_data() -> Arc { - Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }) + Arc::new(CrateWorkspaceData { target: Err("".into()), toolchain: None }) } #[test] diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 14544acc11bdf..0e411bcfae60e 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -6,6 +6,7 @@ pub use salsa_macros; // FIXME: Rename this crate, base db is non descriptive mod change; mod input; +pub mod target; use std::{ cell::RefCell, @@ -20,8 +21,7 @@ pub use crate::{ BuiltCrateData, BuiltDependency, Crate, CrateBuilder, CrateBuilderId, CrateDataBuilder, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CratesIdMap, CratesMap, DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroLoadingError, - ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult, - UniqueCrateData, + ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, UniqueCrateData, }, }; use dashmap::{DashMap, mapref::entry::Entry}; @@ -359,8 +359,7 @@ impl Nonce { /// Crate related data shared by the whole workspace. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct CrateWorkspaceData { - // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query - pub data_layout: TargetLayoutLoadResult, + pub target: Result, /// Toolchain version used to compile the crate. pub toolchain: Option, } diff --git a/src/tools/rust-analyzer/crates/base-db/src/target.rs b/src/tools/rust-analyzer/crates/base-db/src/target.rs new file mode 100644 index 0000000000000..19d3407bf3c80 --- /dev/null +++ b/src/tools/rust-analyzer/crates/base-db/src/target.rs @@ -0,0 +1,50 @@ +//! Information about the target. + +use std::fmt; + +use triomphe::Arc; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Arch { + // Only what we need is present here. + Wasm32, + Wasm64, + Other, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct TargetData { + pub data_layout: Box, + pub arch: Arch, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct TargetLoadError(Arc); + +impl fmt::Debug for TargetLoadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for TargetLoadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl std::error::Error for TargetLoadError {} + +impl From for TargetLoadError { + fn from(value: String) -> Self { + Self(value.into()) + } +} + +impl From<&str> for TargetLoadError { + fn from(value: &str) -> Self { + Self(value.into()) + } +} + +pub type TargetLoadResult = Result; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index 338851b715bf0..6afa04bc412aa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -84,7 +84,7 @@ pub const BAZ: u32 = 0; ) .unwrap(), ), - Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }), + Arc::new(CrateWorkspaceData { target: Err("".into()), toolchain: None }), ) }; let a = add_crate("a", 0); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 0b7213d785c91..0aec2b9dec7bc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -2,6 +2,7 @@ //! type inference-related queries. use base_db::Crate; +use base_db::target::TargetLoadError; use hir_def::{ AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, @@ -108,7 +109,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] - fn target_data_layout(&self, krate: Crate) -> Result, Arc>; + fn target_data_layout(&self, krate: Crate) -> Result, TargetLoadError>; #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs index 82d0ed4f19470..8a7d93d50c05b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs @@ -1,6 +1,6 @@ //! Target dependent parameters needed for layouts -use base_db::Crate; +use base_db::{Crate, target::TargetLoadError}; use hir_def::layout::TargetDataLayout; use rustc_abi::{AddressSpace, AlignFromBytesError, TargetDataLayoutErrors}; use triomphe::Arc; @@ -10,9 +10,9 @@ use crate::db::HirDatabase; pub fn target_data_layout_query( db: &dyn HirDatabase, krate: Crate, -) -> Result, Arc> { - match &krate.workspace_data(db).data_layout { - Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it, AddressSpace::ZERO) { +) -> Result, TargetLoadError> { + match &krate.workspace_data(db).target { + Ok(target) => match TargetDataLayout::parse_from_llvm_datalayout_string(&target.data_layout, AddressSpace::ZERO) { Ok(it) => Ok(Arc::new(it)), Err(e) => { Err(match e { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 90de7e5ca633d..523ddad94666b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -1,3 +1,4 @@ +use base_db::target::TargetData; use chalk_ir::{AdtId, TyKind}; use either::Either; use hir_def::db::DefDatabase; @@ -18,8 +19,8 @@ use crate::{ mod closure; -fn current_machine_data_layout() -> String { - project_model::toolchain_info::target_data_layout::get( +fn current_machine_target_data() -> TargetData { + project_model::toolchain_info::target_data::get( QueryConfig::Rustc(&Sysroot::empty(), &std::env::current_dir().unwrap()), None, &FxHashMap::default(), @@ -32,7 +33,8 @@ fn eval_goal( minicore: &str, ) -> Result, LayoutError> { let _tracing = setup_tracing(); - let target_data_layout = current_machine_data_layout(); + let target_data = current_machine_target_data(); + let target_data_layout = target_data.data_layout; let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\n{ra_fixture}", ); @@ -104,7 +106,8 @@ fn eval_expr( minicore: &str, ) -> Result, LayoutError> { let _tracing = setup_tracing(); - let target_data_layout = current_machine_data_layout(); + let target_data = current_machine_target_data(); + let target_data_layout = target_data.data_layout; let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\nfn main(){{let goal = {{{ra_fixture}}};}}", ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index c60ace85be124..94d7c2f5ec5ae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; use base_db::Crate; +use base_db::target::TargetLoadError; use chalk_ir::{Mutability, cast::Cast}; use either::Either; use hir_def::{ @@ -337,7 +338,7 @@ impl Address { pub enum MirEvalError { ConstEvalError(String, Box), LayoutError(LayoutError, Ty), - TargetDataLayoutNotAvailable(Arc), + TargetDataLayoutNotAvailable(TargetLoadError), /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected /// then use this type of error. UndefinedBehavior(String), diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 3a6b3247d65c6..50cbef581c7d7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -263,7 +263,7 @@ impl Analysis { false, proc_macro_cwd, Arc::new(CrateWorkspaceData { - data_layout: Err("fixture has no layout".into()), + target: Err("fixture has no layout".into()), toolchain: None, }), ); diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index d39781b15066d..e36b904881513 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -18,7 +18,7 @@ pub mod project_json; pub mod toolchain_info { pub mod rustc_cfg; - pub mod target_data_layout; + pub mod target_data; pub mod target_tuple; pub mod version; diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index ed72520f40d4d..987d381fac638 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -9,7 +9,6 @@ use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; use span::FileId; -use triomphe::Arc; use crate::{ CargoWorkspace, CfgOverrides, ManifestPath, ProjectJson, ProjectJsonData, ProjectWorkspace, @@ -47,7 +46,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace { sysroot: Sysroot::empty(), rustc_cfg: Vec::new(), toolchain: None, - target_layout: Err("target_data_layout not loaded".into()), + target: Err("target_data_layout not loaded".into()), extra_includes: Vec::new(), set_test: true, } @@ -62,7 +61,7 @@ fn load_rust_project(file: &str) -> (CrateGraphBuilder, ProcMacroPaths) { sysroot, rustc_cfg: Vec::new(), toolchain: None, - target_layout: Err(Arc::from("test has no data layout")), + target: Err("test has no target data".into()), cfg_overrides: Default::default(), extra_includes: Vec::new(), set_test: true, @@ -265,7 +264,7 @@ fn smoke_test_real_sysroot_cargo() { rustc_cfg: Vec::new(), cfg_overrides: Default::default(), toolchain: None, - target_layout: Err("target_data_layout not loaded".into()), + target: Err("target_data_layout not loaded".into()), extra_includes: Vec::new(), set_test: true, }; diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data.rs similarity index 72% rename from src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs rename to src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data.rs index f1d99cb8b002c..b815c0b79718e 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data.rs @@ -1,23 +1,54 @@ //! Runs `rustc --print target-spec-json` to get the target_data_layout. use anyhow::Context; +use base_db::target; use rustc_hash::FxHashMap; +use serde_derive::Deserialize; use toolchain::Tool; use crate::{Sysroot, toolchain_info::QueryConfig, utf8_stdout}; +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Arch { + Wasm32, + Wasm64, + #[serde(other)] + Other, +} + +impl From for target::Arch { + fn from(value: Arch) -> Self { + match value { + Arch::Wasm32 => target::Arch::Wasm32, + Arch::Wasm64 => target::Arch::Wasm64, + Arch::Other => target::Arch::Other, + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct TargetSpec { + pub data_layout: String, + pub arch: Arch, +} + /// Uses `rustc --print target-spec-json`. pub fn get( config: QueryConfig<'_>, target: Option<&str>, extra_env: &FxHashMap>, -) -> anyhow::Result { +) -> anyhow::Result { const RUSTC_ARGS: [&str; 2] = ["--print", "target-spec-json"]; let process = |output: String| { - (|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))() - .ok_or_else(|| { - anyhow::format_err!("could not parse target-spec-json from command output") - }) + let target_spec = serde_json::from_str::(&output).map_err(|_| { + anyhow::format_err!("could not parse target-spec-json from command output") + })?; + Ok(target::TargetData { + arch: target_spec.arch.into(), + data_layout: target_spec.data_layout.into_boxed_str(), + }) }; let (sysroot, current_dir) = match config { QueryConfig::Cargo(sysroot, cargo_toml, _) => { diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 00032bcf1d2e4..e0d2105c8df89 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -8,7 +8,7 @@ use anyhow::Context; use base_db::{ CrateBuilderId, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, DependencyBuilder, Env, LangCrateOrigin, ProcMacroLoadingError, - ProcMacroPaths, TargetLayoutLoadResult, + ProcMacroPaths, target::TargetLoadResult, }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; use intern::{Symbol, sym}; @@ -30,7 +30,7 @@ use crate::{ env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env}, project_json::{Crate, CrateArrayIdx}, sysroot::RustLibSrcWorkspace, - toolchain_info::{QueryConfig, rustc_cfg, target_data_layout, target_tuple, version}, + toolchain_info::{QueryConfig, rustc_cfg, target_data, target_tuple, version}, utf8_stdout, }; use tracing::{debug, error, info}; @@ -63,7 +63,7 @@ pub struct ProjectWorkspace { /// The toolchain version used by this workspace. pub toolchain: Option, /// The target data layout queried for workspace. - pub target_layout: TargetLayoutLoadResult, + pub target: TargetLoadResult, /// A set of cfg overrides for this workspace. pub cfg_overrides: CfgOverrides, /// Additional includes to add for the VFS. @@ -115,7 +115,7 @@ impl fmt::Debug for ProjectWorkspace { sysroot, rustc_cfg, toolchain, - target_layout, + target: target_layout, cfg_overrides, extra_includes, set_test, @@ -309,8 +309,8 @@ impl ProjectWorkspace { let rustc_cfg = s.spawn(|| { rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env) }); - let data_layout = s.spawn(|| { - target_data_layout::get( + let target_data = s.spawn(|| { + target_data::get( toolchain_config, targets.first().map(Deref::deref), extra_env, @@ -392,7 +392,7 @@ impl ProjectWorkspace { s.spawn(move || cargo_config_env(cargo_toml, &config_file)); thread::Result::Ok(( rustc_cfg.join()?, - data_layout.join()?, + target_data.join()?, rustc_dir.join()?, loaded_sysroot.join()?, cargo_metadata.join()?, @@ -442,7 +442,7 @@ impl ProjectWorkspace { rustc_cfg, cfg_overrides: cfg_overrides.clone(), toolchain, - target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + target: data_layout.map_err(|it| it.to_string().into()), extra_includes: extra_includes.clone(), set_test: *set_test, }) @@ -480,11 +480,7 @@ impl ProjectWorkspace { rustc_cfg::get(query_config, targets.first().map(Deref::deref), &config.extra_env) }); let data_layout = s.spawn(|| { - target_data_layout::get( - query_config, - targets.first().map(Deref::deref), - &config.extra_env, - ) + target_data::get(query_config, targets.first().map(Deref::deref), &config.extra_env) }); let loaded_sysroot = s.spawn(|| { if let Some(sysroot_project) = sysroot_project { @@ -513,7 +509,7 @@ impl ProjectWorkspace { thread::Result::Ok((rustc_cfg.join()?, data_layout.join()?, loaded_sysroot.join()?)) }); - let (rustc_cfg, target_layout, loaded_sysroot) = match join { + let (rustc_cfg, target_data, loaded_sysroot) = match join { Ok(it) => it, Err(e) => std::panic::resume_unwind(e), }; @@ -527,7 +523,7 @@ impl ProjectWorkspace { sysroot, rustc_cfg, toolchain, - target_layout: target_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + target: target_data.map_err(|it| it.to_string().into()), cfg_overrides: config.cfg_overrides.clone(), extra_includes: config.extra_includes.clone(), set_test: config.set_test, @@ -551,7 +547,7 @@ impl ProjectWorkspace { let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env) .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); - let data_layout = target_data_layout::get(query_config, None, &config.extra_env); + let target_data = target_data::get(query_config, None, &config.extra_env); let target_dir = config .target_dir .clone() @@ -610,7 +606,7 @@ impl ProjectWorkspace { sysroot, rustc_cfg, toolchain, - target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + target: target_data.map_err(|it| it.to_string().into()), cfg_overrides: config.cfg_overrides.clone(), extra_includes: config.extra_includes.clone(), set_test: config.set_test, @@ -942,7 +938,7 @@ impl ProjectWorkspace { let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self; let crate_ws_data = Arc::new(CrateWorkspaceData { toolchain: self.toolchain.clone(), - data_layout: self.target_layout.clone(), + target: self.target.clone(), }); let (crate_graph, proc_macros) = match kind { ProjectWorkspaceKind::Json(project) => project_json_to_crate_graph( @@ -1000,13 +996,15 @@ impl ProjectWorkspace { } pub fn eq_ignore_build_data(&self, other: &Self) -> bool { - let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides, .. } = self; + let Self { + kind, sysroot, rustc_cfg, toolchain, target: target_layout, cfg_overrides, .. + } = self; let Self { kind: o_kind, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg, toolchain: o_toolchain, - target_layout: o_target_layout, + target: o_target_layout, cfg_overrides: o_cfg_overrides, .. } = other; diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index 3722e2c721686..4f6ce4dc95374 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -70,7 +70,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -155,7 +155,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -240,7 +240,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -325,7 +325,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -406,7 +406,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index 3722e2c721686..4f6ce4dc95374 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -70,7 +70,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -155,7 +155,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -240,7 +240,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -325,7 +325,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -406,7 +406,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 7b156ea63a58f..6862918e09ae6 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -69,7 +69,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -153,7 +153,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -237,7 +237,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -321,7 +321,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, @@ -402,7 +402,7 @@ }, }, ws_data: CrateWorkspaceData { - data_layout: Err( + target: Err( "target_data_layout not loaded", ), toolchain: None, diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt index 98fe598eb3a32..28ad3236ae813 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt @@ -43,8 +43,8 @@ entries: {}, }, ws_data: CrateWorkspaceData { - data_layout: Err( - "test has no data layout", + target: Err( + "test has no target data", ), toolchain: None, }, @@ -93,8 +93,8 @@ entries: {}, }, ws_data: CrateWorkspaceData { - data_layout: Err( - "test has no data layout", + target: Err( + "test has no target data", ), toolchain: None, }, diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index 0dc373b5b47ed..dabb3aa674414 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -40,8 +40,8 @@ entries: {}, }, ws_data: CrateWorkspaceData { - data_layout: Err( - "test has no data layout", + target: Err( + "test has no target data", ), toolchain: None, }, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 36ae98b321b84..609ebf2b514f0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -11,7 +11,7 @@ use ide_db::base_db; use itertools::Either; use paths::Utf8PathBuf; use profile::StopWatch; -use project_model::toolchain_info::{QueryConfig, target_data_layout}; +use project_model::toolchain_info::{QueryConfig, target_data}; use project_model::{ CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, RustLibSource, RustSourceWorkspaceConfig, Sysroot, @@ -19,7 +19,6 @@ use project_model::{ use load_cargo::{LoadCargoConfig, ProcMacroServerChoice, load_workspace}; use rustc_hash::FxHashMap; -use triomphe::Arc; use vfs::{AbsPathBuf, FileId}; use walkdir::WalkDir; @@ -87,7 +86,7 @@ impl Tester { sysroot.set_workspace(loaded_sysroot); } - let data_layout = target_data_layout::get( + let target_data = target_data::get( QueryConfig::Rustc(&sysroot, tmp_file.parent().unwrap().as_ref()), None, &cargo_config.extra_env, @@ -101,7 +100,7 @@ impl Tester { sysroot, rustc_cfg: vec![], toolchain: None, - target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + target: target_data.map_err(|it| it.to_string().into()), cfg_overrides: Default::default(), extra_includes: vec![], set_test: true, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 2bebb0c1b9700..3464a9644b19d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -97,6 +97,7 @@ impl Project<'_> { proc_macro_names, toolchain, target_data_layout: _, + target_arch: _, } = FixtureWithProjectMeta::parse(self.fixture); assert!(proc_macro_names.is_empty()); assert!(mini_core.is_none()); @@ -177,6 +178,7 @@ impl Project<'_> { proc_macro_names, toolchain, target_data_layout: _, + target_arch: _, } = FixtureWithProjectMeta::parse(self.fixture); assert!(proc_macro_names.is_empty()); assert!(mini_core.is_none()); diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 57fca70547bf9..7574d12c0cfd0 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -1,6 +1,7 @@ //! A set of high-level utility fixture methods to use in tests. use std::{any::TypeId, mem, str::FromStr, sync}; +use base_db::target::TargetData; use base_db::{ Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, DependencyBuilder, Env, FileChange, FileSet, FxIndexMap, LangCrateOrigin, SourceDatabase, @@ -136,8 +137,11 @@ impl ChangeFixture { proc_macro_names, toolchain, target_data_layout, + target_arch, } = FixtureWithProjectMeta::parse(ra_fixture); - let target_data_layout = Ok(target_data_layout.into()); + let target_data_layout = target_data_layout.into(); + let target_arch = parse_target_arch(&target_arch); + let target = Ok(TargetData { arch: target_arch, data_layout: target_data_layout }); let toolchain = Some({ let channel = toolchain.as_deref().unwrap_or("stable"); Version::parse(&format!("1.76.0-{channel}")).unwrap() @@ -163,8 +167,7 @@ impl ChangeFixture { let mut file_position = None; - let crate_ws_data = - Arc::new(CrateWorkspaceData { data_layout: target_data_layout, toolchain }); + let crate_ws_data = Arc::new(CrateWorkspaceData { target, toolchain }); // FIXME: This is less than ideal let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())); @@ -395,6 +398,15 @@ impl ChangeFixture { } } +fn parse_target_arch(arch: &str) -> base_db::target::Arch { + use base_db::target::Arch::*; + match arch { + "wasm32" => Wasm32, + "wasm64" => Wasm64, + _ => Other, + } +} + fn default_test_proc_macros() -> Box<[(String, ProcMacro)]> { Box::new([ ( 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 e830c6a7cf688..c024089a016f9 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -149,6 +149,8 @@ pub struct FixtureWithProjectMeta { /// You probably don't want to manually specify this. See LLVM manual for the /// syntax, if you must: pub target_data_layout: String, + /// Specifies the target architecture. + pub target_arch: String, } impl FixtureWithProjectMeta { @@ -178,6 +180,7 @@ impl FixtureWithProjectMeta { let mut toolchain = None; let mut target_data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_owned(); + let mut target_arch = "x86_64".to_owned(); let mut mini_core = None; let mut res: Vec = Vec::new(); let mut proc_macro_names = vec![]; @@ -194,6 +197,12 @@ impl FixtureWithProjectMeta { fixture = remain; } + if let Some(meta) = fixture.strip_prefix("//- target_arch:") { + let (meta, remain) = meta.split_once('\n').unwrap(); + meta.trim().clone_into(&mut target_arch); + fixture = remain; + } + if let Some(meta) = fixture.strip_prefix("//- proc_macros:") { let (meta, remain) = meta.split_once('\n').unwrap(); proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect(); @@ -232,7 +241,14 @@ impl FixtureWithProjectMeta { } } - Self { fixture: res, mini_core, proc_macro_names, toolchain, target_data_layout } + Self { + fixture: res, + mini_core, + proc_macro_names, + toolchain, + target_data_layout, + target_arch, + } } //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo @@ -511,6 +527,7 @@ fn parse_fixture_gets_full_meta() { proc_macro_names, toolchain, target_data_layout: _, + target_arch: _, } = FixtureWithProjectMeta::parse( r#" //- toolchain: nightly From d6638e9bd2b455cf0d3a0df04afc2bab8f134fc9 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 9 Sep 2025 13:49:11 +0300 Subject: [PATCH 175/251] Make `#[target_feature]` safe always on WASM Even when the feature isn't enabled, as it's not UB to invoke an undefined feature in WASM (just a trap). --- .../hir-ty/src/diagnostics/unsafe_check.rs | 24 +++++++++++++++---- .../rust-analyzer/crates/hir-ty/src/lib.rs | 5 +++- .../rust-analyzer/crates/hir-ty/src/utils.rs | 12 ++++++++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 23 ++++++++++++++---- .../src/handlers/missing_unsafe.rs | 16 +++++++++++++ 5 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index d6d669258cc1f..64c4cdeaddf31 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -15,8 +15,9 @@ use hir_def::{ use span::Edition; use crate::{ - InferenceResult, Interner, TargetFeatures, TyExt, TyKind, db::HirDatabase, - utils::is_fn_unsafe_to_call, + InferenceResult, Interner, TargetFeatures, TyExt, TyKind, + db::HirDatabase, + utils::{is_fn_unsafe_to_call, target_feature_is_safe_in_target}, }; #[derive(Debug, Default)] @@ -144,6 +145,9 @@ struct UnsafeVisitor<'db> { def_target_features: TargetFeatures, // FIXME: This needs to be the edition of the span of each call. edition: Edition, + /// On some targets (WASM), calling safe functions with `#[target_feature]` is always safe, even when + /// the target feature is not enabled. This flag encodes that. + target_feature_is_safe: bool, } impl<'db> UnsafeVisitor<'db> { @@ -159,7 +163,12 @@ impl<'db> UnsafeVisitor<'db> { DefWithBodyId::FunctionId(func) => TargetFeatures::from_attrs(&db.attrs(func.into())), _ => TargetFeatures::default(), }; - let edition = resolver.module().krate().data(db).edition; + let krate = resolver.module().krate(); + let edition = krate.data(db).edition; + let target_feature_is_safe = match &krate.workspace_data(db).target { + Ok(target) => target_feature_is_safe_in_target(target), + Err(_) => false, + }; Self { db, infer, @@ -172,6 +181,7 @@ impl<'db> UnsafeVisitor<'db> { callback: unsafe_expr_cb, def_target_features, edition, + target_feature_is_safe, } } @@ -184,7 +194,13 @@ impl<'db> UnsafeVisitor<'db> { } fn check_call(&mut self, node: ExprId, func: FunctionId) { - let unsafety = is_fn_unsafe_to_call(self.db, func, &self.def_target_features, self.edition); + let unsafety = is_fn_unsafe_to_call( + self.db, + func, + &self.def_target_features, + self.edition, + self.target_feature_is_safe, + ); match unsafety { crate::utils::Unsafety::Safe => {} crate::utils::Unsafety::Unsafe => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index c16bbb7b99221..ee352619487c6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -129,7 +129,10 @@ pub use mapping::{ pub use method_resolution::check_orphan_rules; pub use target_feature::TargetFeatures; pub use traits::TraitEnvironment; -pub use utils::{Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call}; +pub use utils::{ + Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call, + target_feature_is_safe_in_target, +}; pub use variance::Variance; pub use chalk_ir::{ diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 881b1c1a9db26..07679d2a119d3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -3,7 +3,10 @@ use std::{cell::LazyCell, iter}; -use base_db::Crate; +use base_db::{ + Crate, + target::{self, TargetData}, +}; use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder}; use hir_def::{ EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, @@ -275,18 +278,23 @@ pub enum Unsafety { DeprecatedSafe2024, } +pub fn target_feature_is_safe_in_target(target: &TargetData) -> bool { + matches!(target.arch, target::Arch::Wasm32 | target::Arch::Wasm64) +} + pub fn is_fn_unsafe_to_call( db: &dyn HirDatabase, func: FunctionId, caller_target_features: &TargetFeatures, call_edition: Edition, + target_feature_is_safe: bool, ) -> Unsafety { let data = db.function_signature(func); if data.is_unsafe() { return Unsafety::Unsafe; } - if data.has_target_feature() { + if data.has_target_feature() && !target_feature_is_safe { // RFC 2396 . let callee_target_features = TargetFeatures::from_attrs_no_implications(&db.attrs(func.into())); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 6eb8a8bf60fd1..3f78a04df1d29 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2542,11 +2542,26 @@ impl Function { caller: Option, call_edition: Edition, ) -> bool { - let target_features = caller - .map(|caller| hir_ty::TargetFeatures::from_attrs(&db.attrs(caller.id.into()))) - .unwrap_or_default(); + let (target_features, target_feature_is_safe_in_target) = caller + .map(|caller| { + let target_features = + hir_ty::TargetFeatures::from_attrs(&db.attrs(caller.id.into())); + let target_feature_is_safe_in_target = + match &caller.krate(db).id.workspace_data(db).target { + Ok(target) => hir_ty::target_feature_is_safe_in_target(target), + Err(_) => false, + }; + (target_features, target_feature_is_safe_in_target) + }) + .unwrap_or_else(|| (hir_ty::TargetFeatures::default(), false)); matches!( - hir_ty::is_fn_unsafe_to_call(db, self.id, &target_features, call_edition), + hir_ty::is_fn_unsafe_to_call( + db, + self.id, + &target_features, + call_edition, + target_feature_is_safe_in_target + ), hir_ty::Unsafety::Unsafe ) } 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 17caf63018256..4bb64747f5bb7 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 @@ -998,4 +998,20 @@ extern "C" fn naked() { "#, ); } + + #[test] + fn target_feature_safe_on_wasm() { + check_diagnostics( + r#" +//- target_arch: wasm32 + +#[target_feature(enable = "simd128")] +fn requires_target_feature() {} + +fn main() { + requires_target_feature(); +} + "#, + ); + } } From 0fad52401e39eba86e8246834a5317b9c8d77652 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 22:54:10 +0000 Subject: [PATCH 176/251] WIP switch inference table to next-solver --- .../crates/hir-ty/src/consteval_nextsolver.rs | 6 +- .../crates/hir-ty/src/infer/closure.rs | 2 +- .../crates/hir-ty/src/infer/coerce.rs | 64 +- .../crates/hir-ty/src/infer/expr.rs | 32 +- .../crates/hir-ty/src/infer/path.rs | 12 +- .../crates/hir-ty/src/infer/unify.rs | 589 ++++++----- .../rust-analyzer/crates/hir-ty/src/lib.rs | 16 +- .../crates/hir-ty/src/method_resolution.rs | 201 ++-- .../infer/canonical/canonicalizer.rs | 785 ++++++++++++++ .../src/next_solver/infer/canonical/mod.rs | 1 + .../hir-ty/src/next_solver/infer/mod.rs | 54 +- .../src/next_solver/infer/snapshot/mod.rs | 4 +- .../crates/hir-ty/src/next_solver/mapping.rs | 965 +++++++++++++++++- .../crates/hir-ty/src/next_solver/solver.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 67 +- .../rust-analyzer/crates/hir/src/attrs.rs | 4 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 12 +- 17 files changed, 2292 insertions(+), 526 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index 4f95c9a13acdb..4700335931549 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -27,7 +27,7 @@ use crate::{ next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, SolverDefId, Ty, ValueConst, - mapping::{ChalkToNextSolver, convert_args_for_result, convert_binder_to_early_binder}, + mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, }, }; @@ -145,7 +145,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option GeneralConstId::StaticId(id), _ => unreachable!(), }; - let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); try_const_usize(db, ec) } @@ -168,7 +168,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), _ => unreachable!(), }; - let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); try_const_isize(db, &ec) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 9ef046afdb3d3..493652b764015 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -568,7 +568,7 @@ impl InferenceContext<'_> { let supplied_sig = self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind); let snapshot = self.table.snapshot(); - if !self.table.unify(&expected_sig.substitution, &supplied_sig.expected_sig.substitution) { + if !self.table.unify::<_, crate::next_solver::GenericArgs<'_>>(&expected_sig.substitution.0, &supplied_sig.expected_sig.substitution.0) { self.table.rollback_to(snapshot); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 631a91bac481b..b47834f0c749c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -7,22 +7,20 @@ use std::iter; -use chalk_ir::{BoundVar, Goal, Mutability, TyKind, TyVariableKind, cast::Cast}; -use hir_def::{hir::ExprId, lang_item::LangItem}; +use chalk_ir::{BoundVar, Mutability, TyKind, TyVariableKind, cast::Cast}; +use hir_def::{ + hir::ExprId, + lang_item::LangItem, +}; +use rustc_type_ir::solve::Certainty; use stdx::always; use triomphe::Arc; use crate::{ - Canonical, DomainGoal, FnAbi, FnPointer, FnSig, InEnvironment, Interner, Lifetime, - Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, - autoderef::{Autoderef, AutoderefKind}, - db::HirDatabase, - infer::{ + autoderef::{Autoderef, AutoderefKind}, db::HirDatabase, infer::{ Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, TypeError, TypeMismatch, - }, - traits::NextTraitSolveResult, - utils::ClosureSubst, + }, utils::ClosureSubst, Canonical, FnAbi, FnPointer, FnSig, Goal, InEnvironment, Interner, Lifetime, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt }; use super::unify::InferenceTable; @@ -42,7 +40,7 @@ fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec { fn success( adj: Vec, target: Ty, - goals: Vec>>, + goals: Vec>, ) -> CoerceResult { Ok(InferOk { goals, value: (adj, target) }) } @@ -304,7 +302,7 @@ impl InferenceTable<'_> { fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty, coerce_never: CoerceNever) -> CoerceResult { if from_ty.is_never() { if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) { - self.set_diverging(*tv, true); + self.set_diverging(*tv, TyVariableKind::General, true); } if coerce_never == CoerceNever::Yes { // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound @@ -707,41 +705,15 @@ impl InferenceTable<'_> { b.push(coerce_from).push(to_ty.clone()).build() }; - let goal: InEnvironment = - InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner)); - - let canonicalized = self.canonicalize_with_free_vars(goal); - - // FIXME: rustc's coerce_unsized is more specialized -- it only tries to - // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the - // rest for later. Also, there's some logic about sized type variables. - // Need to find out in what cases this is necessary - let solution = self.db.trait_solve( - krate, - self.trait_env.block, - canonicalized.value.clone().cast(Interner), - ); - - match solution { - // FIXME: this is a weaker guarantee than Chalk's `Guidance::Unique` - // was. Chalk's unique guidance at least guarantees that the real solution - // is some "subset" of the solutions matching the guidance, but the - // substs for `Certainty::No` don't have that same guarantee (I think). - NextTraitSolveResult::Certain(v) => { - canonicalized.apply_solution( - self, - Canonical { - binders: v.binders, - // FIXME handle constraints - value: v.value.subst, - }, - ); - } - // ...so, should think about how to get some actually get some guidance here - NextTraitSolveResult::Uncertain(..) | NextTraitSolveResult::NoSolution => { - return Err(TypeError); + let goal: Goal = coerce_unsized_tref.cast(Interner); + + self.commit_if_ok(|table| { + match table.solve_obligation(goal) { + Ok(Certainty::Yes) => Ok(()), + Ok(Certainty::Maybe(_)) => Ok(()), + Err(_) => Err(TypeError), } - } + })?; let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 261c02386822d..e39f3ab75f16f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -23,28 +23,9 @@ use stdx::always; use syntax::ast::RangeOp; use crate::{ - Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, - DeclOrigin, IncorrectGenericsLenKind, Interner, Rawness, Scalar, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, - autoderef::{Autoderef, builtin_deref, deref_by_trait}, - consteval, - generics::generics, - infer::{ - BreakableKind, - coerce::{CoerceMany, CoerceNever, CoercionCause}, - find_continuable, - pat::contains_explicit_ref_binding, - }, - lang_items::lang_items_for_bin_op, - lower::{ - LifetimeElisionKind, ParamLoweringMode, lower_to_chalk_mutability, - path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings}, - }, - mapping::{ToChalk, from_chalk}, - method_resolution::{self, VisibleFromModule}, - primitive::{self, UintTy}, - static_lifetime, to_chalk_trait_id, - traits::FnTrait, + autoderef::{builtin_deref, deref_by_trait, Autoderef}, consteval, generics::generics, infer::{ + coerce::{CoerceMany, CoerceNever, CoercionCause}, find_continuable, pat::contains_explicit_ref_binding, BreakableKind + }, lang_items::lang_items_for_bin_op, lower::{lower_to_chalk_mutability, path::{substs_from_args_and_bindings, GenericArgsLowerer, TypeLikeConst}, ParamLoweringMode}, mapping::{from_chalk, ToChalk}, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind }; use super::{ @@ -826,7 +807,7 @@ impl InferenceContext<'_> { let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes); if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) { - let canonicalized = self.canonicalize(base_ty.clone()); + let canonicalized = ChalkToNextSolver::from_nextsolver(self.canonicalize(base_ty.clone().to_nextsolver(self.table.interner)), self.table.interner); let receiver_adjustments = method_resolution::resolve_indexing_op( self.db, self.table.trait_env.clone(), @@ -932,6 +913,7 @@ impl InferenceContext<'_> { } None => { let expected_ty = expected.to_option(&mut self.table); + tracing::debug!(?expected_ty); let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) { Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty, Some(TyKind::Scalar(Scalar::Char)) => { @@ -1678,7 +1660,7 @@ impl InferenceContext<'_> { None => { // no field found, lets attempt to resolve it like a function so that IDE things // work out while people are typing - let canonicalized_receiver = self.canonicalize(receiver_ty.clone()); + let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); let resolved = method_resolution::lookup_method( self.db, &canonicalized_receiver, @@ -1824,7 +1806,7 @@ impl InferenceContext<'_> { expected: &Expectation, ) -> Ty { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes); - let canonicalized_receiver = self.canonicalize(receiver_ty.clone()); + let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); let resolved = method_resolution::lookup_method( self.db, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index bc8648ecdd943..9f3cd2b8fb006 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -10,15 +10,7 @@ use hir_expand::name::Name; use stdx::never; use crate::{ - InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, - TyKind, ValueTyDefId, - builder::ParamKind, - consteval, error_lifetime, - generics::generics, - infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, - lower::LifetimeElisionKind, - method_resolution::{self, VisibleFromModule}, - to_chalk_trait_id, + builder::ParamKind, consteval, error_lifetime, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, to_chalk_trait_id, InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId }; use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; @@ -322,7 +314,7 @@ impl InferenceContext<'_> { return Some(result); } - let canonical_ty = self.canonicalize(ty.clone()); + let canonical_ty = self.canonicalize(ty.clone().to_nextsolver(self.table.interner)); let mut not_visible = None; let res = method_resolution::iterate_method_candidates( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index bb4782bd41942..3745d2c98fd9f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -3,35 +3,27 @@ use std::{fmt, mem}; use chalk_ir::{ - CanonicalVarKind, FloatTy, IntTy, TyVariableKind, UniverseIndex, cast::Cast, - fold::TypeFoldable, interner::HasInterner, zip::Zip, + cast::Cast, fold::TypeFoldable, interner::HasInterner, CanonicalVarKind, FloatTy, IntTy, TyVariableKind, }; -use chalk_solve::infer::ParameterEnaVariableExt; use either::Either; -use ena::unify::UnifyKey; use hir_def::{AdtId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_next_trait_solver::solve::HasChanged; +use rustc_type_ir::{inherent::Span, relate::{solver_relating::RelateExt, Relate}, solve::{Certainty, NoSolution}, FloatVid, IntVid, TyVid}; use smallvec::SmallVec; use triomphe::Arc; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, - GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, - OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, - TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, - consteval::unknown_const, - db::HirDatabase, - fold_generic_args, fold_tys_and_consts, to_chalk_trait_id, - traits::{FnTrait, NextTraitSolveResult}, + consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{infer::{canonical::canonicalizer::OriginalQueryValues, snapshot::CombinedSnapshot, DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, InferenceVarExt}, DbInterner, ParamEnvAnd, SolverDefIds}, to_chalk_trait_id, traits::{next_trait_solve, next_trait_solve_canonical, next_trait_solve_in_ctxt, FnTrait, NextTraitSolveResult}, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause }; -impl InferenceContext<'_> { - pub(super) fn canonicalize(&mut self, t: T) -> Canonical +impl<'db> InferenceContext<'db> { + pub(super) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where - T: TypeFoldable + HasInterner, + T: rustc_type_ir::TypeFoldable>, { self.table.canonicalize(t) } @@ -42,11 +34,11 @@ impl InferenceContext<'_> { ) -> SmallVec<[WhereClause; 4]> { self.table.resolve_obligations_as_possible(); - let root = self.table.var_unification_table.inference_var_root(self_ty); + let root = InferenceVar::from_vid(self.table.infer_ctxt.root_var(self_ty.to_vid())); let pending_obligations = mem::take(&mut self.table.pending_obligations); let obligations = pending_obligations .iter() - .filter_map(|obligation| match obligation.value.value.goal.data(Interner) { + .filter_map(|obligation| match obligation.goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(clause)) => { let ty = match clause { WhereClause::AliasEq(AliasEq { @@ -59,18 +51,9 @@ impl InferenceContext<'_> { WhereClause::TypeOutlives(to) => to.ty.clone(), _ => return None, }; - - let uncanonical = - chalk_ir::Substitute::apply(&obligation.free_vars, ty, Interner); - if matches!( - self.resolve_ty_shallow(&uncanonical).kind(Interner), - TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root, - ) { - Some(chalk_ir::Substitute::apply( - &obligation.free_vars, - clause.clone(), - Interner, - )) + let ty = self.resolve_ty_shallow(&ty); + if matches!(ty.kind(Interner), TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root) { + Some(clause.clone()) } else { None } @@ -229,32 +212,31 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable; #[derive(Clone)] pub(crate) struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, + pub(crate) interner: DbInterner<'a>, pub(crate) trait_env: Arc, pub(crate) tait_coercion_table: Option>, - var_unification_table: ChalkInferenceTable, - type_variable_table: SmallVec<[TypeVariableFlags; 16]>, - pending_obligations: Vec>>, - /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on - /// temporary allocations. - resolve_obligations_buffer: Vec>>, + infer_ctxt: InferCtxt<'a>, + diverging_tys: FxHashSet, + pending_obligations: Vec>, } pub(crate) struct InferenceTableSnapshot { - var_table_snapshot: chalk_solve::infer::InferenceSnapshot, - type_variable_table: SmallVec<[TypeVariableFlags; 16]>, - pending_obligations: Vec>>, + ctxt_snapshot: CombinedSnapshot, + diverging_tys: FxHashSet, + pending_obligations: Vec>, } impl<'a> InferenceTable<'a> { pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { + let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); InferenceTable { db, + interner, trait_env, tait_coercion_table: None, - var_unification_table: ChalkInferenceTable::new(), - type_variable_table: SmallVec::new(), + infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []) }), + diverging_tys: FxHashSet::default(), pending_obligations: Vec::new(), - resolve_obligations_buffer: Vec::new(), } } @@ -265,29 +247,43 @@ impl<'a> InferenceTable<'a> { /// marked as diverging if necessary, so that resolving them gives the right /// result. pub(super) fn propagate_diverging_flag(&mut self) { - for i in 0..self.type_variable_table.len() { - if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) { - continue; + let mut new_tys = FxHashSet::default(); + for ty in self.diverging_tys.iter() { + match ty.kind(Interner) { + TyKind::InferenceVar(var, kind) => { + match kind { + TyVariableKind::General => { + let root = InferenceVar::from(self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32()); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); + } + } + TyVariableKind::Integer => { + let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from_usize(var.index() as usize)).as_u32()); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); + } + } + TyVariableKind::Float => { + let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from_usize(var.index() as usize)).as_u32()); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); + } + } + } + } + _ => {} } - let v = InferenceVar::from(i as u32); - let root = self.var_unification_table.inference_var_root(v); - self.modify_type_variable_flag(root, |f| { - *f |= TypeVariableFlags::DIVERGING; - }); } + self.diverging_tys.extend(new_tys.into_iter()); } - pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { - self.modify_type_variable_flag(iv, |f| { - f.set(TypeVariableFlags::DIVERGING, diverging); - }); + pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind, diverging: bool) { + self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner)); } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - let is_diverging = self - .type_variable_table - .get(iv.index() as usize) - .is_some_and(|data| data.contains(TypeVariableFlags::DIVERGING)); + let is_diverging = self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); if is_diverging { return TyKind::Never.intern(Interner); } @@ -299,30 +295,27 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize_with_free_vars(&mut self, t: T) -> Canonicalized + pub(crate) fn canonicalize_with_free_vars(&mut self, t: ParamEnvAnd<'a, T>) -> (rustc_type_ir::Canonical, ParamEnvAnd<'a, T>>, OriginalQueryValues<'a>) where - T: TypeFoldable + HasInterner, + T: rustc_type_ir::TypeFoldable>, { // try to resolve obligations before canonicalizing, since this might // result in new knowledge about variables self.resolve_obligations_as_possible(); - let result = self.var_unification_table.canonicalize(Interner, t); - let free_vars = result - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(Interner)) - .collect(); - Canonicalized { value: result.quantified, free_vars } + + let mut orig_values = OriginalQueryValues::default(); + let result = self.infer_ctxt.canonicalize_query(t, &mut orig_values); + (result.canonical, orig_values) } - pub(crate) fn canonicalize(&mut self, t: T) -> Canonical + pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where - T: TypeFoldable + HasInterner, + T: rustc_type_ir::TypeFoldable>, { // try to resolve obligations before canonicalizing, since this might // result in new knowledge about variables self.resolve_obligations_as_possible(); - self.var_unification_table.canonicalize(Interner, t).quantified + self.infer_ctxt.canonicalize_response(t) } /// Recurses through the given type, normalizing associated types mentioned @@ -348,6 +341,7 @@ impl<'a> InferenceTable<'a> { self.resolve_ty_shallow(&ty) } TyKind::AssociatedType(id, subst) => { + return Either::Left(self.resolve_ty_shallow(&ty)); if ty.data(Interner).flags.intersects( chalk_ir::TypeFlags::HAS_TY_INFER | chalk_ir::TypeFlags::HAS_CT_INFER, @@ -370,21 +364,24 @@ impl<'a> InferenceTable<'a> { )), ); let in_env = InEnvironment::new(&self.trait_env.env, goal); + let goal = in_env.to_nextsolver(self.interner); + let goal = ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; - let canonicalized = { - let result = - self.var_unification_table.canonicalize(Interner, in_env); - let free_vars = result - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(Interner)) - .collect(); - Canonicalized { value: result.quantified, free_vars } + let (canonical_goal, _orig_values) = { + let mut orig_values = OriginalQueryValues::default(); + let result = self.infer_ctxt.canonicalize_query(goal, &mut orig_values); + (result.canonical, orig_values) + }; + let canonical_goal = rustc_type_ir::Canonical { + max_universe: canonical_goal.max_universe, + variables: canonical_goal.variables, + value: crate::next_solver::Goal { param_env: canonical_goal.value.param_env, predicate: canonical_goal.value.value }, }; - let solution = self.db.trait_solve( + let solution = next_trait_solve_canonical( + self.db, self.trait_env.krate, self.trait_env.block, - canonicalized.value.clone(), + canonical_goal.clone(), ); if let NextTraitSolveResult::Certain(canonical_subst) = solution { // This is not great :) But let's just assert this for now and come back to it later. @@ -512,38 +509,27 @@ impl<'a> InferenceTable<'a> { var } - fn modify_type_variable_flag(&mut self, var: InferenceVar, cb: F) - where - F: FnOnce(&mut TypeVariableFlags), - { - let idx = var.index() as usize; - if self.type_variable_table.len() <= idx { - self.extend_type_variable_table(idx); - } - if let Some(f) = self.type_variable_table.get_mut(idx) { - cb(f); - } - } - fn extend_type_variable_table(&mut self, to_index: usize) { - let count = to_index - self.type_variable_table.len() + 1; - self.type_variable_table.extend(std::iter::repeat_n(TypeVariableFlags::default(), count)); - } - fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); - // Chalk might have created some type variables for its own purposes that we don't know about... - self.extend_type_variable_table(var.index() as usize); - assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); - let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap(); + let var = match kind { + TyVariableKind::General => { + let var = self.infer_ctxt.next_ty_vid(); + InferenceVar::from(var.as_u32()) + } + TyVariableKind::Integer => { + let var = self.infer_ctxt.next_int_vid(); + InferenceVar::from(var.as_u32()) + } + TyVariableKind::Float => { + let var = self.infer_ctxt.next_float_vid(); + InferenceVar::from(var.as_u32()) + } + }; + + let ty = var.to_ty(Interner, kind); if diverging { - *flags |= TypeVariableFlags::DIVERGING; - } - if matches!(kind, TyVariableKind::Integer) { - *flags |= TypeVariableFlags::INTEGER; - } else if matches!(kind, TyVariableKind::Float) { - *flags |= TypeVariableFlags::FLOAT; + self.diverging_tys.insert(ty.clone()); } - var.to_ty_with_kind(Interner, kind) + ty } pub(crate) fn new_type_var(&mut self) -> Ty { @@ -563,12 +549,14 @@ impl<'a> InferenceTable<'a> { } pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); + let var = self.infer_ctxt.next_const_vid(); + let var = InferenceVar::from(var.as_u32()); var.to_const(Interner, ty) } pub(crate) fn new_lifetime_var(&mut self) -> Lifetime { - let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); + let var = self.infer_ctxt.next_region_vid(); + let var = InferenceVar::from(var.as_u32()); var.to_lifetime(Interner) } @@ -580,16 +568,16 @@ impl<'a> InferenceTable<'a> { where T: HasInterner + TypeFoldable, { - self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback) + self.resolve_with_fallback_inner(t, &fallback) } pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind]) -> Substitution { Substitution::from_iter( Interner, - binders.iter().map(|kind| { - let param_infer_var = - kind.map_ref(|&ui| self.var_unification_table.new_variable(ui)); - param_infer_var.to_generic_arg(Interner) + binders.iter().map(|kind| match &kind.kind { + chalk_ir::VariableKind::Ty(ty_variable_kind) => self.new_var(*ty_variable_kind, false).cast(Interner), + chalk_ir::VariableKind::Lifetime => self.new_lifetime_var().cast(Interner), + chalk_ir::VariableKind::Const(ty) => self.new_const_var(ty.clone()).cast(Interner), }), ) } @@ -601,16 +589,23 @@ impl<'a> InferenceTable<'a> { let subst = self.fresh_subst(canonical.binders.as_slice(Interner)); subst.apply(canonical.value, Interner) } + + pub(crate) fn instantiate_canonical_ns(&mut self, canonical: rustc_type_ir::Canonical, T>) -> T + where + T: rustc_type_ir::TypeFoldable>, + { + self.infer_ctxt.instantiate_canonical(&canonical).0 + } fn resolve_with_fallback_inner( &mut self, - var_stack: &mut Vec, t: T, fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, ) -> T where T: HasInterner + TypeFoldable, { + let mut var_stack = &mut vec![]; t.fold_with( &mut resolve::Resolver { table: self, var_stack, fallback }, DebruijnIndex::INNERMOST, @@ -639,29 +634,26 @@ impl<'a> InferenceTable<'a> { let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner); let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner); - let scalar_vars: Vec<_> = self - .type_variable_table - .iter() - .enumerate() - .filter_map(|(index, flags)| { - let kind = if flags.contains(TypeVariableFlags::INTEGER) { - TyVariableKind::Integer - } else if flags.contains(TypeVariableFlags::FLOAT) { - TyVariableKind::Float - } else { - return None; + let int_vars = self.infer_ctxt.inner.borrow_mut().int_unification_table().len(); + for v in 0..int_vars { + let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer); + let maybe_resolved = self.resolve_ty_shallow(&var); + if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { + // I don't think we can ever unify these vars with float vars, but keep this here for now + let fallback = match kind { + TyVariableKind::Integer => &int_fallback, + TyVariableKind::Float => &float_fallback, + TyVariableKind::General => unreachable!(), }; - - // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them - // without directly constructing them from `index`? - let var = InferenceVar::from(index as u32).to_ty(Interner, kind); - Some(var) - }) - .collect(); - - for var in scalar_vars { + self.unify(&var, fallback); + } + } + let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len(); + for v in 0..float_vars { + let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer); let maybe_resolved = self.resolve_ty_shallow(&var); if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { + // I don't think we can ever unify these vars with float vars, but keep this here for now let fallback = match kind { TyVariableKind::Integer => &int_fallback, TyVariableKind::Float => &float_fallback, @@ -673,7 +665,7 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - pub(crate) fn unify>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify, U: Relate>>(&mut self, ty1: &T, ty2: &T) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, @@ -683,58 +675,65 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled - pub(crate) fn unify_deeply>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify_deeply, U: Relate>>(&mut self, ty1: &T, ty2: &T) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, }; result.goals.iter().all(|goal| { - let canonicalized = self.canonicalize_with_free_vars(goal.clone()); - self.try_resolve_obligation(&canonicalized).certain() + let goal = goal.to_nextsolver(self.interner); + match next_trait_solve_in_ctxt(&self.infer_ctxt, goal) { + Ok((_, Certainty::Yes)) => true, + _ => false, + } }) } /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the /// caller needs to deal with them. - pub(crate) fn try_unify>( + pub(crate) fn try_unify, U: Relate>>( &mut self, t1: &T, t2: &T, ) -> InferResult<()> { - match self.var_unification_table.relate( - Interner, - &self.db, - &self.trait_env.env, - chalk_ir::Variance::Invariant, - t1, - t2, - ) { - Ok(result) => Ok(InferOk { goals: result.goals, value: () }), - Err(chalk_ir::NoSolution) => Err(TypeError), + let param_env = self.trait_env.env.to_nextsolver(self.interner); + let lhs = t1.to_nextsolver(self.interner); + let rhs = t2.to_nextsolver(self.interner); + let variance = rustc_type_ir::Variance::Invariant; + let span = crate::next_solver::Span::dummy(); + match self.infer_ctxt.relate(param_env, lhs, variance, rhs, span) { + Ok(res) => { + let goals = res.into_iter().map(|g| ChalkToNextSolver::from_nextsolver(g, self.interner)).collect(); + Ok(InferOk { goals, value: () }) + } + Err(_) => { + Err(TypeError) + } } } /// If `ty` is a type variable with known type, returns that type; /// otherwise, return ty. + #[tracing::instrument(skip(self))] pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) { return ty.clone(); } self.resolve_obligations_as_possible(); - self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone()) + ChalkToNextSolver::from_nextsolver(self.infer_ctxt.resolve_vars_if_possible(ty.to_nextsolver(self.interner)), self.interner) } pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { - let var_table_snapshot = self.var_unification_table.snapshot(); - let type_variable_table = self.type_variable_table.clone(); + let ctxt_snapshot = self.infer_ctxt.start_snapshot(); + let diverging_tys = self.diverging_tys.clone(); let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table } + InferenceTableSnapshot {ctxt_snapshot, pending_obligations, diverging_tys } } #[tracing::instrument(skip_all)] pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { - self.var_unification_table.rollback_to(snapshot.var_table_snapshot); - self.type_variable_table = snapshot.type_variable_table; + self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); + self.diverging_tys = snapshot.diverging_tys; self.pending_obligations = snapshot.pending_obligations; } @@ -746,15 +745,39 @@ impl<'a> InferenceTable<'a> { result } + pub(crate) fn commit_if_ok(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> Result) -> Result { + let snapshot = self.snapshot(); + let result = f(self); + match result { + Ok(_) => {} + Err(_) => { + self.rollback_to(snapshot); + } + } + result + } + /// Checks an obligation without registering it. Useful mostly to check /// whether a trait *might* be implemented before deciding to 'lock in' the /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult { let in_env = InEnvironment::new(&self.trait_env.env, goal); - let canonicalized = self.canonicalize(in_env); + let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner)); - self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized) + next_trait_solve_canonical(self.db, self.trait_env.krate, self.trait_env.block, canonicalized) + } + + #[tracing::instrument(level = "debug", skip(self))] + pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result { + let goal = InEnvironment::new(&self.trait_env.env, goal); + let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { + return Ok(Certainty::Yes); + }; + + let goal = goal.to_nextsolver(self.interner); + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); + result.map(|m| m.1) } pub(crate) fn register_obligation(&mut self, goal: Goal) { @@ -762,8 +785,8 @@ impl<'a> InferenceTable<'a> { self.register_obligation_in_env(in_env) } - #[tracing::instrument(level = "debug", skip(self))] - fn register_obligation_in_env(&mut self, goal: InEnvironment) { + // If this goal is an `AliasEq` for an opaque type, just unify instead of trying to solve (since the next-solver is lazy) + fn unify_opaque_instead_of_solve(&mut self, goal: InEnvironment) -> Option> { match goal.goal.data(Interner) { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), @@ -779,7 +802,7 @@ impl<'a> InferenceTable<'a> { .intern(Interner), ty, ) { - return; + return None; } } _ => {} @@ -788,20 +811,20 @@ impl<'a> InferenceTable<'a> { } _ => {} } - let canonicalized = { - let result = self.var_unification_table.canonicalize(Interner, goal); - let free_vars = result - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(Interner)) - .collect(); - Canonicalized { value: result.quantified, free_vars } - }; - tracing::debug!(?canonicalized); - let solution = self.try_resolve_obligation(&canonicalized); - tracing::debug!(?solution); - if solution.uncertain() { - self.pending_obligations.push(canonicalized); + Some(goal) + } + + #[tracing::instrument(level = "debug", skip(self))] + fn register_obligation_in_env(&mut self, goal: InEnvironment) { + let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { return }; + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + tracing::debug!(?result); + match result { + Ok((_, Certainty::Yes)) => {} + Err(rustc_type_ir::solve::NoSolution) => {} + Ok((_, Certainty::Maybe(_))) => { + self.pending_obligations.push(goal); + } } } @@ -812,28 +835,35 @@ impl<'a> InferenceTable<'a> { pub(crate) fn resolve_obligations_as_possible(&mut self) { let _span = tracing::info_span!("resolve_obligations_as_possible").entered(); let mut changed = true; - let mut obligations = mem::take(&mut self.resolve_obligations_buffer); while mem::take(&mut changed) { - mem::swap(&mut self.pending_obligations, &mut obligations); + let mut obligations = mem::take(&mut self.pending_obligations); - for canonicalized in obligations.drain(..) { - tracing::debug!(obligation = ?canonicalized); - if !self.check_changed(&canonicalized) { - tracing::debug!("not changed"); - self.pending_obligations.push(canonicalized); + for goal in obligations.drain(..) { + tracing::debug!(obligation = ?goal); + + let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { + changed = true; continue; + }; + + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + let (has_changed, certainty) = match result { + Ok(result) => result, + Err(_) => { + continue; + } + }; + + if matches!(has_changed, HasChanged::Yes) { + changed = true; + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => self.pending_obligations.push(goal), } - changed = true; - let uncanonical = chalk_ir::Substitute::apply( - &canonicalized.free_vars, - canonicalized.value.value, - Interner, - ); - self.register_obligation_in_env(uncanonical); } } - self.resolve_obligations_buffer = obligations; - self.resolve_obligations_buffer.clear(); } pub(crate) fn fudge_inference>( @@ -904,32 +934,13 @@ impl<'a> InferenceTable<'a> { .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST) } - /// This checks whether any of the free variables in the `canonicalized` - /// have changed (either been unified with another variable, or with a - /// value). If this is not the case, we don't need to try to solve the goal - /// again -- it'll give the same result as last time. - fn check_changed(&mut self, canonicalized: &Canonicalized>) -> bool { - canonicalized.free_vars.iter().any(|var| { - let iv = match var.data(Interner) { - GenericArgData::Ty(ty) => ty.inference_var(Interner), - GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - GenericArgData::Const(c) => c.inference_var(Interner), - } - .expect("free var is not inference var"); - if self.var_unification_table.probe_var(iv).is_some() { - return true; - } - let root = self.var_unification_table.inference_var_root(iv); - iv != root - }) - } - #[tracing::instrument(level = "debug", skip(self))] fn try_resolve_obligation( &mut self, canonicalized: &Canonicalized>, ) -> NextTraitSolveResult { - let solution = self.db.trait_solve( + let solution = next_trait_solve( + self.db, self.trait_env.krate, self.trait_env.block, canonicalized.value.clone(), @@ -1014,33 +1025,15 @@ impl<'a> InferenceTable<'a> { .fill_with_unknown() .build(); - let trait_env = self.trait_env.env.clone(); - let obligation = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if !self - .db - .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .no_solution() - { - self.register_obligation(obligation.goal); + let goal: Goal = trait_ref.clone().cast(Interner); + if !self.try_obligation(goal.clone()).no_solution() { + self.register_obligation(goal); let return_ty = self.normalize_projection_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let obligation: chalk_ir::InEnvironment> = - InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if !self - .db - .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .no_solution() - { + let goal = trait_ref.clone().cast(Interner); + if !self.try_obligation(goal).no_solution() { return Some((fn_x, arg_tys, return_ty)); } } @@ -1165,20 +1158,26 @@ impl<'a> InferenceTable<'a> { impl fmt::Debug for InferenceTable<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish() + f.debug_struct("InferenceTable").finish() } } mod resolve { use super::InferenceTable; use crate::{ - ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, - InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind, + next_solver::mapping::ChalkToNextSolver, ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind }; use chalk_ir::{ cast::Cast, fold::{TypeFoldable, TypeFolder}, }; + use rustc_type_ir::{FloatVid, IntVid, TyVid}; + + #[derive(Copy, Clone, PartialEq, Eq)] + pub(super) enum VarKind { + Ty(TyVariableKind), + Const, + } #[derive(chalk_derive::FallibleTypeFolder)] #[has_interner(Interner)] @@ -1188,7 +1187,7 @@ mod resolve { F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, > { pub(super) table: &'a mut InferenceTable<'b>, - pub(super) var_stack: &'a mut Vec, + pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>, pub(super) fallback: F, } impl TypeFolder for Resolver<'_, '_, F> @@ -1209,25 +1208,79 @@ mod resolve { kind: TyVariableKind, outer_binder: DebruijnIndex, ) -> Ty { - let var = self.table.var_unification_table.inference_var_root(var); - if self.var_stack.contains(&var) { - // recursive type - let default = self.table.fallback_value(var, kind).cast(Interner); - return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) - .assert_ty_ref(Interner) - .clone(); - } - if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { - // known_ty may contain other variables that are known by now - self.var_stack.push(var); - let result = known_ty.fold_with(self, outer_binder); - self.var_stack.pop(); - result.assert_ty_ref(Interner).clone() - } else { - let default = self.table.fallback_value(var, kind).cast(Interner); - (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) - .assert_ty_ref(Interner) - .clone() + match kind { + TyVariableKind::General => { + let vid = self.table.infer_ctxt.root_var(TyVid::from(var.index())); + let var = InferenceVar::from(vid.as_u32()); + if self.var_stack.contains(&(var, VarKind::Ty(kind))) { + // recursive type + let default = self.table.fallback_value(var, kind).cast(Interner); + return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone(); + } + if let Ok(known_ty) = self.table.infer_ctxt.probe_ty_var(vid) { + let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + // known_ty may contain other variables that are known by now + self.var_stack.push((var, VarKind::Ty(kind))); + let result = known_ty.fold_with(self, outer_binder); + self.var_stack.pop(); + result + } else { + let default = self.table.fallback_value(var, kind).cast(Interner); + (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone() + } + } + TyVariableKind::Integer => { + let vid = self.table.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from(var.index())); + let var = InferenceVar::from(vid.as_u32()); + if self.var_stack.contains(&(var, VarKind::Ty(kind))) { + // recursive type + let default = self.table.fallback_value(var, kind).cast(Interner); + return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone(); + } + if let Some(known_ty) = self.table.infer_ctxt.resolve_int_var(vid) { + let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + // known_ty may contain other variables that are known by now + self.var_stack.push((var, VarKind::Ty(kind))); + let result = known_ty.fold_with(self, outer_binder); + self.var_stack.pop(); + result + } else { + let default = self.table.fallback_value(var, kind).cast(Interner); + (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone() + } + } + TyVariableKind::Float => { + let vid = self.table.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from(var.index())); + let var = InferenceVar::from(vid.as_u32()); + if self.var_stack.contains(&(var, VarKind::Ty(kind))) { + // recursive type + let default = self.table.fallback_value(var, kind).cast(Interner); + return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone(); + } + if let Some(known_ty) = self.table.infer_ctxt.resolve_float_var(vid) { + let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + // known_ty may contain other variables that are known by now + self.var_stack.push((var, VarKind::Ty(kind))); + let result = known_ty.fold_with(self, outer_binder); + self.var_stack.pop(); + result + } else { + let default = self.table.fallback_value(var, kind).cast(Interner); + (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(Interner) + .clone() + } + } } } @@ -1237,25 +1290,27 @@ mod resolve { var: InferenceVar, outer_binder: DebruijnIndex, ) -> Const { - let var = self.table.var_unification_table.inference_var_root(var); + let vid = self.table.infer_ctxt.root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); + let var = InferenceVar::from(vid.as_u32()); let default = ConstData { ty: ty.clone(), value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }), } .intern(Interner) .cast(Interner); - if self.var_stack.contains(&var) { + if self.var_stack.contains(&(var, VarKind::Const)) { // recursive return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) .assert_const_ref(Interner) .clone(); } - if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { + if let Ok(known_const) = self.table.infer_ctxt.probe_const_var(vid) { + let known_const: Const = ChalkToNextSolver::from_nextsolver(known_const, self.table.interner); // known_ty may contain other variables that are known by now - self.var_stack.push(var); - let result = known_ty.fold_with(self, outer_binder); + self.var_stack.push((var, VarKind::Const)); + let result = known_const.fold_with(self, outer_binder); self.var_stack.pop(); - result.assert_const_ref(Interner).clone() + result } else { (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) .assert_const_ref(Interner) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index c16bbb7b99221..323ea951a9141 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -957,23 +957,13 @@ pub fn callable_sig_from_fn_trait( ) .build(); - let block = trait_env.block; - let trait_env = trait_env.env.clone(); - let obligation = - InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() }; - let canonical = table.canonicalize(obligation.clone()); - if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() { - table.register_obligation(obligation.goal); + if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { + table.register_obligation(trait_ref.clone().cast(Interner)); let return_ty = table.normalize_projection_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let obligation: chalk_ir::InEnvironment> = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = table.canonicalize(obligation.clone()); - if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() { + if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { let ret_ty = table.resolve_completely(return_ty); let args_ty = table.resolve_completely(args_ty); let params = args_ty diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index f0be352fdd151..ee223059d1e56 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -16,25 +16,13 @@ use hir_def::{ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::{IntoKind, SliceLike}; +use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _}; use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; use crate::{ - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, - Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, - TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause, - autoderef::{self, AutoderefKind}, - db::HirDatabase, - error_lifetime, from_chalk_trait_id, from_foreign_def_id, - infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, - lang_items::is_box, - next_solver::SolverDefId, - primitive::{FloatTy, IntTy, UintTy}, - to_chalk_trait_id, - traits::NextTraitSolveResult, - utils::all_super_traits, + autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, lang_items::is_box, next_solver::{mapping::ChalkToNextSolver, SolverDefId}, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, traits::{next_trait_solve_canonical}, utils::all_super_traits, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause }; /// This is used as a key for indexing impls. @@ -533,9 +521,9 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option, +pub(crate) fn lookup_method<'db>( + db: &'db dyn HirDatabase, + ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -697,9 +685,9 @@ impl ReceiverAdjustments { // This would be nicer if it just returned an iterator, but that runs into // lifetime problems, because we need to borrow temp `CrateImplDefs`. // FIXME add a context type here? -pub(crate) fn iterate_method_candidates( - ty: &Canonical, - db: &dyn HirDatabase, +pub(crate) fn iterate_method_candidates<'db, T>( + ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -1046,9 +1034,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { is_not_orphan } -pub fn iterate_path_candidates( - ty: &Canonical, - db: &dyn HirDatabase, +pub fn iterate_path_candidates<'db>( + ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -1068,9 +1056,9 @@ pub fn iterate_path_candidates( ) } -pub fn iterate_method_candidates_dyn( - ty: &Canonical, - db: &dyn HirDatabase, +pub fn iterate_method_candidates_dyn<'db>( + ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -1108,7 +1096,7 @@ pub fn iterate_method_candidates_dyn( // types*. let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical(ty.clone()); + let ty = table.instantiate_canonical_ns(ty.clone()); let deref_chain = autoderef_method_receiver(&mut table, ty); deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| { @@ -1139,20 +1127,22 @@ pub fn iterate_method_candidates_dyn( } #[tracing::instrument(skip_all, fields(name = ?name))] -fn iterate_method_candidates_with_autoref( - table: &mut InferenceTable<'_>, - receiver_ty: Canonical, +fn iterate_method_candidates_with_autoref<'db>( + table: &mut InferenceTable<'db>, + receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, first_adjustment: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { - if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) { + if matches!(receiver_ty.value.kind(), rustc_type_ir::TyKind::Bound(..)) { // don't try to resolve methods on unknown types return ControlFlow::Continue(()); } + let interner = table.interner; + let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| { iterate_method_candidates_by_receiver( table, @@ -1166,7 +1156,11 @@ fn iterate_method_candidates_with_autoref( }; let mut maybe_reborrowed = first_adjustment.clone(); - if let Some((_, _, m)) = receiver_ty.value.as_reference() { + if let rustc_type_ir::TyKind::Ref(_, _, m) = receiver_ty.value.kind() { + let m = match m { + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + }; // Prefer reborrow of references to move maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m)); maybe_reborrowed.autoderefs += 1; @@ -1174,10 +1168,10 @@ fn iterate_method_candidates_with_autoref( iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?; - let refed = Canonical { - value: TyKind::Ref(Mutability::Not, error_lifetime(), receiver_ty.value.clone()) - .intern(Interner), - binders: receiver_ty.binders.clone(), + let refed = crate::next_solver::Canonical { + max_universe: receiver_ty.max_universe, + variables: receiver_ty.variables, + value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Not), }; iterate_method_candidates_by_receiver( @@ -1185,10 +1179,10 @@ fn iterate_method_candidates_with_autoref( first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)), )?; - let ref_muted = Canonical { - value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone()) - .intern(Interner), - binders: receiver_ty.binders.clone(), + let ref_muted = crate::next_solver::Canonical { + max_universe: receiver_ty.max_universe, + variables: receiver_ty.variables, + value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Mut), }; iterate_method_candidates_by_receiver( @@ -1196,10 +1190,11 @@ fn iterate_method_candidates_with_autoref( first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)), )?; - if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() { - let const_ptr_ty = Canonical { - value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner), - binders: receiver_ty.binders, + if let rustc_type_ir::TyKind::RawPtr(ty, rustc_ast_ir::Mutability::Mut) = receiver_ty.value.kind() { + let const_ptr_ty = rustc_type_ir::Canonical { + max_universe: rustc_type_ir::UniverseIndex::ZERO, + value: crate::next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not), + variables: receiver_ty.variables, }; iterate_method_candidates_by_receiver( const_ptr_ty, @@ -1250,16 +1245,17 @@ where } #[tracing::instrument(skip_all, fields(name = ?name))] -fn iterate_method_candidates_by_receiver( - table: &mut InferenceTable<'_>, - receiver_ty: Canonical, +fn iterate_method_candidates_by_receiver<'db>( + table: &mut InferenceTable<'db>, + receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, receiver_adjustments: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { - let receiver_ty = table.instantiate_canonical(receiver_ty); + let receiver_ty = table.instantiate_canonical_ns(receiver_ty); + let receiver_ty: crate::Ty = ChalkToNextSolver::from_nextsolver(receiver_ty, table.interner); // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that, including raw derefs. @@ -1307,9 +1303,9 @@ fn iterate_method_candidates_by_receiver( } #[tracing::instrument(skip_all, fields(name = ?name))] -fn iterate_method_candidates_for_self_ty( - self_ty: &Canonical, - db: &dyn HirDatabase, +fn iterate_method_candidates_for_self_ty<'db>( + self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -1317,7 +1313,7 @@ fn iterate_method_candidates_for_self_ty( callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { let mut table = InferenceTable::new(db, env); - let self_ty = table.instantiate_canonical(self_ty.clone()); + let self_ty = ChalkToNextSolver::from_nextsolver(table.instantiate_canonical_ns(self_ty.clone()), table.interner); iterate_inherent_methods( &self_ty, &mut table, @@ -1354,7 +1350,7 @@ fn iterate_trait_method_candidates( ) -> ControlFlow<()> { let db = table.db; - let canonical_self_ty = table.canonicalize(self_ty.clone()); + let canonical_self_ty = ChalkToNextSolver::from_nextsolver(table.canonicalize(self_ty.clone().to_nextsolver(table.interner)), table.interner); let TraitEnvironment { krate, block, .. } = *table.trait_env; 'traits: for &t in traits_in_scope { @@ -1583,13 +1579,14 @@ pub(crate) fn resolve_indexing_op( ) -> Option { let mut table = InferenceTable::new(db, env); let ty = table.instantiate_canonical(ty); - let deref_chain = autoderef_method_receiver(&mut table, ty); + let interner = table.interner; + let deref_chain = autoderef_method_receiver(&mut table, ty.to_nextsolver(interner)); for (ty, adj) in deref_chain { - let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty); - if !db - .trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner)) - .no_solution() - { + //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty); + let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ChalkToNextSolver::from_nextsolver(ty, interner)); + let goal: chalk_ir::Canonical>> = goal.cast(Interner); + let goal = goal.to_nextsolver(interner); + if !next_trait_solve_canonical(db, table.trait_env.krate, table.trait_env.block, goal).no_solution() { return Some(adj); } } @@ -1773,26 +1770,11 @@ fn is_valid_impl_fn_candidate( }); for goal in goals.clone() { - let in_env = InEnvironment::new(&table.trait_env.env, goal); - let canonicalized = table.canonicalize_with_free_vars(in_env); - let solution = table.db.trait_solve( - table.trait_env.krate, - table.trait_env.block, - canonicalized.value.clone(), - ); - - match solution { - NextTraitSolveResult::Certain(canonical_subst) => { - canonicalized.apply_solution( - table, - Canonical { - binders: canonical_subst.binders, - value: canonical_subst.value.subst, - }, - ); + match table.solve_obligation(goal) { + Ok(_) => {} + Err(_) => { + return IsValidCandidate::No; } - NextTraitSolveResult::Uncertain(..) => {} - NextTraitSolveResult::NoSolution => return IsValidCandidate::No, } } @@ -1857,25 +1839,66 @@ fn generic_implements_goal( Canonical { binders, value } } -fn autoderef_method_receiver( - table: &mut InferenceTable<'_>, - ty: Ty, -) -> Vec<(Canonical, ReceiverAdjustments)> { - let mut deref_chain: Vec<_> = Vec::new(); - let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true); +/* +/// This creates Substs for a trait with the given Self type and type variables +/// for all other parameters, to query the trait solver with it. +#[tracing::instrument(skip_all)] +fn generic_implements_goal_ns<'db>( + db: &'db dyn HirDatabase, + interner: DbInterner<'db>, + env: &TraitEnvironment, + trait_: TraitId, + self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, +) -> crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> { + let variables = self_ty.variables; + let trait_ref = TyBuilder::trait_ref(db, trait_) + .push(ChalkToNextSolver::from_nextsolver(self_ty.value, interner)) + .fill_with_bound_vars(DebruijnIndex::INNERMOST, variables.len()) + .build(); + + let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let args = infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_)); + + rustc_type_ir::TraitRef::new(interner, SolverDefId::TraitId(trait_)).with_self_ty(interner, self_ty.value); + + + let kinds = + binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| { + let vk = match it.data(Interner) { + GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General), + GenericArgData::Lifetime(_) => VariableKind::Lifetime, + GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()), + }; + WithKind::new(vk, UniverseIndex::ROOT) + })); + let binders = CanonicalVarKinds::from_iter(Interner, kinds); + + let obligation = trait_ref.cast(Interner); + let value = InEnvironment::new(&env.env, obligation); + crate::next_solver::Canonical { max_universe, value, variables } +} +*/ + +fn autoderef_method_receiver<'db>( + table: &mut InferenceTable<'db>, + ty: crate::next_solver::Ty<'db>, +) -> Vec<(crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> { + let interner = table.interner; + let mut deref_chain = Vec::new(); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ChalkToNextSolver::from_nextsolver(ty, interner), false, true); while let Some((ty, derefs)) = autoderef.next() { deref_chain.push(( - autoderef.table.canonicalize(ty), + autoderef.table.canonicalize(ty.to_nextsolver(interner)), ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false }, )); } // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) - if let Some((TyKind::Array(parameters, _), binders, adj)) = - deref_chain.last().map(|(ty, adj)| (ty.value.kind(Interner), ty.binders.clone(), adj)) + if let Some((rustc_type_ir::Array(parameters, _), variables, max_universe, adj)) = + deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables.clone(), d.0.max_universe, d.1.clone())) { - let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner); + let unsized_ty = crate::next_solver::Ty::new_slice(interner, parameters); deref_chain.push(( - Canonical { value: unsized_ty, binders }, + crate::next_solver::Canonical { max_universe, value: unsized_ty, variables, }, ReceiverAdjustments { unsize_array: true, ..adj.clone() }, )); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs new file mode 100644 index 0000000000000..0820006e5dfb0 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -0,0 +1,785 @@ + +use rustc_hash::FxHashMap; +use rustc_index::Idx; +use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _}; +use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar}; +use rustc_type_ir::{BoundVar, CanonicalQueryInput, CanonicalTyVarKind, DebruijnIndex, Flags, InferConst, RegionKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex}; +use smallvec::SmallVec; +use tracing::debug; + +use crate::next_solver::infer::InferCtxt; +use crate::next_solver::{Binder, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty, TyKind}; + +/// When we canonicalize a value to form a query, we wind up replacing +/// various parts of it with canonical variables. This struct stores +/// those replaced bits to remember for when we process the query +/// result. +#[derive(Clone, Debug)] +pub struct OriginalQueryValues<'db> { + /// Map from the universes that appear in the query to the universes in the + /// caller context. For all queries except `evaluate_goal` (used by Chalk), + /// we only ever put ROOT values into the query, so this map is very + /// simple. + pub universe_map: SmallVec<[UniverseIndex; 4]>, + + /// This is equivalent to `CanonicalVarValues`, but using a + /// `SmallVec` yields a significant performance win. + pub var_values: SmallVec<[GenericArg<'db>; 8]>, +} + +impl<'db> Default for OriginalQueryValues<'db> { + fn default() -> Self { + let mut universe_map = SmallVec::default(); + universe_map.push(UniverseIndex::ROOT); + + Self { universe_map, var_values: SmallVec::default() } + } +} + +impl<'db> InferCtxt<'db> { + /// Canonicalizes a query value `V`. When we canonicalize a query, + /// we not only canonicalize unbound inference variables, but we + /// *also* replace all free regions whatsoever. So for example a + /// query like `T: Trait<'static>` would be canonicalized to + /// + /// ```text + /// T: Trait<'?0> + /// ``` + /// + /// with a mapping M that maps `'?0` to `'static`. + /// + /// To get a good understanding of what is happening here, check + /// out the [chapter in the rustc dev guide][c]. + /// + /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query + pub fn canonicalize_query( + &self, + value: ParamEnvAnd<'db, V>, + query_state: &mut OriginalQueryValues<'db>, + ) -> CanonicalQueryInput, ParamEnvAnd<'db, V>> + where + V: TypeFoldable>, + { + let (param_env, value) = value.into_parts(); + // FIXME(#118965): We don't canonicalize the static lifetimes that appear in the + // `param_env` because they are treated differently by trait selection. + let canonical_param_env = Canonicalizer::canonicalize( + param_env, + None, + self.interner, + &CanonicalizeFreeRegionsOtherThanStatic, + query_state, + ); + + let canonical = Canonicalizer::canonicalize_with_base( + canonical_param_env, + value, + Some(self), + self.interner, + &CanonicalizeAllFreeRegions, + query_state, + ) + .unchecked_map(|(param_env, value)| ParamEnvAnd { param_env, value }); + CanonicalQueryInput { canonical, typing_mode: self.typing_mode() } + } + + /// Canonicalizes a query *response* `V`. When we canonicalize a + /// query response, we only canonicalize unbound inference + /// variables, and we leave other free regions alone. So, + /// continuing with the example from `canonicalize_query`, if + /// there was an input query `T: Trait<'static>`, it would have + /// been canonicalized to + /// + /// ```text + /// T: Trait<'?0> + /// ``` + /// + /// with a mapping M that maps `'?0` to `'static`. But if we found that there + /// exists only one possible impl of `Trait`, and it looks like + /// ```ignore (illustrative) + /// impl Trait<'static> for T { .. } + /// ``` + /// then we would prepare a query result R that (among other + /// things) includes a mapping to `'?0 := 'static`. When + /// canonicalizing this query result R, we would leave this + /// reference to `'static` alone. + /// + /// To get a good understanding of what is happening here, check + /// out the [chapter in the rustc dev guide][c]. + /// + /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result + pub fn canonicalize_response(&self, value: V) -> Canonical<'db, V> + where + V: TypeFoldable>, + { + let mut query_state = OriginalQueryValues::default(); + Canonicalizer::canonicalize( + value, + Some(self), + self.interner, + &CanonicalizeQueryResponse, + &mut query_state, + ) + } + + pub fn canonicalize_user_type_annotation(&self, value: V) -> Canonical<'db, V> + where + V: TypeFoldable>, + { + let mut query_state = OriginalQueryValues::default(); + Canonicalizer::canonicalize( + value, + Some(self), + self.interner, + &CanonicalizeUserTypeAnnotation, + &mut query_state, + ) + } +} + +/// Controls how we canonicalize "free regions" that are not inference +/// variables. This depends on what we are canonicalizing *for* -- +/// e.g., if we are canonicalizing to create a query, we want to +/// replace those with inference variables, since we want to make a +/// maximally general query. But if we are canonicalizing a *query +/// response*, then we don't typically replace free regions, as they +/// must have been introduced from other parts of the system. +trait CanonicalizeMode { + fn canonicalize_free_region<'db>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'db>, + r: Region<'db>, + ) -> Region<'db>; + + fn any(&self) -> bool; + + // Do we preserve universe of variables. + fn preserve_universes(&self) -> bool; +} + +struct CanonicalizeQueryResponse; + +impl CanonicalizeMode for CanonicalizeQueryResponse { + fn canonicalize_free_region<'db>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'db>, + mut r: Region<'db>, + ) -> Region<'db> { + let infcx = canonicalizer.infcx.unwrap(); + + if let RegionKind::ReVar(vid) = r.kind() { + r = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(canonicalizer.tcx, vid); + debug!( + "canonical: region var found with vid {vid:?}, \ + opportunistically resolved to {r:?}", + ); + }; + + match r.kind() { + RegionKind::ReLateParam(_) | RegionKind::ReErased | RegionKind::ReStatic | RegionKind::ReEarlyParam(..) | RegionKind::ReError(..) => r, + + RegionKind::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( + CanonicalVarKind::PlaceholderRegion(placeholder), + r, + ), + + RegionKind::ReVar(vid) => { + let universe = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .probe_value(vid) + .unwrap_err(); + canonicalizer.canonical_var_for_region( + CanonicalVarKind::Region(universe), + r, + ) + } + + _ => { + // Other than `'static` or `'empty`, the query + // response should be executing in a fully + // canonicalized environment, so there shouldn't be + // any other region names it can come up. + // + // rust-lang/rust#57464: `impl Trait` can leak local + // scopes (in manner violating typeck). Therefore, use + // `delayed_bug` to allow type error over an ICE. + panic!("unexpected region in query response: `{r:?}`"); + } + } + } + + fn any(&self) -> bool { + false + } + + fn preserve_universes(&self) -> bool { + true + } +} + +struct CanonicalizeUserTypeAnnotation; + +impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { + fn canonicalize_free_region<'db>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'db>, + r: Region<'db>, + ) -> Region<'db> { + match r.kind() { + RegionKind::ReEarlyParam(_) + | RegionKind::ReLateParam(_) + | RegionKind::ReErased + | RegionKind::ReStatic + | RegionKind::ReError(_) => r, + RegionKind::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), + RegionKind::RePlaceholder(..) | RegionKind::ReBound(..) => { + // We only expect region names that the user can type. + panic!("unexpected region in query response: `{:?}`", r) + } + } + } + + fn any(&self) -> bool { + false + } + + fn preserve_universes(&self) -> bool { + false + } +} + +struct CanonicalizeAllFreeRegions; + +impl CanonicalizeMode for CanonicalizeAllFreeRegions { + fn canonicalize_free_region<'db>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'db>, + r: Region<'db>, + ) -> Region<'db> { + canonicalizer.canonical_var_for_region_in_root_universe(r) + } + + fn any(&self) -> bool { + true + } + + fn preserve_universes(&self) -> bool { + false + } +} + +struct CanonicalizeFreeRegionsOtherThanStatic; + +impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic { + fn canonicalize_free_region<'db>( + &self, + canonicalizer: &mut Canonicalizer<'_, 'db>, + r: Region<'db>, + ) -> Region<'db> { + if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) } + } + + fn any(&self) -> bool { + true + } + + fn preserve_universes(&self) -> bool { + false + } +} + +struct Canonicalizer<'cx, 'db> { + /// Set to `None` to disable the resolution of inference variables. + infcx: Option<&'cx InferCtxt<'db>>, + tcx: DbInterner<'db>, + variables: SmallVec<[CanonicalVarKind<'db>; 8]>, + query_state: &'cx mut OriginalQueryValues<'db>, + // Note that indices is only used once `var_values` is big enough to be + // heap-allocated. + indices: FxHashMap, BoundVar>, + canonicalize_mode: &'cx dyn CanonicalizeMode, + needs_canonical_flags: TypeFlags, + + binder_index: DebruijnIndex, +} + +impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.tcx + } + + fn fold_binder(&mut self, t: Binder<'db, T>) -> Binder<'db, T> + where + T: TypeFoldable>, + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + match r.kind() { + RegionKind::ReBound(index, ..) => { + if index >= self.binder_index { + panic!("escaping late-bound region during canonicalization"); + } else { + r + } + } + + RegionKind::ReStatic + | RegionKind::ReEarlyParam(..) + | RegionKind::ReError(_) + | RegionKind::ReLateParam(_) + | RegionKind::RePlaceholder(..) + | RegionKind::ReVar(_) + | RegionKind::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r), + } + } + + fn fold_ty(&mut self, mut t: Ty<'db>) -> Ty<'db> { + match t.kind() { + TyKind::Infer(TyVar(mut vid)) => { + // We need to canonicalize the *root* of our ty var. + // This is so that our canonical response correctly reflects + // any equated inference vars correctly! + let root_vid = self.infcx.unwrap().root_var(vid); + if root_vid != vid { + t = Ty::new_var(self.tcx, root_vid); + vid = root_vid; + } + + debug!("canonical: type var found with vid {:?}", vid); + match self.infcx.unwrap().probe_ty_var(vid) { + // `t` could be a float / int variable; canonicalize that instead. + Ok(t) => { + debug!("(resolved to {:?})", t); + self.fold_ty(t) + } + + // `TyVar(vid)` is unresolved, track its universe index in the canonicalized + // result. + Err(mut ui) => { + if !self.canonicalize_mode.preserve_universes() { + // FIXME: perf problem described in #55921. + ui = UniverseIndex::ROOT; + } + self.canonicalize_ty_var( + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), + t, + ) + } + } + } + + TyKind::Infer(IntVar(vid)) => { + let nt = self.infcx.unwrap().opportunistic_resolve_int_var(vid); + if nt != t { + return self.fold_ty(nt); + } else { + self.canonicalize_ty_var( + CanonicalVarKind::Ty(CanonicalTyVarKind::Int), + t, + ) + } + } + TyKind::Infer(FloatVar(vid)) => { + let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid); + if nt != t { + return self.fold_ty(nt); + } else { + self.canonicalize_ty_var( + CanonicalVarKind::Ty(CanonicalTyVarKind::Float), + t, + ) + } + } + + TyKind::Infer(InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_)) => { + panic!("encountered a fresh type during canonicalization") + } + + TyKind::Placeholder(mut placeholder) => { + if !self.canonicalize_mode.preserve_universes() { + placeholder.universe = UniverseIndex::ROOT; + } + self.canonicalize_ty_var( + CanonicalVarKind::PlaceholderTy(placeholder), + t, + ) + } + + TyKind::Bound(debruijn, _) => { + if debruijn >= self.binder_index { + panic!("escaping bound type during canonicalization") + } else { + t + } + } + + TyKind::Closure(..) + | TyKind::CoroutineClosure(..) + | TyKind::Coroutine(..) + | TyKind::CoroutineWitness(..) + | TyKind::Bool + | TyKind::Char + | TyKind::Int(..) + | TyKind::Uint(..) + | TyKind::Float(..) + | TyKind::Adt(..) + | TyKind::Str + | TyKind::Error(_) + | TyKind::Array(..) + | TyKind::Slice(..) + | TyKind::RawPtr(..) + | TyKind::Ref(..) + | TyKind::FnDef(..) + | TyKind::FnPtr(..) + | TyKind::Dynamic(..) + | TyKind::UnsafeBinder(_) + | TyKind::Never + | TyKind::Tuple(..) + | TyKind::Alias(..) + | TyKind::Foreign(..) + | TyKind::Pat(..) + | TyKind::Param(..) => { + if t.flags().intersects(self.needs_canonical_flags) { + t.super_fold_with(self) + } else { + t + } + } + } + } + + fn fold_const(&mut self, mut ct: Const<'db>) -> Const<'db> { + match ct.kind() { + ConstKind::Infer(InferConst::Var(mut vid)) => { + // We need to canonicalize the *root* of our const var. + // This is so that our canonical response correctly reflects + // any equated inference vars correctly! + let root_vid = self.infcx.unwrap().root_const_var(vid); + if root_vid != vid { + ct = Const::new_var(self.tcx, root_vid); + vid = root_vid; + } + + debug!("canonical: const var found with vid {:?}", vid); + match self.infcx.unwrap().probe_const_var(vid) { + Ok(c) => { + debug!("(resolved to {:?})", c); + return self.fold_const(c); + } + + // `ConstVar(vid)` is unresolved, track its universe index in the + // canonicalized result + Err(mut ui) => { + if !self.canonicalize_mode.preserve_universes() { + // FIXME: perf problem described in #55921. + ui = UniverseIndex::ROOT; + } + return self.canonicalize_const_var( + CanonicalVarKind::Const(ui), + ct, + ); + } + } + } + ConstKind::Infer(InferConst::Fresh(_)) => { + panic!("encountered a fresh const during canonicalization") + } + ConstKind::Bound(debruijn, _) => { + if debruijn >= self.binder_index { + panic!("escaping bound const during canonicalization") + } else { + return ct; + } + } + ConstKind::Placeholder(placeholder) => { + return self.canonicalize_const_var( + CanonicalVarKind::PlaceholderConst(placeholder), + ct, + ); + } + _ => {} + } + + if ct.flags().intersects(self.needs_canonical_flags) { + ct.super_fold_with(self) + } else { + ct + } + } +} + +impl<'cx, 'db> Canonicalizer<'cx, 'db> { + /// The main `canonicalize` method, shared impl of + /// `canonicalize_query` and `canonicalize_response`. + fn canonicalize( + value: V, + infcx: Option<&InferCtxt<'db>>, + tcx: DbInterner<'db>, + canonicalize_region_mode: &dyn CanonicalizeMode, + query_state: &mut OriginalQueryValues<'db>, + ) -> Canonical<'db, V> + where + V: TypeFoldable>, + { + let base = Canonical { + max_universe: UniverseIndex::ROOT, + variables: CanonicalVars::new_from_iter(tcx, []), + value: (), + }; + Canonicalizer::canonicalize_with_base( + base, + value, + infcx, + tcx, + canonicalize_region_mode, + query_state, + ) + .unchecked_map(|((), val)| val) + } + + fn canonicalize_with_base( + base: Canonical<'db, U>, + value: V, + infcx: Option<&InferCtxt<'db>>, + tcx: DbInterner<'db>, + canonicalize_region_mode: &dyn CanonicalizeMode, + query_state: &mut OriginalQueryValues<'db>, + ) -> Canonical<'db, (U, V)> + where + V: TypeFoldable>, + { + let needs_canonical_flags = if canonicalize_region_mode.any() { + TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS + } else { + TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER + }; + + // Fast path: nothing that needs to be canonicalized. + if !value.has_type_flags(needs_canonical_flags) { + return base.unchecked_map(|b| (b, value)); + } + + let mut canonicalizer = Canonicalizer { + infcx, + tcx, + canonicalize_mode: canonicalize_region_mode, + needs_canonical_flags, + variables: SmallVec::from_slice(base.variables.as_slice()), + query_state, + indices: FxHashMap::default(), + binder_index: DebruijnIndex::ZERO, + }; + if canonicalizer.query_state.var_values.spilled() { + canonicalizer.indices = canonicalizer + .query_state + .var_values + .iter() + .enumerate() + .map(|(i, &kind)| (kind, BoundVar::from(i))) + .collect(); + } + let out_value = value.fold_with(&mut canonicalizer); + + // Once we have canonicalized `out_value`, it should not + // contain anything that ties it to this inference context + // anymore. + debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); + + let canonical_variables = CanonicalVars::new_from_iter(tcx, canonicalizer.universe_canonicalized_variables()); + + let max_universe = canonical_variables + .iter() + .map(|cvar| cvar.universe()) + .max() + .unwrap_or(UniverseIndex::ROOT); + + Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) } + } + + /// Creates a canonical variable replacing `kind` from the input, + /// or returns an existing variable if `kind` has already been + /// seen. `kind` is expected to be an unbound variable (or + /// potentially a free region). + fn canonical_var(&mut self, info: CanonicalVarKind<'db>, kind: GenericArg<'db>) -> BoundVar { + let Canonicalizer { variables, query_state, indices, .. } = self; + + let var_values = &mut query_state.var_values; + + let universe = info.universe(); + if universe != UniverseIndex::ROOT { + assert!(self.canonicalize_mode.preserve_universes()); + + // Insert universe into the universe map. To preserve the order of the + // universes in the value being canonicalized, we don't update the + // universe in `info` until we have finished canonicalizing. + match query_state.universe_map.binary_search(&universe) { + Err(idx) => query_state.universe_map.insert(idx, universe), + Ok(_) => {} + } + } + + // This code is hot. `variables` and `var_values` are usually small + // (fewer than 8 elements ~95% of the time). They are SmallVec's to + // avoid allocations in those cases. We also don't use `indices` to + // determine if a kind has been seen before until the limit of 8 has + // been exceeded, to also avoid allocations for `indices`. + if !var_values.spilled() { + // `var_values` is stack-allocated. `indices` isn't used yet. Do a + // direct linear search of `var_values`. + if let Some(idx) = var_values.iter().position(|&k| k == kind) { + // `kind` is already present in `var_values`. + BoundVar::new(idx) + } else { + // `kind` isn't present in `var_values`. Append it. Likewise + // for `info` and `variables`. + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + + // If `var_values` has become big enough to be heap-allocated, + // fill up `indices` to facilitate subsequent lookups. + if var_values.spilled() { + assert!(indices.is_empty()); + *indices = var_values + .iter() + .enumerate() + .map(|(i, &kind)| (kind, BoundVar::new(i))) + .collect(); + } + // The cv is the index of the appended element. + BoundVar::new(var_values.len() - 1) + } + } else { + // `var_values` is large. Do a hashmap search via `indices`. + *indices.entry(kind).or_insert_with(|| { + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + BoundVar::new(variables.len() - 1) + }) + } + } + + /// Replaces the universe indexes used in `var_values` with their index in + /// `query_state.universe_map`. This minimizes the maximum universe used in + /// the canonicalized value. + fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'db>; 8]> { + if self.query_state.universe_map.len() == 1 { + return self.variables; + } + + let reverse_universe_map: FxHashMap = self + .query_state + .universe_map + .iter() + .enumerate() + .map(|(idx, universe)| (*universe, UniverseIndex::from_usize(idx))) + .collect(); + + self.variables + .iter() + .map(|v| match *v { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { + return *v; + } + CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) + } + CanonicalVarKind::Region(u) => { + CanonicalVarKind::Region(reverse_universe_map[&u]) + } + CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + }) + .collect() + } + + /// Shorthand helper that creates a canonical region variable for + /// `r` (always in the root universe). The reason that we always + /// put these variables into the root universe is because this + /// method is used during **query construction:** in that case, we + /// are taking all the regions and just putting them into the most + /// generic context we can. This may generate solutions that don't + /// fit (e.g., that equate some region variable with a placeholder + /// it can't name) on the caller side, but that's ok, the caller + /// can figure that out. In the meantime, it maximizes our + /// caching. + /// + /// (This works because unification never fails -- and hence trait + /// selection is never affected -- due to a universe mismatch.) + fn canonical_var_for_region_in_root_universe( + &mut self, + r: Region<'db>, + ) -> Region<'db> { + self.canonical_var_for_region( + CanonicalVarKind::Region(UniverseIndex::ROOT), + r, + ) + } + + /// Creates a canonical variable (with the given `info`) + /// representing the region `r`; return a region referencing it. + fn canonical_var_for_region( + &mut self, + info: CanonicalVarKind<'db>, + r: Region<'db>, + ) -> Region<'db> { + let var = self.canonical_var(info, r.into()); + let br = BoundRegion { var, kind: BoundRegionKind::Anon }; + Region::new_bound(self.cx(), self.binder_index, br) + } + + /// Given a type variable `ty_var` of the given kind, first check + /// if `ty_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `ty_var`. + fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> { + debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); + let var = self.canonical_var(info, ty_var.into()); + Ty::new_bound(self.tcx, self.binder_index, BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var }) + } + + /// Given a type variable `const_var` of the given kind, first check + /// if `const_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `const_var`. + fn canonicalize_const_var( + &mut self, + info: CanonicalVarKind<'db>, + const_var: Const<'db>, + ) -> Const<'db> { + debug_assert!( + !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var)) + ); + let var = self.canonical_var(info, const_var.into()); + Const::new_bound(self.tcx, self.binder_index, var) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs index 4457e1340d584..ec41111ed8153 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -42,6 +42,7 @@ use rustc_type_ir::{ }, }; +pub mod canonicalizer; pub mod instantiate; impl<'db> InferCtxt<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 585719144ef42..894c91e0f49db 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -190,12 +190,13 @@ impl<'db> InferCtxtInner<'db> { } #[inline] - fn int_unification_table(&mut self) -> UnificationTable<'_, 'db, IntVid> { + pub(crate) fn int_unification_table(&mut self) -> UnificationTable<'_, 'db, IntVid> { + tracing::debug!(?self.int_unification_storage); self.int_unification_storage.with_log(&mut self.undo_log) } #[inline] - fn float_unification_table(&mut self) -> UnificationTable<'_, 'db, FloatVid> { + pub(crate) fn float_unification_table(&mut self) -> UnificationTable<'_, 'db, FloatVid> { self.float_unification_storage.with_log(&mut self.undo_log) } @@ -213,6 +214,7 @@ impl<'db> InferCtxtInner<'db> { } } +#[derive(Clone)] pub struct InferCtxt<'db> { pub interner: DbInterner<'db>, @@ -500,6 +502,10 @@ impl<'db> InferCtxt<'db> { self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None }) } + pub fn next_ty_vid(&self) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), TypeVariableOrigin { param_def_id: None }) + } + pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> { let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); Ty::new_var(self.interner, vid) @@ -519,6 +525,15 @@ impl<'db> InferCtxt<'db> { self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None }) } + pub fn next_const_vid(&self) -> ConstVid { + self + .inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVariableValue::Unknown { origin: ConstVariableOrigin { param_def_id: None }, universe: self.universe() }) + .vid + } + pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> { let vid = self .inner @@ -546,12 +561,20 @@ impl<'db> InferCtxt<'db> { Ty::new_int_var(self.interner, next_int_var_id) } + pub fn next_int_vid(&self) -> IntVid { + self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown) + } + pub fn next_float_var(&self) -> Ty<'db> { let next_float_var_id = self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown); Ty::new_float_var(self.interner, next_float_var_id) } + pub fn next_float_vid(&self) -> FloatVid { + self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown) + } + /// Creates a fresh region variable with the next available index. /// The variable will be created in the maximum universe created /// thus far, allowing it to name any region created thus far. @@ -559,6 +582,10 @@ impl<'db> InferCtxt<'db> { self.next_region_var_in_universe(self.universe()) } + pub fn next_region_vid(&self) -> RegionVid { + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe()) + } + /// Creates a fresh region variable with the next available index /// in the given universe; typically, you can use /// `next_region_var` and just use the maximal universe. @@ -782,6 +809,18 @@ impl<'db> InferCtxt<'db> { } } + pub fn resolve_int_var(&self, vid: IntVid) -> Option> { + let mut inner = self.inner.borrow_mut(); + let value = inner.int_unification_table().probe_value(vid); + match value { + IntVarValue::IntType(ty) => Some(Ty::new_int(self.interner, ty)), + IntVarValue::UintType(ty) => Some(Ty::new_uint(self.interner, ty)), + IntVarValue::Unknown => { + None + } + } + } + /// Resolves a float var to a rigid int type, if it was constrained to one, /// or else the root float var in the unification table. pub fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'db> { @@ -795,6 +834,17 @@ impl<'db> InferCtxt<'db> { } } + pub fn resolve_float_var(&self, vid: FloatVid) -> Option> { + let mut inner = self.inner.borrow_mut(); + let value = inner.float_unification_table().probe_value(vid); + match value { + FloatVarValue::Known(ty) => Some(Ty::new_float(self.interner, ty)), + FloatVarValue::Unknown => { + None + } + } + } + /// Where possible, replaces type/const variables in /// `value` with their final value. Note that region variables /// are unaffected. If a type/const variable has not been unified, it diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs index eb426205575ad..8c7dfb25e07f9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs @@ -46,7 +46,7 @@ impl<'db> InferCtxt<'db> { UndoLogs::>::num_open_snapshots(&self.inner.borrow_mut().undo_log) } - fn start_snapshot(&self) -> CombinedSnapshot { + pub(crate) fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); let mut inner = self.inner.borrow_mut(); @@ -59,7 +59,7 @@ impl<'db> InferCtxt<'db> { } #[instrument(skip(self, snapshot), level = "debug")] - fn rollback_to(&self, snapshot: CombinedSnapshot) { + pub(crate) fn rollback_to(&self, snapshot: CombinedSnapshot) { let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot; self.universe.set(universe); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index dc54ee7d58785..79c402ff29c3d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -2,8 +2,8 @@ use base_db::Crate; use chalk_ir::{ - CanonicalVarKind, CanonicalVarKinds, ForeignDefId, InferenceVar, Substitution, TyVariableKind, - WellFormed, fold::Shift, interner::HasInterner, + CanonicalVarKind, CanonicalVarKinds, FnPointer, InferenceVar, Substitution, TyVariableKind, + WellFormed, cast::Cast, fold::Shift, interner::HasInterner, }; use hir_def::{ CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId, @@ -24,12 +24,12 @@ use salsa::{Id, plumbing::AsId}; use crate::next_solver::BoundConst; use crate::{ - ConcreteConst, ConstScalar, ImplTraitId, Interner, MemoryMap, + ConstScalar, ImplTraitId, Interner, MemoryMap, db::{ HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId, InternedOpaqueTyId, InternedTypeOrConstParamId, }, - from_assoc_type_id, from_chalk_trait_id, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, mapping::ToChalk, next_solver::{ Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst, @@ -141,6 +141,7 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db pub trait ChalkToNextSolver<'db, Out> { fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out; + fn from_nextsolver(out: Out, interner: DbInterner<'db>) -> Self; } impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { @@ -427,6 +428,343 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { }, ) } + + fn from_nextsolver(out: Ty<'db>, interner: DbInterner<'db>) -> Self { + use crate::{Scalar, TyKind}; + use chalk_ir::{FloatTy, IntTy, UintTy}; + match out.kind() { + rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool), + rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char), + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => { + TyKind::Scalar(Scalar::Int(IntTy::I8)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => { + TyKind::Scalar(Scalar::Int(IntTy::I16)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => { + TyKind::Scalar(Scalar::Int(IntTy::I32)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => { + TyKind::Scalar(Scalar::Int(IntTy::I64)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => { + TyKind::Scalar(Scalar::Int(IntTy::I128)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => { + TyKind::Scalar(Scalar::Int(IntTy::Isize)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => { + TyKind::Scalar(Scalar::Uint(UintTy::U8)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => { + TyKind::Scalar(Scalar::Uint(UintTy::U16)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => { + TyKind::Scalar(Scalar::Uint(UintTy::U32)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => { + TyKind::Scalar(Scalar::Uint(UintTy::U64)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => { + TyKind::Scalar(Scalar::Uint(UintTy::U128)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => { + TyKind::Scalar(Scalar::Uint(UintTy::Usize)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => { + TyKind::Scalar(Scalar::Float(FloatTy::F16)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => { + TyKind::Scalar(Scalar::Float(FloatTy::F32)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => { + TyKind::Scalar(Scalar::Float(FloatTy::F64)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => { + TyKind::Scalar(Scalar::Float(FloatTy::F128)) + } + rustc_type_ir::TyKind::Str => TyKind::Str, + rustc_type_ir::TyKind::Error(_) => TyKind::Error, + rustc_type_ir::TyKind::Never => TyKind::Never, + + rustc_type_ir::TyKind::Adt(def, args) => { + let adt_id = def.inner().id; + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + TyKind::Adt(chalk_ir::AdtId(adt_id), subst) + } + + rustc_type_ir::TyKind::Infer(infer_ty) => { + let (var, kind) = match infer_ty { + rustc_type_ir::InferTy::TyVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::General) + } + rustc_type_ir::InferTy::IntVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::Integer) + } + rustc_type_ir::InferTy::FloatVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::Float) + } + _ => todo!(), + }; + TyKind::InferenceVar(var, kind) + } + + rustc_type_ir::TyKind::Ref(r, ty, mutability) => { + let mutability = match mutability { + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + }; + let r = ChalkToNextSolver::from_nextsolver(r, interner); + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + TyKind::Ref(mutability, r, ty) + } + + rustc_type_ir::TyKind::Tuple(tys) => { + let size = tys.len(); + let subst = Substitution::from_iter( + Interner, + tys.iter().map(|ty| { + chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver( + ty, interner, + )) + .intern(Interner) + }), + ); + TyKind::Tuple(size, subst) + } + + rustc_type_ir::TyKind::Array(ty, const_) => { + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let const_ = ChalkToNextSolver::from_nextsolver(const_, interner); + TyKind::Array(ty, const_) + } + + rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind { + rustc_type_ir::AliasTyKind::Projection => { + let assoc_ty_id = match alias_ty.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), + }; + let associated_ty_id = to_assoc_type_id(assoc_ty_id); + let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); + TyKind::AssociatedType(associated_ty_id, substitution) + } + rustc_type_ir::AliasTyKind::Opaque => { + let opaque_ty_id = match alias_ty.def_id { + SolverDefId::InternedOpaqueTyId(id) => id, + _ => unreachable!(), + }; + let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); + TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { + opaque_ty_id: opaque_ty_id.into(), + substitution, + })) + } + rustc_type_ir::AliasTyKind::Inherent => todo!(), + rustc_type_ir::AliasTyKind::Free => todo!(), + }, + + rustc_type_ir::TyKind::Placeholder(placeholder) => { + let ui = chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }; + let placeholder_index = + chalk_ir::PlaceholderIndex { idx: placeholder.bound.var.as_usize(), ui }; + TyKind::Placeholder(placeholder_index) + } + + rustc_type_ir::TyKind::Bound(debruijn_index, ty) => { + TyKind::BoundVar(chalk_ir::BoundVar { + debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), + index: ty.var.as_usize(), + }) + } + + rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => { + let num_binders = bound_sig.bound_vars().len(); + let sig = chalk_ir::FnSig { + abi: fn_header.abi, + safety: match fn_header.safety { + crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, + crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: fn_header.c_variadic, + }; + let args = GenericArgs::new_from_iter( + interner, + bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), + ); + let substitution = ChalkToNextSolver::from_nextsolver(args, interner); + let substitution = chalk_ir::FnSubst(substitution); + let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; + TyKind::Function(fnptr) + } + + rustc_type_ir::TyKind::Dynamic(preds, region, dyn_kind) => { + assert!(matches!(dyn_kind, rustc_type_ir::DynKind::Dyn)); + let self_ty = Ty::new_bound( + interner, + DebruijnIndex::from_u32(1), + BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) }, + ); + let bounds = chalk_ir::QuantifiedWhereClauses::from_iter( + Interner, + preds.iter().map(|p| { + let binders = chalk_ir::VariableKinds::from_iter( + Interner, + p.bound_vars().iter().map(|b| match b { + BoundVarKind::Ty(kind) => { + chalk_ir::VariableKind::Ty(TyVariableKind::General) + } + BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime, + BoundVarKind::Const => chalk_ir::VariableKind::Const( + crate::TyKind::Error.intern(Interner), + ), + }), + ); + let where_clause = match p.skip_binder() { + rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { + let trait_ref = TraitRef::new( + interner, + trait_ref.def_id, + [self_ty.clone().into()] + .into_iter() + .chain(trait_ref.args.iter()), + ); + let trait_id = match trait_ref.def_id { + SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + let substitution = + ChalkToNextSolver::from_nextsolver(trait_ref.args, interner); + let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; + chalk_ir::WhereClause::Implemented(trait_ref) + } + rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => { + let trait_id = match trait_ { + SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + let substitution = chalk_ir::Substitution::empty(Interner); + let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; + chalk_ir::WhereClause::Implemented(trait_ref) + } + rustc_type_ir::ExistentialPredicate::Projection( + existential_projection, + ) => { + let projection = ProjectionPredicate { + projection_term: AliasTerm::new( + interner, + existential_projection.def_id, + [self_ty.clone().into()] + .iter() + .chain(existential_projection.args.clone().iter()), + ), + term: existential_projection.term.clone(), + }; + let associated_ty_id = match projection.projection_term.def_id { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => unreachable!(), + }; + let substitution = ChalkToNextSolver::from_nextsolver( + projection.projection_term.args, + interner, + ); + let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id, + substitution, + }); + let ty = match projection.term { + Term::Ty(ty) => ty, + _ => unreachable!(), + }; + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let alias_eq = chalk_ir::AliasEq { alias, ty }; + chalk_ir::WhereClause::AliasEq(alias_eq) + } + }; + chalk_ir::Binders::new(binders, where_clause) + }), + ); + let binders = chalk_ir::VariableKinds::from1( + Interner, + chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), + ); + let bounds = chalk_ir::Binders::new(binders, bounds); + let dyn_ty = chalk_ir::DynTy { + bounds, + lifetime: ChalkToNextSolver::from_nextsolver(region, interner), + }; + TyKind::Dyn(dyn_ty) + } + + rustc_type_ir::TyKind::Slice(ty) => { + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + TyKind::Slice(ty) + } + + rustc_type_ir::TyKind::Foreign(def_id) => { + let id = match def_id { + SolverDefId::TypeAliasId(id) => to_foreign_def_id(id), + _ => unreachable!(), + }; + TyKind::Foreign(id) + } + rustc_type_ir::TyKind::Pat(_, _) => todo!(), + rustc_type_ir::TyKind::RawPtr(ty, mutability) => { + let mutability = match mutability { + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + }; + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + TyKind::Raw(mutability, ty) + } + rustc_type_ir::TyKind::FnDef(def_id, args) => { + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + match def_id { + SolverDefId::FunctionId(id) => { + TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst) + } + SolverDefId::Ctor(Ctor::Enum(e)) => TyKind::FnDef( + CallableDefId::EnumVariantId(e).to_chalk(interner.db()), + subst, + ), + SolverDefId::Ctor(Ctor::Struct(s)) => { + TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst) + } + _ => unreachable!("Unexpected def id {:?}", def_id), + } + } + + rustc_type_ir::TyKind::Closure(def_id, args) => { + let id = match def_id { + SolverDefId::InternedClosureId(id) => id, + _ => unreachable!(), + }; + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + TyKind::Closure(id.into(), subst) + } + rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(), + rustc_type_ir::TyKind::Coroutine(def_id, args) => { + let id = match def_id { + SolverDefId::InternedCoroutineId(id) => id, + _ => unreachable!(), + }; + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + TyKind::Coroutine(id.into(), subst) + } + rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { + let id = match def_id { + SolverDefId::InternedCoroutineId(id) => id, + _ => unreachable!(), + }; + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + TyKind::CoroutineWitness(id.into(), subst) + } + + rustc_type_ir::TyKind::Param(_) => todo!(), + rustc_type_ir::TyKind::UnsafeBinder(_) => todo!(), + } + .intern(Interner) + } } impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { @@ -461,6 +799,40 @@ impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { }, ) } + + fn from_nextsolver(out: Region<'db>, interner: DbInterner<'db>) -> Self { + match out.kind() { + rustc_type_ir::RegionKind::ReEarlyParam(early) => todo!(), + rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( + chalk_ir::DebruijnIndex::new(db.as_u32()), + bound.var.as_usize(), + )), + ), + rustc_type_ir::RegionKind::ReLateParam(_) => todo!(), + rustc_type_ir::RegionKind::ReStatic => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Static) + } + rustc_type_ir::RegionKind::ReVar(vid) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())), + ), + rustc_type_ir::RegionKind::RePlaceholder(placeholder) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { + idx: placeholder.bound.var.as_usize(), + ui: chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }, + }), + ), + rustc_type_ir::RegionKind::ReErased => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Erased) + } + rustc_type_ir::RegionKind::ReError(_) => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Error) + } + } + } } impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { @@ -505,6 +877,62 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { }, ) } + + fn from_nextsolver(out: Const<'db>, interner: DbInterner<'db>) -> Self { + let value: chalk_ir::ConstValue = match out.kind() { + rustc_type_ir::ConstKind::Param(_) => unimplemented!(), + rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { + chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32())) + } + rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => { + panic!("Vars should not be freshened.") + } + rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { + chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( + chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), + var.index(), + )) + } + rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { + chalk_ir::ConstValue::Placeholder(chalk_ir::PlaceholderIndex { + ui: chalk_ir::UniverseIndex { counter: placeholder_const.universe.as_usize() }, + idx: placeholder_const.bound.as_usize(), + }) + } + rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => { + let id = match unevaluated_const.def { + SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), + SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), + _ => unreachable!(), + }; + let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::UnevaluatedConst(id, subst), + }) + } + rustc_type_ir::ConstKind::Value(value_const) => { + let bytes = value_const.value.inner(); + let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + // SAFETY: will never use this without a db + interned: ConstScalar::Bytes(bytes.0.clone(), unsafe { + std::mem::transmute::, MemoryMap<'static>>(bytes.1.clone()) + }), + }); + return chalk_ir::ConstData { + ty: ChalkToNextSolver::from_nextsolver(value_const.ty, interner), + value, + } + .intern(Interner); + } + rustc_type_ir::ConstKind::Error(_) => { + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::Unknown, + }) + } + rustc_type_ir::ConstKind::Expr(_) => unimplemented!(), + }; + chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) + } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys>> @@ -518,6 +946,13 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys>> ), } } + + fn from_nextsolver( + out: rustc_type_ir::FnSigTys>, + interner: DbInterner<'db>, + ) -> Self { + todo!() + } } impl< @@ -536,6 +971,13 @@ impl< binders.to_nextsolver(interner), ) } + + fn from_nextsolver( + out: rustc_type_ir::Binder, U>, + interner: DbInterner<'db>, + ) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds { @@ -545,6 +987,10 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind { @@ -555,6 +1001,10 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind BoundVarKind::Const, } } + + fn from_nextsolver(out: BoundVarKind, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg { @@ -565,6 +1015,10 @@ impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg const_.to_nextsolver(interner).into(), } } + + fn from_nextsolver(out: GenericArg<'db>, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution { fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> { @@ -573,6 +1027,31 @@ impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution GenericArg<'db> { arg.to_nextsolver(interner) }), ) } + + fn from_nextsolver(out: GenericArgs<'db>, interner: DbInterner<'db>) -> Self { + let mut substs = Vec::with_capacity(out.len()); + for arg in out.iter() { + match arg.clone().kind() { + rustc_type_ir::GenericArgKind::Type(ty) => { + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner)); + } + rustc_type_ir::GenericArgKind::Lifetime(region) => { + let lifetime = ChalkToNextSolver::from_nextsolver(region, interner); + substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner)); + } + rustc_type_ir::GenericArgKind::Const(const_) => { + substs.push( + chalk_ir::GenericArgData::Const(ChalkToNextSolver::from_nextsolver( + const_, interner, + )) + .intern(Interner), + ); + } + } + } + Substitution::from_iter(Interner, substs) + } } impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution { @@ -588,18 +1067,30 @@ impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution }), ) } + + fn from_nextsolver(out: Tys<'db>, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex { fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { rustc_type_ir::DebruijnIndex::from_u32(self.depth()) } + + fn from_nextsolver(out: rustc_type_ir::DebruijnIndex, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex { fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex { rustc_type_ir::UniverseIndex::from_u32(self.counter as u32) } + + fn from_nextsolver(out: rustc_type_ir::UniverseIndex, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy> @@ -618,6 +1109,10 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy> } } } + + fn from_nextsolver(out: rustc_type_ir::InferTy, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability { @@ -627,6 +1122,10 @@ impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutabil chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not, } } + + fn from_nextsolver(out: rustc_ast_ir::Mutability, interner: DbInterner<'db>) -> Self { + todo!() + } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { @@ -638,16 +1137,65 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant, } } + + fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self { + todo!() + } } -impl<'db> ChalkToNextSolver<'db, Canonical<'db, Goal, Predicate<'db>>>> - for chalk_ir::Canonical>> +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance { + match self { + chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant, + chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant, + chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant, + } + } + + fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self { + todo!() + } +} + +impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf { + VariancesOf::new_from_iter( + interner, + self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)), + ) + } + + fn from_nextsolver(out: VariancesOf, interner: DbInterner<'db>) -> Self { + todo!() + } +} + +impl<'db> ChalkToNextSolver<'db, Goal, Predicate<'db>>> + for chalk_ir::InEnvironment> { - fn to_nextsolver( - &self, + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Goal, Predicate<'db>> { + Goal::new( + interner, + self.environment.to_nextsolver(interner), + self.goal.to_nextsolver(interner), + ) + } + + fn from_nextsolver( + out: Goal, Predicate<'db>>, interner: DbInterner<'db>, - ) -> Canonical<'db, Goal, Predicate<'db>>> { - let param_env = self.value.environment.to_nextsolver(interner); + ) -> Self { + chalk_ir::InEnvironment { + environment: ChalkToNextSolver::from_nextsolver(out.param_env, interner), + goal: ChalkToNextSolver::from_nextsolver(out.predicate, interner), + } + } +} + +impl<'db, T: HasInterner + ChalkToNextSolver<'db, U>, U> + ChalkToNextSolver<'db, Canonical<'db, U>> for chalk_ir::Canonical +{ + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Canonical<'db, U> { let variables = CanonicalVars::new_from_iter( interner, self.binders.iter(Interner).map(|k| match &k.kind { @@ -672,10 +1220,49 @@ impl<'db> ChalkToNextSolver<'db, Canonical<'db, Goal, Predicate< ); Canonical { max_universe: UniverseIndex::ROOT, - value: Goal::new(interner, param_env, self.value.goal.to_nextsolver(interner)), + value: self.value.to_nextsolver(interner), variables, } } + + fn from_nextsolver(out: Canonical<'db, U>, interner: DbInterner<'db>) -> Self { + let binders = chalk_ir::CanonicalVarKinds::from_iter( + Interner, + out.variables.iter().map(|v| match v { + rustc_type_ir::CanonicalVarKind::Ty( + rustc_type_ir::CanonicalTyVarKind::General(ui), + ) => chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::General), + chalk_ir::UniverseIndex { counter: ui.as_usize() }, + ), + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) => { + chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Integer), + chalk_ir::UniverseIndex::root(), + ) + } + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Float) => { + chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Float), + chalk_ir::UniverseIndex::root(), + ) + } + rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => todo!(), + rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Lifetime, + chalk_ir::UniverseIndex { counter: ui.as_usize() }, + ), + rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => todo!(), + rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)), + chalk_ir::UniverseIndex { counter: ui.as_usize() }, + ), + rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => todo!(), + }), + ); + let value = ChalkToNextSolver::from_nextsolver(out.value, interner); + chalk_ir::Canonical { binders, value } + } } impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { @@ -693,7 +1280,16 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { } chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."), chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."), - chalk_ir::GoalData::EqGoal(eq_goal) => panic!("Should not be constructed."), + chalk_ir::GoalData::EqGoal(eq_goal) => { + let pred_kind = PredicateKind::AliasRelate( + Term::Ty(eq_goal.a.assert_ty_ref(Interner).clone().to_nextsolver(interner)), + Term::Ty(eq_goal.b.assert_ty_ref(Interner).clone().to_nextsolver(interner)), + rustc_type_ir::AliasRelationDirection::Equate, + ); + let pred_kind = + Binder::bind_with_vars(pred_kind, BoundVarKinds::new_from_iter(interner, [])); + Predicate::new(interner, pred_kind) + } chalk_ir::GoalData::SubtypeGoal(subtype_goal) => { let subtype_predicate = SubtypePredicate { a: subtype_goal.a.to_nextsolver(interner), @@ -718,6 +1314,124 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."), } } + + fn from_nextsolver(out: Predicate<'db>, interner: DbInterner<'db>) -> Self { + chalk_ir::Goal::new( + Interner, + match out.kind().skip_binder() { + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + trait_pred, + )) => { + let trait_ref = + ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner); + let where_clause = chalk_ir::WhereClause::Implemented(trait_ref); + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) + } + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection( + proj_predicate, + )) => { + let associated_ty_id = match proj_predicate.def_id() { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => unreachable!(), + }; + let substitution = ChalkToNextSolver::from_nextsolver( + proj_predicate.projection_term.args, + interner, + ); + let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id, + substitution, + }); + let ty = match proj_predicate.term.kind() { + rustc_type_ir::TermKind::Ty(ty) => ty, + rustc_type_ir::TermKind::Const(_) => todo!(), + }; + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let alias_eq = chalk_ir::AliasEq { alias, ty }; + let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq); + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) + } + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives( + outlives, + )) => { + let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner); + let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner); + let where_clause = + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + lifetime, + ty, + }); + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) + } + rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::RegionOutlives(outlives), + ) => { + let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner); + let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner); + let where_clause = + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a, + b, + }); + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) + } + rustc_type_ir::PredicateKind::Clause(_) => todo!(), + rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(), + rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(), + rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(), + rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(), + rustc_type_ir::PredicateKind::Ambiguous => todo!(), + rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(), + rustc_type_ir::PredicateKind::AliasRelate( + alias_term, + ty_term, + alias_relation_direction, + ) => { + let ty = match ty_term { + Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner), + Term::Const(..) => todo!(), + }; + match alias_term { + Term::Ty(alias_ty) => match alias_ty.kind() { + rustc_type_ir::TyKind::Alias(kind, alias) => match kind { + rustc_type_ir::AliasTyKind::Projection => { + let associated_ty_id = match alias.def_id { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => todo!(), + }; + let substitution = + ChalkToNextSolver::from_nextsolver(alias.args, interner); + let proj_ty = + chalk_ir::ProjectionTy { associated_ty_id, substitution }; + let alias = chalk_ir::AliasTy::Projection(proj_ty); + let alias_eq = chalk_ir::AliasEq { alias, ty }; + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(alias_eq), + )) + } + _ => todo!(), + }, + rustc_type_ir::TyKind::Infer(var) => { + assert!(matches!( + alias_relation_direction, + rustc_type_ir::AliasRelationDirection::Equate + )); + let a: chalk_ir::Ty<_> = + ChalkToNextSolver::from_nextsolver(alias_ty, interner); + let eq_goal = chalk_ir::EqGoal { + a: chalk_ir::GenericArgData::Ty(a).intern(Interner), + b: chalk_ir::GenericArgData::Ty(ty).intern(Interner), + }; + chalk_ir::GoalData::EqGoal(eq_goal) + } + _ => todo!("Unexpected alias term {:?}", alias_term), + }, + Term::Const(..) => todo!(), + } + } + }, + ) + } } impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment { @@ -730,12 +1444,32 @@ impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment, interner: DbInterner<'db>) -> Self { + let clauses = chalk_ir::ProgramClauses::from_iter( + Interner, + out.clauses.iter().map(|c| -> chalk_ir::ProgramClause { + ChalkToNextSolver::from_nextsolver(c, interner) + }), + ); + chalk_ir::Environment { clauses } + } } impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause { fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> { Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner))) } + + fn from_nextsolver(out: Clause<'db>, interner: DbInterner<'db>) -> Self { + chalk_ir::ProgramClause::new( + Interner, + chalk_ir::ProgramClauseData(chalk_ir::Binders::empty( + Interner, + ChalkToNextSolver::from_nextsolver(out.0.kind().skip_binder(), interner), + )), + ) + } } impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> @@ -746,6 +1480,14 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> assert!(self.constraints.is_empty(Interner)); self.consequence.to_nextsolver(interner) } + fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self { + chalk_ir::ProgramClauseImplication { + consequence: ChalkToNextSolver::from_nextsolver(out, interner), + conditions: chalk_ir::Goals::empty(Interner), + constraints: chalk_ir::Constraints::empty(Interner), + priority: chalk_ir::ClausePriority::High, + } + } } impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal { @@ -864,6 +1606,98 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal panic!("Should not be constructed."), } } + + fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self { + let domain_goal = match out { + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => { + let trait_ref = ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner); + let where_clause = chalk_ir::WhereClause::Implemented(trait_ref); + chalk_ir::DomainGoal::Holds(where_clause) + } + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection( + proj_predicate, + )) => { + let associated_ty_id = match proj_predicate.def_id() { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => unreachable!(), + }; + let substitution = ChalkToNextSolver::from_nextsolver( + proj_predicate.projection_term.args, + interner, + ); + let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id, + substitution, + }); + let ty = match proj_predicate.term.kind() { + rustc_type_ir::TermKind::Ty(ty) => ty, + rustc_type_ir::TermKind::Const(_) => todo!(), + }; + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let alias_eq = chalk_ir::AliasEq { alias, ty }; + let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq); + chalk_ir::DomainGoal::Holds(where_clause) + } + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives( + outlives, + )) => { + let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner); + let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner); + let where_clause = + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty }); + chalk_ir::DomainGoal::Holds(where_clause) + } + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives( + outlives, + )) => { + let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner); + let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner); + let where_clause = + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b }); + chalk_ir::DomainGoal::Holds(where_clause) + } + rustc_type_ir::PredicateKind::Clause(_) => todo!(), + rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(), + rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(), + rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(), + rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(), + rustc_type_ir::PredicateKind::Ambiguous => todo!(), + rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(), + rustc_type_ir::PredicateKind::AliasRelate( + alias_term, + ty_term, + alias_relation_direction, + ) => { + let alias = match alias_term { + Term::Ty(alias_ty) => match alias_ty.kind() { + rustc_type_ir::TyKind::Alias(kind, alias) => match kind { + rustc_type_ir::AliasTyKind::Projection => { + let associated_ty_id = match alias.def_id { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => todo!(), + }; + let substitution = + ChalkToNextSolver::from_nextsolver(alias.args, interner); + let proj_ty = + chalk_ir::ProjectionTy { associated_ty_id, substitution }; + chalk_ir::AliasTy::Projection(proj_ty) + } + _ => todo!(), + }, + _ => todo!(), + }, + Term::Const(..) => todo!(), + }; + let ty = match ty_term { + Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner), + Term::Const(..) => todo!(), + }; + let alias_eq = chalk_ir::AliasEq { alias, ty }; + chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq(alias_eq)) + } + }; + domain_goal + } } impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef { @@ -871,6 +1705,15 @@ impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef let args = self.substitution.to_nextsolver(interner); TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args) } + + fn from_nextsolver(out: TraitRef<'db>, interner: DbInterner<'db>) -> Self { + let trait_id = match out.def_id { + SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + let substitution = ChalkToNextSolver::from_nextsolver(out.args, interner); + chalk_ir::TraitRef { trait_id, substitution } + } } impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause { @@ -911,6 +1754,10 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause, interner: DbInterner<'db>) -> Self { + todo!() + } } pub fn convert_canonical_args_for_result<'db>( @@ -956,7 +1803,10 @@ pub fn convert_canonical_args_for_result<'db>( binders, value: chalk_ir::ConstrainedSubst { constraints: chalk_ir::Constraints::empty(Interner), - subst: convert_args_for_result(interner, &value), + subst: ChalkToNextSolver::from_nextsolver( + GenericArgs::new_from_iter(interner, value), + interner, + ), }, } } @@ -1047,7 +1897,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::TyKind::Adt(def, args) => { let adt_id = def.inner().id; - let subst = convert_args_for_result(interner, args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(args, interner); TyKind::Adt(chalk_ir::AdtId(adt_id), subst) } @@ -1062,11 +1912,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::InferTy::FloatVar(var) => { (InferenceVar::from(var.as_u32()), TyVariableKind::Float) } - rustc_type_ir::InferTy::FreshFloatTy(..) - | rustc_type_ir::InferTy::FreshIntTy(..) - | rustc_type_ir::InferTy::FreshTy(..) => { - panic!("Freshening shouldn't happen.") - } + _ => todo!(), }; TyKind::InferenceVar(var, kind) } @@ -1086,7 +1932,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) let subst = Substitution::from_iter( Interner, tys.iter().map(|ty| { - chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty)) + chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver(ty, interner)) .intern(Interner) }), ); @@ -1094,8 +1940,8 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) } rustc_type_ir::TyKind::Array(ty, const_) => { - let ty = convert_ty_for_result(interner, ty); - let const_ = convert_const_for_result(interner, const_); + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let const_ = ChalkToNextSolver::from_nextsolver(const_, interner); TyKind::Array(ty, const_) } @@ -1106,7 +1952,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) _ => unreachable!(), }; let associated_ty_id = to_assoc_type_id(assoc_ty_id); - let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); + let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); TyKind::AssociatedType(associated_ty_id, substitution) } rustc_type_ir::AliasTyKind::Opaque => { @@ -1114,14 +1960,14 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedOpaqueTyId(id) => id, _ => unreachable!(), }; - let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); + let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id: opaque_ty_id.into(), substitution, })) } - rustc_type_ir::AliasTyKind::Inherent => unimplemented!(), - rustc_type_ir::AliasTyKind::Free => unimplemented!(), + rustc_type_ir::AliasTyKind::Inherent => todo!(), + rustc_type_ir::AliasTyKind::Free => todo!(), }, // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion. @@ -1156,7 +2002,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) interner, bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), ); - let substitution = convert_args_for_result(interner, args.as_slice()); + let substitution = ChalkToNextSolver::from_nextsolver(args, interner); let substitution = chalk_ir::FnSubst(substitution); let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; TyKind::Function(fnptr) @@ -1199,11 +2045,11 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) let trait_ref = TraitRef::new( interner, trait_ref.def_id, - [self_ty.into()].into_iter().chain(trait_ref.args.iter()), + [self_ty.clone().into()].into_iter().chain(trait_ref.args.iter()), ); let trait_id = to_chalk_trait_id(trait_ref.def_id.0); let substitution = - convert_args_for_result(interner, trait_ref.args.as_slice()); + ChalkToNextSolver::from_nextsolver(trait_ref.args, interner); let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; chalk_ir::WhereClause::Implemented(trait_ref) } @@ -1221,19 +2067,19 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) projection_term: AliasTerm::new( interner, existential_projection.def_id, - [self_ty.into()] + [self_ty.clone().into()] .iter() - .chain(existential_projection.args.iter()), + .chain(existential_projection.args.clone().iter()), ), - term: existential_projection.term, + term: existential_projection.term.clone(), }; let associated_ty_id = match projection.projection_term.def_id { SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), _ => unreachable!(), }; - let substitution = convert_args_for_result( + let substitution = ChalkToNextSolver::from_nextsolver( + projection.projection_term.args, interner, - projection.projection_term.args.as_slice(), ); let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id, @@ -1243,7 +2089,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) Term::Ty(ty) => ty, _ => unreachable!(), }; - let ty = convert_ty_for_result(interner, ty); + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); let alias_eq = chalk_ir::AliasEq { alias, ty }; chalk_ir::WhereClause::AliasEq(alias_eq) } @@ -1262,7 +2108,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) } rustc_type_ir::TyKind::Slice(ty) => { - let ty = convert_ty_for_result(interner, ty); + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); TyKind::Slice(ty) } @@ -1273,24 +2119,29 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) }; TyKind::Foreign(to_foreign_def_id(def_id)) } - rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(), + rustc_type_ir::TyKind::Pat(_, _) => todo!(), rustc_type_ir::TyKind::RawPtr(ty, mutability) => { let mutability = match mutability { rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, }; - let ty = convert_ty_for_result(interner, ty); + let ty = ChalkToNextSolver::from_nextsolver(ty, interner); TyKind::Raw(mutability, ty) } rustc_type_ir::TyKind::FnDef(def_id, args) => { - let id = match def_id { - SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), - SolverDefId::Ctor(Ctor::Struct(id)) => CallableDefId::StructId(id), - SolverDefId::Ctor(Ctor::Enum(id)) => CallableDefId::EnumVariantId(id), - _ => unreachable!(), - }; - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::FnDef(id.to_chalk(interner.db()), subst) + let subst = ChalkToNextSolver::from_nextsolver(args, interner); + match def_id { + SolverDefId::FunctionId(id) => { + TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst) + } + SolverDefId::Ctor(Ctor::Enum(e)) => { + TyKind::FnDef(CallableDefId::EnumVariantId(e).to_chalk(interner.db()), subst) + } + SolverDefId::Ctor(Ctor::Struct(s)) => { + TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst) + } + _ => unreachable!("Unexpected def id {:?}", def_id), + } } rustc_type_ir::TyKind::Closure(def_id, args) => { @@ -1298,16 +2149,16 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedClosureId(id) => id, _ => unreachable!(), }; - let subst = convert_args_for_result(interner, args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(args, interner); TyKind::Closure(id.into(), subst) } - rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(), + rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(), rustc_type_ir::TyKind::Coroutine(def_id, args) => { let id = match def_id { SolverDefId::InternedCoroutineId(id) => id, _ => unreachable!(), }; - let subst = convert_args_for_result(interner, args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(args, interner); TyKind::Coroutine(id.into(), subst) } rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { @@ -1315,7 +2166,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedCoroutineId(id) => id, _ => unreachable!(), }; - let subst = convert_args_for_result(interner, args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(args, interner); TyKind::CoroutineWitness(id.into(), subst) } @@ -1419,3 +2270,17 @@ pub fn convert_region_for_result<'db>( }; chalk_ir::Lifetime::new(Interner, lifetime) } + +pub trait InferenceVarExt { + fn to_vid(self) -> rustc_type_ir::TyVid; + fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar; +} + +impl InferenceVarExt for InferenceVar { + fn to_vid(self) -> rustc_type_ir::TyVid { + rustc_type_ir::TyVid::from_u32(self.index()) + } + fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar { + InferenceVar::from(vid.as_u32()) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 1d0ee0e488dcf..b9b2950a94a3b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -14,7 +14,7 @@ use crate::{ db::HirDatabase, next_solver::{ ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, - mapping::{ChalkToNextSolver, convert_args_for_result}, + mapping::ChalkToNextSolver, util::sizedness_fast_path, }, }; @@ -200,7 +200,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { SolverDefId::StaticId(c) => GeneralConstId::StaticId(c), _ => unreachable!(), }; - let subst = convert_args_for_result(self.interner, uv.args.as_slice()); + let subst = ChalkToNextSolver::from_nextsolver(uv.args, self.interner); let ec = self.cx().db.const_eval(c, subst, None).ok()?; Some(ec.to_nextsolver(self.interner)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 51cf5be1372ca..0c58e031c3a0f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -1,6 +1,7 @@ //! Trait solving using Chalk. use core::fmt; +use std::hash::Hash; use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable}; use chalk_solve::rust_ir; @@ -20,17 +21,9 @@ use stdx::never; use triomphe::Arc; use crate::{ - AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, - ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, - db::HirDatabase, - infer::unify::InferenceTable, - next_solver::{ - DbInterner, GenericArg, SolverContext, Span, - infer::{DbInternerInferExt, InferCtxt}, - mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, - util::mini_canonicalize, - }, - utils::UnevaluatedConstEvaluatorFolder, + db::HirDatabase, infer::unify::InferenceTable, next_solver::{ + infer::{DbInternerInferExt, InferCtxt}, mapping::{convert_canonical_args_for_result, ChalkToNextSolver}, util::mini_canonicalize, DbInterner, GenericArg, Predicate, SolverContext, Span + }, utils::UnevaluatedConstEvaluatorFolder, AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause }; /// A set of clauses that we assume to be true. E.g. if we are inside this function: @@ -231,7 +224,6 @@ impl NextTraitSolveResult { } } -/// Solve a trait goal using Chalk. pub fn next_trait_solve( db: &dyn HirDatabase, krate: Crate, @@ -290,6 +282,57 @@ pub fn next_trait_solve( } } +pub fn next_trait_solve_canonical<'db>( + db: &'db dyn HirDatabase, + krate: Crate, + block: Option, + goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>, +) -> NextTraitSolveResult { + // FIXME: should use analysis_in_body, but that needs GenericDefId::Block + let context = SolverContext( + DbInterner::new_with(db, Some(krate), block) + .infer_ctxt() + .build(TypingMode::non_body_analysis()), + ); + + tracing::info!(?goal); + + let (goal, var_values) = + context.instantiate_canonical(&goal); + tracing::info!(?var_values); + + let res = context.evaluate_root_goal( + goal.clone(), + Span::dummy(), + None + ); + + let vars = + var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect(); + let canonical_var_values = mini_canonicalize(context, vars); + + let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values)); + + tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); + + match res { + Err(_) => NextTraitSolveResult::NoSolution, + Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( + convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args) + ), + Ok((_, Certainty::Maybe(_), args)) => { + let subst = convert_canonical_args_for_result( + DbInterner::new_with(db, Some(krate), block), + args, + ); + NextTraitSolveResult::Uncertain(chalk_ir::Canonical { + binders: subst.binders, + value: subst.value.subst, + }) + } + } +} + /// Solve a trait goal using Chalk. pub fn next_trait_solve_in_ctxt<'db, 'a>( infer_ctxt: &'a InferCtxt<'db>, diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 928753ef0edeb..79a154a5d8e6e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -14,7 +14,7 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::Name, }; -use hir_ty::{db::HirDatabase, method_resolution}; +use hir_ty::{db::HirDatabase, method_resolution, next_solver::{mapping::ChalkToNextSolver, DbInterner}}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -271,7 +271,7 @@ fn resolve_impl_trait_item<'db>( // // FIXME: resolve type aliases (which are not yielded by iterate_path_candidates) _ = method_resolution::iterate_path_candidates( - &canonical, + &canonical.to_nextsolver(DbInterner::new_with(db, Some(environment.krate), environment.block)), db, environment, &traits_in_scope, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 6eb8a8bf60fd1..52ab808d22841 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -5611,7 +5611,11 @@ impl<'db> Type<'db> { .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); _ = method_resolution::iterate_method_candidates_dyn( - &canonical, + &canonical.to_nextsolver(DbInterner::new_with( + db, + Some(environment.krate), + environment.block, + )), db, environment, traits_in_scope, @@ -5698,7 +5702,11 @@ impl<'db> Type<'db> { .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); _ = method_resolution::iterate_path_candidates( - &canonical, + &canonical.to_nextsolver(DbInterner::new_with( + db, + Some(environment.krate), + environment.block, + )), db, environment, traits_in_scope, From 69140ec44c2f57497ae2375a6f75f0bfe76b8003 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 29 Aug 2025 21:47:10 +0900 Subject: [PATCH 177/251] Fix failing tests and fill-in missing details --- .../crates/hir-ty/src/autoderef.rs | 14 +- .../crates/hir-ty/src/chalk_ext.rs | 41 +- .../crates/hir-ty/src/consteval_nextsolver.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 28 +- .../crates/hir-ty/src/infer/closure.rs | 12 +- .../crates/hir-ty/src/infer/coerce.rs | 67 +- .../crates/hir-ty/src/infer/expr.rs | 57 +- .../crates/hir-ty/src/infer/pat.rs | 12 +- .../crates/hir-ty/src/infer/path.rs | 12 +- .../crates/hir-ty/src/infer/unify.rs | 472 +++++---- .../rust-analyzer/crates/hir-ty/src/lib.rs | 11 +- .../crates/hir-ty/src/method_resolution.rs | 223 ++-- .../rust-analyzer/crates/hir-ty/src/mir.rs | 3 +- .../crates/hir-ty/src/mir/monomorphization.rs | 26 +- .../crates/hir-ty/src/next_solver.rs | 4 +- .../infer/canonical/canonicalizer.rs | 136 ++- .../hir-ty/src/next_solver/infer/mod.rs | 25 +- .../crates/hir-ty/src/next_solver/mapping.rs | 974 ++++-------------- .../crates/hir-ty/src/next_solver/solver.rs | 6 +- .../crates/hir-ty/src/tests/coercion.rs | 14 +- .../crates/hir-ty/src/tests/incremental.rs | 6 +- .../crates/hir-ty/src/tests/macros.rs | 4 +- .../hir-ty/src/tests/method_resolution.rs | 10 +- .../crates/hir-ty/src/tests/never_type.rs | 24 +- .../crates/hir-ty/src/tests/opaque_types.rs | 4 +- .../crates/hir-ty/src/tests/patterns.rs | 26 +- .../crates/hir-ty/src/tests/regression.rs | 12 +- .../hir-ty/src/tests/regression/new_solver.rs | 2 +- .../crates/hir-ty/src/tests/simple.rs | 4 +- .../crates/hir-ty/src/tests/traits.rs | 28 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 43 +- .../rust-analyzer/crates/hir/src/attrs.rs | 12 +- .../ide-completion/src/context/tests.rs | 3 +- .../src/handlers/type_mismatch.rs | 3 +- .../rust-analyzer/crates/ide-ssr/src/tests.rs | 15 +- .../crates/ide/src/doc_links/tests.rs | 3 +- 36 files changed, 914 insertions(+), 1428 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 4ea0156e1248a..82696a5c94daf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -13,7 +13,7 @@ use triomphe::Arc; use crate::{ Canonical, Goal, Interner, ProjectionTyExt, TraitEnvironment, Ty, TyBuilder, TyKind, - db::HirDatabase, infer::unify::InferenceTable, + db::HirDatabase, infer::unify::InferenceTable, next_solver::mapping::ChalkToNextSolver, }; const AUTODEREF_RECURSION_LIMIT: usize = 20; @@ -98,7 +98,7 @@ impl<'table, 'db> Autoderef<'table, 'db> { explicit: bool, use_receiver_trait: bool, ) -> Self { - let ty = table.resolve_ty_shallow(&ty); + let ty = table.structurally_resolve_type(&ty); Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait } } @@ -114,7 +114,7 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> { explicit: bool, use_receiver_trait: bool, ) -> Self { - let ty = table.resolve_ty_shallow(&ty); + let ty = table.structurally_resolve_type(&ty); Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait } } } @@ -160,7 +160,7 @@ pub(crate) fn autoderef_step( use_receiver_trait: bool, ) -> Option<(AutoderefKind, Ty)> { if let Some(derefed) = builtin_deref(table.db, &ty, explicit) { - Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed))) + Some((AutoderefKind::Builtin, table.structurally_resolve_type(derefed))) } else { Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?)) } @@ -187,7 +187,7 @@ pub(crate) fn deref_by_trait( use_receiver_trait: bool, ) -> Option { let _p = tracing::info_span!("deref_by_trait").entered(); - if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() { + if table.structurally_resolve_type(&ty).inference_var(Interner).is_some() { // don't try to deref unknown variables return None; } @@ -229,8 +229,8 @@ pub(crate) fn deref_by_trait( return None; } - table.register_obligation(implements_goal); + table.register_obligation(implements_goal.to_nextsolver(table.interner)); let result = table.normalize_projection_ty(projection); - Some(table.resolve_ty_shallow(&result)) + Some(table.structurally_resolve_type(&result)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 33ae099c690ea..9f0ea14a8063d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -245,26 +245,30 @@ impl TyExt for Ty { } fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option> { + let handle_async_block_type_impl_trait = |def: DefWithBodyId| { + let krate = def.module(db).krate(); + if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { + // This is only used by type walking. + // Parameters will be walked outside, and projection predicate is not used. + // So just provide the Future trait. + let impl_bound = Binders::empty( + Interner, + WhereClause::Implemented(TraitRef { + trait_id: to_chalk_trait_id(future_trait), + substitution: Substitution::empty(Interner), + }), + ); + Some(vec![impl_bound]) + } else { + None + } + }; + match self.kind(Interner) { TyKind::OpaqueType(opaque_ty_id, subst) => { match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { - let krate = def.module(db).krate(); - if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { - // This is only used by type walking. - // Parameters will be walked outside, and projection predicate is not used. - // So just provide the Future trait. - let impl_bound = Binders::empty( - Interner, - WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(future_trait), - substitution: Substitution::empty(Interner), - }), - ); - Some(vec![impl_bound]) - } else { - None - } + handle_async_block_type_impl_trait(def) } ImplTraitId::ReturnTypeImplTrait(func, idx) => { db.return_type_impl_traits(func).map(|it| { @@ -299,8 +303,9 @@ impl TyExt for Ty { data.substitute(Interner, &opaque_ty.substitution) }) } - // It always has an parameter for Future::Output type. - ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(), + ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { + return handle_async_block_type_impl_trait(def); + } }; predicates.map(|it| it.into_value_and_skipped_binders().0) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index 4700335931549..6e07d3afe5524 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -27,7 +27,7 @@ use crate::{ next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, SolverDefId, Ty, ValueConst, - mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_binder_to_early_binder}, }, }; @@ -145,7 +145,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option GeneralConstId::StaticId(id), _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); + let subst = unevaluated_const.args.to_chalk(interner); let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); try_const_usize(db, ec) } @@ -168,7 +168,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); + let subst = unevaluated_const.args.to_chalk(interner); let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); try_const_isize(db, &ec) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 71b33a0e9035f..265d1f8541cc8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -55,10 +55,9 @@ use stdx::{always, never}; use triomphe::Arc; use crate::{ - AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId, - ImplTraitIdx, InEnvironment, IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, - ParamLoweringMode, PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty, - TyBuilder, TyExt, + AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, + IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, + PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, db::HirDatabase, fold_tys, generics::Generics, @@ -70,6 +69,7 @@ use crate::{ }, lower::{ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic}, mir::MirSpan, + next_solver::{self, mapping::ChalkToNextSolver}, static_lifetime, to_assoc_type_id, traits::FnTrait, utils::UnevaluatedConstEvaluatorFolder, @@ -182,13 +182,13 @@ impl BindingMode { } #[derive(Debug)] -pub(crate) struct InferOk { +pub(crate) struct InferOk<'db, T> { value: T, - goals: Vec>, + goals: Vec>>, } -impl InferOk { - fn map(self, f: impl FnOnce(T) -> U) -> InferOk { +impl<'db, T> InferOk<'db, T> { + fn map(self, f: impl FnOnce(T) -> U) -> InferOk<'db, U> { InferOk { value: f(self.value), goals: self.goals } } } @@ -203,7 +203,7 @@ pub enum InferenceTyDiagnosticSource { #[derive(Debug)] pub(crate) struct TypeError; -pub(crate) type InferResult = Result, TypeError>; +pub(crate) type InferResult<'db, T> = Result, TypeError>; #[derive(Debug, PartialEq, Eq, Clone)] pub enum InferenceDiagnostic { @@ -832,6 +832,7 @@ impl<'db> InferenceContext<'db> { coercion_casts, diagnostics: _, } = &mut result; + table.resolve_obligations_as_possible(); table.fallback_if_possible(); // Comment from rustc: @@ -1480,7 +1481,8 @@ impl<'db> InferenceContext<'db> { } fn push_obligation(&mut self, o: DomainGoal) { - self.table.register_obligation(o.cast(Interner)); + let goal: crate::Goal = o.cast(Interner); + self.table.register_obligation(goal.to_nextsolver(self.table.interner)); } fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { @@ -1746,7 +1748,7 @@ impl<'db> InferenceContext<'db> { ty = self.table.insert_type_vars(ty); ty = self.table.normalize_associated_types_in(ty); - ty = self.table.resolve_ty_shallow(&ty); + ty = self.table.structurally_resolve_type(&ty); if ty.is_unknown() { return (self.err_ty(), None); } @@ -1817,7 +1819,7 @@ impl<'db> InferenceContext<'db> { let ty = match ty.kind(Interner) { TyKind::Alias(AliasTy::Projection(proj_ty)) => { let ty = self.table.normalize_projection_ty(proj_ty.clone()); - self.table.resolve_ty_shallow(&ty) + self.table.structurally_resolve_type(&ty) } _ => ty, }; @@ -2047,7 +2049,7 @@ impl Expectation { fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { match self { Expectation::HasType(ety) => { - let ety = table.resolve_ty_shallow(ety); + let ety = table.structurally_resolve_type(ety); if ety.is_ty_var() { Expectation::None } else { Expectation::HasType(ety) } } Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 493652b764015..5a69ad68b58e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -39,6 +39,7 @@ use crate::{ infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever}, make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, + next_solver::mapping::ChalkToNextSolver, to_assoc_type_id, traits::FnTrait, utils::{self, elaborate_clause_supertraits}, @@ -437,10 +438,10 @@ impl InferenceContext<'_> { associated_ty_id: to_assoc_type_id(future_output), substitution: Substitution::from1(Interner, ret_param_future.clone()), }); - self.table.register_obligation( + let goal: crate::Goal = crate::AliasEq { alias: future_projection, ty: ret_param_future_output.clone() } - .cast(Interner), - ); + .cast(Interner); + self.table.register_obligation(goal.to_nextsolver(self.table.interner)); Some(FnSubst(Substitution::from_iter( Interner, @@ -568,7 +569,10 @@ impl InferenceContext<'_> { let supplied_sig = self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind); let snapshot = self.table.snapshot(); - if !self.table.unify::<_, crate::next_solver::GenericArgs<'_>>(&expected_sig.substitution.0, &supplied_sig.expected_sig.substitution.0) { + if !self.table.unify::<_, crate::next_solver::GenericArgs<'_>>( + &expected_sig.substitution.0, + &supplied_sig.expected_sig.substitution.0, + ) { self.table.rollback_to(snapshot); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index b47834f0c749c..df516662bfd37 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -8,24 +8,27 @@ use std::iter; use chalk_ir::{BoundVar, Mutability, TyKind, TyVariableKind, cast::Cast}; -use hir_def::{ - hir::ExprId, - lang_item::LangItem, -}; +use hir_def::{hir::ExprId, lang_item::LangItem}; use rustc_type_ir::solve::Certainty; use stdx::always; use triomphe::Arc; use crate::{ - autoderef::{Autoderef, AutoderefKind}, db::HirDatabase, infer::{ + Canonical, FnAbi, FnPointer, FnSig, Goal, Interner, Lifetime, Substitution, TraitEnvironment, + Ty, TyBuilder, TyExt, + autoderef::{Autoderef, AutoderefKind}, + db::HirDatabase, + infer::{ Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, TypeError, TypeMismatch, - }, utils::ClosureSubst, Canonical, FnAbi, FnPointer, FnSig, Goal, InEnvironment, Interner, Lifetime, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt + }, + next_solver, + utils::ClosureSubst, }; use super::unify::InferenceTable; -pub(crate) type CoerceResult = Result, Ty)>, TypeError>; +pub(crate) type CoerceResult<'db> = Result, Ty)>, TypeError>; /// Do not require any adjustments, i.e. coerce `x -> x`. fn identity(_: Ty) -> Vec { @@ -37,11 +40,11 @@ fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec { } /// This always returns `Ok(...)`. -fn success( +fn success<'db>( adj: Vec, target: Ty, - goals: Vec>, -) -> CoerceResult { + goals: Vec>>, +) -> CoerceResult<'db> { Ok(InferOk { goals, value: (adj, target) }) } @@ -107,9 +110,9 @@ impl CoerceMany { /// coerce both to function pointers; /// - if we were concerned with lifetime subtyping, we'd need to look for a /// least upper bound. - pub(super) fn coerce( + pub(super) fn coerce<'db>( &mut self, - ctx: &mut InferenceContext<'_>, + ctx: &mut InferenceContext<'db>, expr: Option, expr_ty: &Ty, cause: CoercionCause, @@ -276,7 +279,7 @@ impl InferenceContext<'_> { } } -impl InferenceTable<'_> { +impl<'db> InferenceTable<'db> { /// Unify two types, but may coerce the first one to the second one /// using "implicit coercion rules" if needed. pub(crate) fn coerce( @@ -285,8 +288,8 @@ impl InferenceTable<'_> { to_ty: &Ty, coerce_never: CoerceNever, ) -> Result<(Vec, Ty), TypeError> { - let from_ty = self.resolve_ty_shallow(from_ty); - let to_ty = self.resolve_ty_shallow(to_ty); + let from_ty = self.structurally_resolve_type(from_ty); + let to_ty = self.structurally_resolve_type(to_ty); match self.coerce_inner(from_ty, &to_ty, coerce_never) { Ok(InferOk { value: (adjustments, ty), goals }) => { self.register_infer_ok(InferOk { value: (), goals }); @@ -299,10 +302,15 @@ impl InferenceTable<'_> { } } - fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty, coerce_never: CoerceNever) -> CoerceResult { + fn coerce_inner( + &mut self, + from_ty: Ty, + to_ty: &Ty, + coerce_never: CoerceNever, + ) -> CoerceResult<'db> { if from_ty.is_never() { if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) { - self.set_diverging(*tv, TyVariableKind::General, true); + self.set_diverging(*tv, TyVariableKind::General); } if coerce_never == CoerceNever::Yes { // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound @@ -370,7 +378,7 @@ impl InferenceTable<'_> { } /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&mut self, t1: &Ty, t2: &Ty, f: F) -> CoerceResult + fn unify_and(&mut self, t1: &Ty, t2: &Ty, f: F) -> CoerceResult<'db> where F: FnOnce(Ty) -> Vec, { @@ -378,7 +386,7 @@ impl InferenceTable<'_> { .and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals)) } - fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult { + fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult<'db> { let (is_ref, from_mt, from_inner) = match from_ty.kind(Interner) { TyKind::Ref(mt, _, ty) => (true, mt, ty), TyKind::Raw(mt, ty) => (false, mt, ty), @@ -420,7 +428,7 @@ impl InferenceTable<'_> { to_ty: &Ty, to_mt: Mutability, to_lt: &Lifetime, - ) -> CoerceResult { + ) -> CoerceResult<'db> { let (_from_lt, from_mt) = match from_ty.kind(Interner) { TyKind::Ref(mt, lt, _) => { coerce_mutabilities(*mt, to_mt)?; @@ -524,7 +532,7 @@ impl InferenceTable<'_> { } /// Attempts to coerce from the type of a Rust function item into a function pointer. - fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult { + fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult<'db> { match to_ty.kind(Interner) { TyKind::Function(_) => { let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig"); @@ -566,7 +574,7 @@ impl InferenceTable<'_> { from_ty: Ty, from_f: &FnPointer, to_ty: &Ty, - ) -> CoerceResult { + ) -> CoerceResult<'db> { self.coerce_from_safe_fn( from_ty, from_f, @@ -583,7 +591,7 @@ impl InferenceTable<'_> { to_ty: &Ty, to_unsafe: F, normal: G, - ) -> CoerceResult + ) -> CoerceResult<'db> where F: FnOnce(Ty) -> Vec, G: FnOnce(Ty) -> Vec, @@ -606,7 +614,7 @@ impl InferenceTable<'_> { from_ty: Ty, from_substs: &Substitution, to_ty: &Ty, - ) -> CoerceResult { + ) -> CoerceResult<'db> { match to_ty.kind(Interner) { // if from_substs is non-capturing (FIXME) TyKind::Function(fn_ty) => { @@ -631,7 +639,7 @@ impl InferenceTable<'_> { /// Coerce a type using `from_ty: CoerceUnsized` /// /// See: - fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult { + fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult<'db> { // These 'if' statements require some explanation. // The `CoerceUnsized` trait is special - it is only // possible to write `impl CoerceUnsized for A` where @@ -707,12 +715,9 @@ impl InferenceTable<'_> { let goal: Goal = coerce_unsized_tref.cast(Interner); - self.commit_if_ok(|table| { - match table.solve_obligation(goal) { - Ok(Certainty::Yes) => Ok(()), - Ok(Certainty::Maybe(_)) => Ok(()), - Err(_) => Err(TypeError), - } + self.commit_if_ok(|table| match table.solve_obligation(goal) { + Ok(Certainty::Yes) => Ok(()), + _ => Err(TypeError), })?; let unsize = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index e39f3ab75f16f..bfeb5bae851a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -23,9 +23,29 @@ use stdx::always; use syntax::ast::RangeOp; use crate::{ - autoderef::{builtin_deref, deref_by_trait, Autoderef}, consteval, generics::generics, infer::{ - coerce::{CoerceMany, CoerceNever, CoercionCause}, find_continuable, pat::contains_explicit_ref_binding, BreakableKind - }, lang_items::lang_items_for_bin_op, lower::{lower_to_chalk_mutability, path::{substs_from_args_and_bindings, GenericArgsLowerer, TypeLikeConst}, ParamLoweringMode}, mapping::{from_chalk, ToChalk}, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind + Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, + DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, + Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, + autoderef::{Autoderef, builtin_deref, deref_by_trait}, + consteval, + generics::generics, + infer::{ + BreakableKind, + coerce::{CoerceMany, CoerceNever, CoercionCause}, + find_continuable, + pat::contains_explicit_ref_binding, + }, + lang_items::lang_items_for_bin_op, + lower::{ + ParamLoweringMode, lower_to_chalk_mutability, + path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings}, + }, + mapping::{ToChalk, from_chalk}, + method_resolution::{self, VisibleFromModule}, + next_solver::mapping::ChalkToNextSolver, + primitive::{self, UintTy}, + static_lifetime, to_chalk_trait_id, + traits::FnTrait, }; use super::{ @@ -383,7 +403,7 @@ impl InferenceContext<'_> { let matchee_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let mut all_arms_diverge = Diverges::Always; for arm in arms.iter() { - let input_ty = self.resolve_ty_shallow(&input_ty); + let input_ty = self.table.structurally_resolve_type(&input_ty); self.infer_top_pat(arm.pat, &input_ty, None); } @@ -633,7 +653,7 @@ impl InferenceContext<'_> { &Expr::Box { expr } => self.infer_expr_box(expr, expected), Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none(), ExprIsRead::Yes); - let inner_ty = self.resolve_ty_shallow(&inner_ty); + let inner_ty = self.table.structurally_resolve_type(&inner_ty); // FIXME: Note down method resolution her match op { UnaryOp::Deref => { @@ -651,7 +671,7 @@ impl InferenceContext<'_> { ); } if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) { - self.resolve_ty_shallow(derefed) + self.table.structurally_resolve_type(derefed) } else { deref_by_trait(&mut self.table, inner_ty, false) .unwrap_or_else(|| self.err_ty()) @@ -807,10 +827,10 @@ impl InferenceContext<'_> { let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes); if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) { - let canonicalized = ChalkToNextSolver::from_nextsolver(self.canonicalize(base_ty.clone().to_nextsolver(self.table.interner)), self.table.interner); + let canonicalized = + self.canonicalize(base_ty.clone().to_nextsolver(self.table.interner)); let receiver_adjustments = method_resolution::resolve_indexing_op( - self.db, - self.table.trait_env.clone(), + &mut self.table, canonicalized, index_trait, ); @@ -983,7 +1003,7 @@ impl InferenceContext<'_> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = this.resolve_ty_shallow(&ty); + let ty = this.table.structurally_resolve_type(&ty); match ty.kind(Interner) { TyKind::FnDef(def, parameters) => { let fnptr_ty = TyKind::Function( @@ -1405,9 +1425,10 @@ impl InferenceContext<'_> { // use knowledge of built-in binary ops, which can sometimes help inference let builtin_ret = self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op); self.unify(&builtin_ret, &ret_ty); + builtin_ret + } else { + ret_ty } - - ret_ty } fn infer_block( @@ -1660,7 +1681,8 @@ impl InferenceContext<'_> { None => { // no field found, lets attempt to resolve it like a function so that IDE things // work out while people are typing - let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); + let canonicalized_receiver = + self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); let resolved = method_resolution::lookup_method( self.db, &canonicalized_receiver, @@ -1806,7 +1828,8 @@ impl InferenceContext<'_> { expected: &Expectation, ) -> Ty { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes); - let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); + let canonicalized_receiver = + self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); let resolved = method_resolution::lookup_method( self.db, @@ -2216,7 +2239,7 @@ impl InferenceContext<'_> { } fn register_obligations_for_call(&mut self, callable_ty: &Ty) { - let callable_ty = self.resolve_ty_shallow(callable_ty); + let callable_ty = self.table.structurally_resolve_type(callable_ty); if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) { let def: CallableDefId = from_chalk(self.db, *fn_def); let generic_predicates = @@ -2305,9 +2328,9 @@ impl InferenceContext<'_> { /// Dereferences a single level of immutable referencing. fn deref_ty_if_possible(&mut self, ty: &Ty) -> Ty { - let ty = self.resolve_ty_shallow(ty); + let ty = self.table.structurally_resolve_type(ty); match ty.kind(Interner) { - TyKind::Ref(Mutability::Not, _, inner) => self.resolve_ty_shallow(inner), + TyKind::Ref(Mutability::Not, _, inner) => self.table.structurally_resolve_type(inner), _ => ty, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 707bec0fce4ce..16489e3068f35 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -190,7 +190,7 @@ impl InferenceContext<'_> { subs: &[PatId], decl: Option, ) -> Ty { - let expected = self.resolve_ty_shallow(expected); + let expected = self.table.structurally_resolve_type(expected); let expectations = match expected.as_tuple() { Some(parameters) => parameters.as_slice(Interner), _ => &[], @@ -238,7 +238,7 @@ impl InferenceContext<'_> { mut default_bm: BindingMode, decl: Option, ) -> Ty { - let mut expected = self.resolve_ty_shallow(expected); + let mut expected = self.table.structurally_resolve_type(expected); if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { cov_mark::hit!(match_ergonomics_ref); @@ -251,7 +251,7 @@ impl InferenceContext<'_> { let mut pat_adjustments = Vec::new(); while let Some((inner, _lifetime, mutability)) = expected.as_reference() { pat_adjustments.push(expected.clone()); - expected = self.resolve_ty_shallow(inner); + expected = self.table.structurally_resolve_type(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), @@ -494,7 +494,7 @@ impl InferenceContext<'_> { default_bm: BindingMode, decl: Option, ) -> Ty { - let expected = self.resolve_ty_shallow(expected); + let expected = self.table.structurally_resolve_type(expected); // If `expected` is an infer ty, we try to equate it to an array if the given pattern // allows it. See issue #16609 @@ -506,7 +506,7 @@ impl InferenceContext<'_> { self.unify(&expected, &resolved_array_ty); } - let expected = self.resolve_ty_shallow(&expected); + let expected = self.table.structurally_resolve_type(&expected); let elem_ty = match expected.kind(Interner) { TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), _ => self.err_ty(), @@ -542,7 +542,7 @@ impl InferenceContext<'_> { if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] && let Some((inner, ..)) = expected.as_reference() { - let inner = self.resolve_ty_shallow(inner); + let inner = self.table.structurally_resolve_type(inner); if matches!(inner.kind(Interner), TyKind::Slice(_)) { let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); let slice_ty = TyKind::Slice(elem_ty).intern(Interner); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 9f3cd2b8fb006..1f62f9c4aa113 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -10,7 +10,15 @@ use hir_expand::name::Name; use stdx::never; use crate::{ - builder::ParamKind, consteval, error_lifetime, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, method_resolution::{self, VisibleFromModule}, next_solver::mapping::ChalkToNextSolver, to_chalk_trait_id, InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId + InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, + TyBuilder, TyExt, TyKind, ValueTyDefId, + builder::ParamKind, + consteval, error_lifetime, + generics::generics, + infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, + method_resolution::{self, VisibleFromModule}, + next_solver::mapping::ChalkToNextSolver, + to_chalk_trait_id, }; use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; @@ -384,7 +392,7 @@ impl InferenceContext<'_> { name: &Name, id: ExprOrPatId, ) -> Option<(ValueNs, Substitution)> { - let ty = self.resolve_ty_shallow(ty); + let ty = self.table.structurally_resolve_type(ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 3745d2c98fd9f..ec4b7ee85dc67 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use chalk_ir::{ - cast::Cast, fold::TypeFoldable, interner::HasInterner, CanonicalVarKind, FloatTy, IntTy, TyVariableKind, + CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable, + interner::HasInterner, }; use either::Either; use hir_def::{AdtId, lang_item::LangItem}; @@ -11,13 +12,36 @@ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_next_trait_solver::solve::HasChanged; -use rustc_type_ir::{inherent::Span, relate::{solver_relating::RelateExt, Relate}, solve::{Certainty, NoSolution}, FloatVid, IntVid, TyVid}; +use rustc_type_ir::{ + AliasRelationDirection, FloatVid, IntVid, TyVid, + inherent::{Span, Term as _}, + relate::{Relate, solver_relating::RelateExt}, + solve::{Certainty, NoSolution}, +}; use smallvec::SmallVec; use triomphe::Arc; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{infer::{canonical::canonicalizer::OriginalQueryValues, snapshot::CombinedSnapshot, DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, InferenceVarExt}, DbInterner, ParamEnvAnd, SolverDefIds}, to_chalk_trait_id, traits::{next_trait_solve, next_trait_solve_canonical, next_trait_solve_in_ctxt, FnTrait, NextTraitSolveResult}, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause + AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, + GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, + OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, + TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, + consteval::unknown_const, + db::HirDatabase, + fold_generic_args, fold_tys_and_consts, + next_solver::{ + self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term, + infer::{ + DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues, + snapshot::CombinedSnapshot, + }, + mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk}, + }, + to_chalk_trait_id, + traits::{ + FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, + }, }; impl<'db> InferenceContext<'db> { @@ -38,7 +62,7 @@ impl<'db> InferenceContext<'db> { let pending_obligations = mem::take(&mut self.table.pending_obligations); let obligations = pending_obligations .iter() - .filter_map(|obligation| match obligation.goal.data(Interner) { + .filter_map(|obligation| match obligation.to_chalk(self.table.interner).goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(clause)) => { let ty = match clause { WhereClause::AliasEq(AliasEq { @@ -67,51 +91,6 @@ impl<'db> InferenceContext<'db> { } } -#[derive(Debug, Clone)] -pub(crate) struct Canonicalized -where - T: HasInterner, -{ - pub(crate) value: Canonical, - free_vars: Vec, -} - -impl> Canonicalized { - pub(crate) fn apply_solution( - &self, - ctx: &mut InferenceTable<'_>, - solution: Canonical, - ) { - // the solution may contain new variables, which we need to convert to new inference vars - let new_vars = Substitution::from_iter( - Interner, - solution.binders.iter(Interner).map(|k| match &k.kind { - VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner), - VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner), - // Chalk can sometimes return new lifetime variables. We just replace them by errors - // for now. - VariableKind::Lifetime => ctx.new_lifetime_var().cast(Interner), - VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner), - }), - ); - for (i, v) in solution.value.iter(Interner).enumerate() { - let var = &self.free_vars[i]; - if let Some(ty) = v.ty(Interner) { - // eagerly replace projections in the type; we may be getting types - // e.g. from where clauses where this hasn't happened yet - let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); - tracing::debug!("unifying {:?} {:?}", var, ty); - ctx.unify(var.assert_ty_ref(Interner), &ty); - } else { - let v = new_vars.apply(v.clone(), Interner); - tracing::debug!("try_unifying {:?} {:?}", var, v); - let _ = ctx.try_unify(var, &v); - } - } - } -} - /// Check if types unify. /// /// Note that we consider placeholder types to unify with everything. @@ -207,23 +186,21 @@ bitflags::bitflags! { } } -type ChalkInferenceTable = chalk_solve::infer::InferenceTable; - #[derive(Clone)] pub(crate) struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) interner: DbInterner<'a>, pub(crate) trait_env: Arc, pub(crate) tait_coercion_table: Option>, - infer_ctxt: InferCtxt<'a>, + pub(crate) infer_ctxt: InferCtxt<'a>, diverging_tys: FxHashSet, - pending_obligations: Vec>, + pending_obligations: Vec>>, } -pub(crate) struct InferenceTableSnapshot { +pub(crate) struct InferenceTableSnapshot<'a> { ctxt_snapshot: CombinedSnapshot, diverging_tys: FxHashSet, - pending_obligations: Vec>, + pending_obligations: Vec>>, } impl<'a> InferenceTable<'a> { @@ -234,7 +211,9 @@ impl<'a> InferenceTable<'a> { interner, trait_env, tait_coercion_table: None, - infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []) }), + infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { + defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), + }), diverging_tys: FxHashSet::default(), pending_obligations: Vec::new(), } @@ -250,40 +229,55 @@ impl<'a> InferenceTable<'a> { let mut new_tys = FxHashSet::default(); for ty in self.diverging_tys.iter() { match ty.kind(Interner) { - TyKind::InferenceVar(var, kind) => { - match kind { - TyVariableKind::General => { - let root = InferenceVar::from(self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + TyKind::InferenceVar(var, kind) => match kind { + TyVariableKind::General => { + let root = InferenceVar::from( + self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } - TyVariableKind::Integer => { - let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from_usize(var.index() as usize)).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + } + TyVariableKind::Integer => { + let root = InferenceVar::from( + self.infer_ctxt + .inner + .borrow_mut() + .int_unification_table() + .find(IntVid::from_usize(var.index() as usize)) + .as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } - TyVariableKind::Float => { - let root = InferenceVar::from(self.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from_usize(var.index() as usize)).as_u32()); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } + } + TyVariableKind::Float => { + let root = InferenceVar::from( + self.infer_ctxt + .inner + .borrow_mut() + .float_unification_table() + .find(FloatVid::from_usize(var.index() as usize)) + .as_u32(), + ); + if root.index() != var.index() { + new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); } } - } + }, _ => {} } } - self.diverging_tys.extend(new_tys.into_iter()); + self.diverging_tys.extend(new_tys); } - pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind, diverging: bool) { + pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind) { self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner)); } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - let is_diverging = self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); + let is_diverging = + self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); if is_diverging { return TyKind::Never.intern(Interner); } @@ -295,19 +289,6 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize_with_free_vars(&mut self, t: ParamEnvAnd<'a, T>) -> (rustc_type_ir::Canonical, ParamEnvAnd<'a, T>>, OriginalQueryValues<'a>) - where - T: rustc_type_ir::TypeFoldable>, - { - // try to resolve obligations before canonicalizing, since this might - // result in new knowledge about variables - self.resolve_obligations_as_possible(); - - let mut orig_values = OriginalQueryValues::default(); - let result = self.infer_ctxt.canonicalize_query(t, &mut orig_values); - (result.canonical, orig_values) - } - pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where T: rustc_type_ir::TypeFoldable>, @@ -341,7 +322,7 @@ impl<'a> InferenceTable<'a> { self.resolve_ty_shallow(&ty) } TyKind::AssociatedType(id, subst) => { - return Either::Left(self.resolve_ty_shallow(&ty)); + // return Either::Left(self.resolve_ty_shallow(&ty)); if ty.data(Interner).flags.intersects( chalk_ir::TypeFlags::HAS_TY_INFER | chalk_ir::TypeFlags::HAS_CT_INFER, @@ -365,51 +346,44 @@ impl<'a> InferenceTable<'a> { ); let in_env = InEnvironment::new(&self.trait_env.env, goal); let goal = in_env.to_nextsolver(self.interner); - let goal = ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; + let goal = + ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; - let (canonical_goal, _orig_values) = { + let (canonical_goal, orig_values) = { let mut orig_values = OriginalQueryValues::default(); - let result = self.infer_ctxt.canonicalize_query(goal, &mut orig_values); + let result = + self.infer_ctxt.canonicalize_query(goal, &mut orig_values); (result.canonical, orig_values) }; let canonical_goal = rustc_type_ir::Canonical { max_universe: canonical_goal.max_universe, variables: canonical_goal.variables, - value: crate::next_solver::Goal { param_env: canonical_goal.value.param_env, predicate: canonical_goal.value.value }, + value: crate::next_solver::Goal { + param_env: canonical_goal.value.param_env, + predicate: canonical_goal.value.value, + }, }; - let solution = next_trait_solve_canonical( - self.db, - self.trait_env.krate, - self.trait_env.block, - canonical_goal.clone(), + let solution = next_trait_solve_canonical_in_ctxt( + &self.infer_ctxt, + canonical_goal, ); if let NextTraitSolveResult::Certain(canonical_subst) = solution { - // This is not great :) But let's just assert this for now and come back to it later. - if canonical_subst.value.subst.len(Interner) != 1 { + let subst = self.instantiate_canonical(canonical_subst).subst; + if subst.len(Interner) != orig_values.var_values.len() { ty } else { - let normalized = canonical_subst.value.subst.as_slice(Interner) - [0] - .assert_ty_ref(Interner); - match normalized.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - if id == &proj_ty.associated_ty_id - && subst == &proj_ty.substitution - { - ty - } else { - normalized.clone() - } - } - TyKind::AssociatedType(new_id, new_subst) => { - if new_id == id && new_subst == subst { - ty + let target_ty = var.to_nextsolver(self.interner); + subst + .iter(Interner) + .zip(orig_values.var_values.iter()) + .find_map(|(new, orig)| { + if orig.ty() == Some(target_ty) { + Some(new.assert_ty_ref(Interner).clone()) } else { - normalized.clone() + None } - } - _ => normalized.clone(), - } + }) + .unwrap_or(ty) } } else { ty @@ -504,8 +478,8 @@ impl<'a> InferenceTable<'a> { pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { let var = self.new_type_var(); let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; - let obligation = alias_eq.cast(Interner); - self.register_obligation(obligation); + let obligation: Goal = alias_eq.cast(Interner); + self.register_obligation(obligation.to_nextsolver(self.interner)); var } @@ -575,7 +549,9 @@ impl<'a> InferenceTable<'a> { Substitution::from_iter( Interner, binders.iter().map(|kind| match &kind.kind { - chalk_ir::VariableKind::Ty(ty_variable_kind) => self.new_var(*ty_variable_kind, false).cast(Interner), + chalk_ir::VariableKind::Ty(ty_variable_kind) => { + self.new_var(*ty_variable_kind, false).cast(Interner) + } chalk_ir::VariableKind::Lifetime => self.new_lifetime_var().cast(Interner), chalk_ir::VariableKind::Const(ty) => self.new_const_var(ty.clone()).cast(Interner), }), @@ -589,8 +565,11 @@ impl<'a> InferenceTable<'a> { let subst = self.fresh_subst(canonical.binders.as_slice(Interner)); subst.apply(canonical.value, Interner) } - - pub(crate) fn instantiate_canonical_ns(&mut self, canonical: rustc_type_ir::Canonical, T>) -> T + + pub(crate) fn instantiate_canonical_ns( + &mut self, + canonical: rustc_type_ir::Canonical, T>, + ) -> T where T: rustc_type_ir::TypeFoldable>, { @@ -605,7 +584,7 @@ impl<'a> InferenceTable<'a> { where T: HasInterner + TypeFoldable, { - let mut var_stack = &mut vec![]; + let var_stack = &mut vec![]; t.fold_with( &mut resolve::Resolver { table: self, var_stack, fallback }, DebruijnIndex::INNERMOST, @@ -618,6 +597,7 @@ impl<'a> InferenceTable<'a> { { let t = self.resolve_with_fallback(t, &|_, _, d, _| d); let t = self.normalize_associated_types_in(t); + // let t = self.resolve_opaque_tys_in(t); // Resolve again, because maybe normalization inserted infer vars. self.resolve_with_fallback(t, &|_, _, d, _| d) } @@ -650,7 +630,7 @@ impl<'a> InferenceTable<'a> { } let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len(); for v in 0..float_vars { - let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer); + let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Float); let maybe_resolved = self.resolve_ty_shallow(&var); if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { // I don't think we can ever unify these vars with float vars, but keep this here for now @@ -665,7 +645,11 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - pub(crate) fn unify, U: Relate>>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify, U: Relate>>( + &mut self, + ty1: &T, + ty2: &T, + ) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, @@ -675,17 +659,17 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled - pub(crate) fn unify_deeply, U: Relate>>(&mut self, ty1: &T, ty2: &T) -> bool { + pub(crate) fn unify_deeply, U: Relate>>( + &mut self, + ty1: &T, + ty2: &T, + ) -> bool { let result = match self.try_unify(ty1, ty2) { Ok(r) => r, Err(_) => return false, }; - result.goals.iter().all(|goal| { - let goal = goal.to_nextsolver(self.interner); - match next_trait_solve_in_ctxt(&self.infer_ctxt, goal) { - Ok((_, Certainty::Yes)) => true, - _ => false, - } + result.goals.into_iter().all(|goal| { + matches!(next_trait_solve_in_ctxt(&self.infer_ctxt, goal), Ok((_, Certainty::Yes))) }) } @@ -695,20 +679,15 @@ impl<'a> InferenceTable<'a> { &mut self, t1: &T, t2: &T, - ) -> InferResult<()> { + ) -> InferResult<'a, ()> { let param_env = self.trait_env.env.to_nextsolver(self.interner); let lhs = t1.to_nextsolver(self.interner); let rhs = t2.to_nextsolver(self.interner); let variance = rustc_type_ir::Variance::Invariant; let span = crate::next_solver::Span::dummy(); match self.infer_ctxt.relate(param_env, lhs, variance, rhs, span) { - Ok(res) => { - let goals = res.into_iter().map(|g| ChalkToNextSolver::from_nextsolver(g, self.interner)).collect(); - Ok(InferOk { goals, value: () }) - } - Err(_) => { - Err(TypeError) - } + Ok(goals) => Ok(InferOk { goals, value: () }), + Err(_) => Err(TypeError), } } @@ -719,19 +698,75 @@ impl<'a> InferenceTable<'a> { if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) { return ty.clone(); } + self.infer_ctxt + .resolve_vars_if_possible(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } + + pub(crate) fn resolve_vars_with_obligations(&mut self, t: T) -> T + where + T: rustc_type_ir::TypeFoldable>, + { + use rustc_type_ir::TypeVisitableExt; + + if !t.has_non_region_infer() { + return t; + } + + let t = self.infer_ctxt.resolve_vars_if_possible(t); + + if !t.has_non_region_infer() { + return t; + } + + self.resolve_obligations_as_possible(); + self.infer_ctxt.resolve_vars_if_possible(t) + } + + pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty { + if let TyKind::Alias(..) = ty.kind(Interner) { + self.structurally_normalize_ty(ty) + } else { + self.resolve_vars_with_obligations(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } + } + + fn structurally_normalize_ty(&mut self, ty: &Ty) -> Ty { + self.structurally_normalize_term(ty.to_nextsolver(self.interner).into()) + .expect_ty() + .to_chalk(self.interner) + } + + fn structurally_normalize_term(&mut self, term: Term<'a>) -> Term<'a> { + if term.to_alias_term().is_none() { + return term; + } + + let new_infer = self.infer_ctxt.next_term_var_of_kind(term); + + self.register_obligation(Predicate::new( + self.interner, + Binder::dummy(PredicateKind::AliasRelate( + term, + new_infer, + AliasRelationDirection::Equate, + )), + )); self.resolve_obligations_as_possible(); - ChalkToNextSolver::from_nextsolver(self.infer_ctxt.resolve_vars_if_possible(ty.to_nextsolver(self.interner)), self.interner) + let res = self.infer_ctxt.resolve_vars_if_possible(new_infer); + if res == new_infer { term } else { res } } - pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { + pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'a> { let ctxt_snapshot = self.infer_ctxt.start_snapshot(); let diverging_tys = self.diverging_tys.clone(); let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot {ctxt_snapshot, pending_obligations, diverging_tys } + InferenceTableSnapshot { ctxt_snapshot, pending_obligations, diverging_tys } } #[tracing::instrument(skip_all)] - pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { + pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'a>) { self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); self.diverging_tys = snapshot.diverging_tys; self.pending_obligations = snapshot.pending_obligations; @@ -745,7 +780,10 @@ impl<'a> InferenceTable<'a> { result } - pub(crate) fn commit_if_ok(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> Result) -> Result { + pub(crate) fn commit_if_ok( + &mut self, + f: impl FnOnce(&mut InferenceTable<'_>) -> Result, + ) -> Result { let snapshot = self.snapshot(); let result = f(self); match result { @@ -765,59 +803,31 @@ impl<'a> InferenceTable<'a> { let in_env = InEnvironment::new(&self.trait_env.env, goal); let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner)); - next_trait_solve_canonical(self.db, self.trait_env.krate, self.trait_env.block, canonicalized) + next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } - + #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result { let goal = InEnvironment::new(&self.trait_env.env, goal); - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { - return Ok(Certainty::Yes); - }; - let goal = goal.to_nextsolver(self.interner); let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); result.map(|m| m.1) } - pub(crate) fn register_obligation(&mut self, goal: Goal) { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - self.register_obligation_in_env(in_env) - } - - // If this goal is an `AliasEq` for an opaque type, just unify instead of trying to solve (since the next-solver is lazy) - fn unify_opaque_instead_of_solve(&mut self, goal: InEnvironment) -> Option> { - match goal.goal.data(Interner) { - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), - )) => { - if ty.inference_var(Interner).is_some() { - match alias { - chalk_ir::AliasTy::Opaque(opaque) => { - if self.unify( - &chalk_ir::TyKind::OpaqueType( - opaque.opaque_ty_id, - opaque.substitution.clone(), - ) - .intern(Interner), - ty, - ) { - return None; - } - } - _ => {} - } - } - } - _ => {} - } - Some(goal) + pub(crate) fn register_obligation(&mut self, predicate: Predicate<'a>) { + let goal = next_solver::Goal { + param_env: self.trait_env.env.to_nextsolver(self.interner), + predicate, + }; + self.register_obligation_in_env(goal) } #[tracing::instrument(level = "debug", skip(self))] - fn register_obligation_in_env(&mut self, goal: InEnvironment) { - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { return }; - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + fn register_obligation_in_env( + &mut self, + goal: next_solver::Goal<'a, next_solver::Predicate<'a>>, + ) { + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); tracing::debug!(?result); match result { Ok((_, Certainty::Yes)) => {} @@ -828,7 +838,7 @@ impl<'a> InferenceTable<'a> { } } - pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk) { + pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk<'a, T>) { infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); } @@ -841,12 +851,7 @@ impl<'a> InferenceTable<'a> { for goal in obligations.drain(..) { tracing::debug!(obligation = ?goal); - let Some(goal) = self.unify_opaque_instead_of_solve(goal) else { - changed = true; - continue; - }; - - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal.to_nextsolver(self.interner)); + let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); let (has_changed, certainty) = match result { Ok(result) => result, Err(_) => { @@ -934,40 +939,6 @@ impl<'a> InferenceTable<'a> { .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST) } - #[tracing::instrument(level = "debug", skip(self))] - fn try_resolve_obligation( - &mut self, - canonicalized: &Canonicalized>, - ) -> NextTraitSolveResult { - let solution = next_trait_solve( - self.db, - self.trait_env.krate, - self.trait_env.block, - canonicalized.value.clone(), - ); - - tracing::debug!(?solution, ?canonicalized); - match &solution { - NextTraitSolveResult::Certain(v) => { - canonicalized.apply_solution( - self, - Canonical { - binders: v.binders.clone(), - // FIXME handle constraints - value: v.value.subst.clone(), - }, - ); - } - // ...so, should think about how to get some actually get some guidance here - NextTraitSolveResult::Uncertain(v) => { - canonicalized.apply_solution(self, v.clone()); - } - NextTraitSolveResult::NoSolution => {} - } - - solution - } - pub(crate) fn callable_sig( &mut self, ty: &Ty, @@ -1027,7 +998,7 @@ impl<'a> InferenceTable<'a> { let goal: Goal = trait_ref.clone().cast(Interner); if !self.try_obligation(goal.clone()).no_solution() { - self.register_obligation(goal); + self.register_obligation(goal.to_nextsolver(self.interner)); let return_ty = self.normalize_projection_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; @@ -1067,7 +1038,7 @@ impl<'a> InferenceTable<'a> { match ty.kind(Interner) { TyKind::Error => self.new_type_var(), TyKind::InferenceVar(..) => { - let ty_resolved = self.resolve_ty_shallow(&ty); + let ty_resolved = self.structurally_resolve_type(&ty); if ty_resolved.is_unknown() { self.new_type_var() } else { ty } } _ => ty, @@ -1165,7 +1136,9 @@ impl fmt::Debug for InferenceTable<'_> { mod resolve { use super::InferenceTable; use crate::{ - next_solver::mapping::ChalkToNextSolver, ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind + ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, + InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind, + next_solver::mapping::NextSolverToChalk, }; use chalk_ir::{ cast::Cast, @@ -1220,7 +1193,7 @@ mod resolve { .clone(); } if let Ok(known_ty) = self.table.infer_ctxt.probe_ty_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1234,7 +1207,13 @@ mod resolve { } } TyVariableKind::Integer => { - let vid = self.table.infer_ctxt.inner.borrow_mut().int_unification_table().find(IntVid::from(var.index())); + let vid = self + .table + .infer_ctxt + .inner + .borrow_mut() + .int_unification_table() + .find(IntVid::from(var.index())); let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type @@ -1244,7 +1223,7 @@ mod resolve { .clone(); } if let Some(known_ty) = self.table.infer_ctxt.resolve_int_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1258,7 +1237,13 @@ mod resolve { } } TyVariableKind::Float => { - let vid = self.table.infer_ctxt.inner.borrow_mut().float_unification_table().find(FloatVid::from(var.index())); + let vid = self + .table + .infer_ctxt + .inner + .borrow_mut() + .float_unification_table() + .find(FloatVid::from(var.index())); let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type @@ -1268,7 +1253,7 @@ mod resolve { .clone(); } if let Some(known_ty) = self.table.infer_ctxt.resolve_float_var(vid) { - let known_ty: Ty = ChalkToNextSolver::from_nextsolver(known_ty, self.table.interner); + let known_ty: Ty = known_ty.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Ty(kind))); let result = known_ty.fold_with(self, outer_binder); @@ -1290,7 +1275,10 @@ mod resolve { var: InferenceVar, outer_binder: DebruijnIndex, ) -> Const { - let vid = self.table.infer_ctxt.root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); + let vid = self + .table + .infer_ctxt + .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); let var = InferenceVar::from(vid.as_u32()); let default = ConstData { ty: ty.clone(), @@ -1305,7 +1293,7 @@ mod resolve { .clone(); } if let Ok(known_const) = self.table.infer_ctxt.probe_const_var(vid) { - let known_const: Const = ChalkToNextSolver::from_nextsolver(known_const, self.table.interner); + let known_const: Const = known_const.to_chalk(self.table.interner); // known_ty may contain other variables that are known by now self.var_stack.push((var, VarKind::Const)); let result = known_const.fold_with(self, outer_binder); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 323ea951a9141..659bc5ade3c79 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -101,7 +101,10 @@ use crate::{ display::{DisplayTarget, HirDisplay}, generics::Generics, infer::unify::InferenceTable, - next_solver::{DbInterner, mapping::convert_ty_for_result}, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, convert_ty_for_result}, + }, }; pub use autoderef::autoderef; @@ -957,8 +960,10 @@ pub fn callable_sig_from_fn_trait( ) .build(); - if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { - table.register_obligation(trait_ref.clone().cast(Interner)); + let goal: Goal = trait_ref.clone().cast(Interner); + let pred = goal.to_nextsolver(table.interner); + if !table.try_obligation(goal).no_solution() { + table.register_obligation(pred); let return_ty = table.normalize_projection_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index ee223059d1e56..fa80567b1ecc0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -22,7 +22,25 @@ use stdx::never; use triomphe::Arc; use crate::{ - autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, lang_items::is_box, next_solver::{mapping::ChalkToNextSolver, SolverDefId}, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, traits::{next_trait_solve_canonical}, utils::all_super_traits, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause + AdtId, AliasTy, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, + GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, + TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, + VariableKind, WhereClause, + autoderef::{self, AutoderefKind}, + db::HirDatabase, + from_chalk_trait_id, from_foreign_def_id, + infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, + lang_items::is_box, + next_solver::{ + self, SolverDefId, + fulfill::FulfillmentCtxt, + infer::DefineOpaqueTypes, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, + primitive::{FloatTy, IntTy, UintTy}, + to_chalk_trait_id, + traits::next_trait_solve_canonical_in_ctxt, + utils::all_super_traits, }; /// This is used as a key for indexing impls. @@ -89,6 +107,7 @@ impl TyFingerprint { } TyKind::AssociatedType(_, _) | TyKind::OpaqueType(_, _) + | TyKind::Alias(AliasTy::Opaque(_)) | TyKind::FnDef(_, _) | TyKind::Closure(_, _) | TyKind::Coroutine(..) @@ -106,7 +125,7 @@ impl TyFingerprint { } /// Creates a TyFingerprint for looking up a trait impl. - pub fn for_trait_impl_ns<'db>(ty: &crate::next_solver::Ty<'db>) -> Option { + pub fn for_trait_impl_ns<'db>(ty: &next_solver::Ty<'db>) -> Option { use rustc_type_ir::TyKind; let fp = match (*ty).kind() { TyKind::Str => TyFingerprint::Str, @@ -523,7 +542,7 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option( db: &'db dyn HirDatabase, - ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, env: Arc, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -605,7 +624,7 @@ pub struct ReceiverAdjustments { impl ReceiverAdjustments { pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec) { - let mut ty = table.resolve_ty_shallow(&ty); + let mut ty = table.structurally_resolve_type(&ty); let mut adjust = Vec::new(); for _ in 0..self.autoderefs { match autoderef::autoderef_step(table, ty.clone(), true, false) { @@ -686,7 +705,7 @@ impl ReceiverAdjustments { // lifetime problems, because we need to borrow temp `CrateImplDefs`. // FIXME add a context type here? pub(crate) fn iterate_method_candidates<'db, T>( - ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, @@ -887,7 +906,7 @@ fn find_matching_impl( if table.try_obligation(goal.clone()).no_solution() { return None; } - table.register_obligation(goal); + table.register_obligation(goal.to_nextsolver(table.interner)); } Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) }) @@ -1035,7 +1054,7 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { } pub fn iterate_path_candidates<'db>( - ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, @@ -1057,7 +1076,7 @@ pub fn iterate_path_candidates<'db>( } pub fn iterate_method_candidates_dyn<'db>( - ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, @@ -1096,7 +1115,7 @@ pub fn iterate_method_candidates_dyn<'db>( // types*. let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical_ns(ty.clone()); + let ty = table.instantiate_canonical_ns(*ty); let deref_chain = autoderef_method_receiver(&mut table, ty); deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| { @@ -1129,18 +1148,13 @@ pub fn iterate_method_candidates_dyn<'db>( #[tracing::instrument(skip_all, fields(name = ?name))] fn iterate_method_candidates_with_autoref<'db>( table: &mut InferenceTable<'db>, - receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + receiver_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, first_adjustment: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { - if matches!(receiver_ty.value.kind(), rustc_type_ir::TyKind::Bound(..)) { - // don't try to resolve methods on unknown types - return ControlFlow::Continue(()); - } - let interner = table.interner; let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| { @@ -1166,12 +1180,17 @@ fn iterate_method_candidates_with_autoref<'db>( maybe_reborrowed.autoderefs += 1; } - iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?; + iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?; - let refed = crate::next_solver::Canonical { + let refed = next_solver::Canonical { max_universe: receiver_ty.max_universe, variables: receiver_ty.variables, - value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Not), + value: next_solver::Ty::new_ref( + interner, + next_solver::Region::error(interner), + receiver_ty.value, + rustc_ast_ir::Mutability::Not, + ), }; iterate_method_candidates_by_receiver( @@ -1179,10 +1198,15 @@ fn iterate_method_candidates_with_autoref<'db>( first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)), )?; - let ref_muted = crate::next_solver::Canonical { + let ref_muted = next_solver::Canonical { max_universe: receiver_ty.max_universe, variables: receiver_ty.variables, - value: crate::next_solver::Ty::new_ref(interner, crate::next_solver::Region::error(interner), receiver_ty.value, rustc_ast_ir::Mutability::Mut), + value: next_solver::Ty::new_ref( + interner, + next_solver::Region::error(interner), + receiver_ty.value, + rustc_ast_ir::Mutability::Mut, + ), }; iterate_method_candidates_by_receiver( @@ -1190,10 +1214,12 @@ fn iterate_method_candidates_with_autoref<'db>( first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)), )?; - if let rustc_type_ir::TyKind::RawPtr(ty, rustc_ast_ir::Mutability::Mut) = receiver_ty.value.kind() { + if let rustc_type_ir::TyKind::RawPtr(ty, rustc_ast_ir::Mutability::Mut) = + receiver_ty.value.kind() + { let const_ptr_ty = rustc_type_ir::Canonical { max_universe: rustc_type_ir::UniverseIndex::ZERO, - value: crate::next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not), + value: next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not), variables: receiver_ty.variables, }; iterate_method_candidates_by_receiver( @@ -1247,7 +1273,7 @@ where #[tracing::instrument(skip_all, fields(name = ?name))] fn iterate_method_candidates_by_receiver<'db>( table: &mut InferenceTable<'db>, - receiver_ty: crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + receiver_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, receiver_adjustments: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -1255,7 +1281,7 @@ fn iterate_method_candidates_by_receiver<'db>( callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { let receiver_ty = table.instantiate_canonical_ns(receiver_ty); - let receiver_ty: crate::Ty = ChalkToNextSolver::from_nextsolver(receiver_ty, table.interner); + let receiver_ty: crate::Ty = receiver_ty.to_chalk(table.interner); // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that, including raw derefs. @@ -1270,6 +1296,7 @@ fn iterate_method_candidates_by_receiver<'db>( Some(&receiver_ty), Some(receiver_adjustments.clone()), visible_from_module, + LookupMode::MethodCall, &mut |adjustments, item, is_visible| { callback.on_inherent_method(adjustments, item, is_visible) }, @@ -1293,6 +1320,7 @@ fn iterate_method_candidates_by_receiver<'db>( name, Some(&receiver_ty), Some(receiver_adjustments.clone()), + LookupMode::MethodCall, &mut |adjustments, item, is_visible| { callback.on_trait_method(adjustments, item, is_visible) }, @@ -1304,7 +1332,7 @@ fn iterate_method_candidates_by_receiver<'db>( #[tracing::instrument(skip_all, fields(name = ?name))] fn iterate_method_candidates_for_self_ty<'db>( - self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + self_ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, env: Arc, traits_in_scope: &FxHashSet, @@ -1313,7 +1341,7 @@ fn iterate_method_candidates_for_self_ty<'db>( callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { let mut table = InferenceTable::new(db, env); - let self_ty = ChalkToNextSolver::from_nextsolver(table.instantiate_canonical_ns(self_ty.clone()), table.interner); + let self_ty = table.instantiate_canonical_ns(*self_ty).to_chalk(table.interner); iterate_inherent_methods( &self_ty, &mut table, @@ -1321,6 +1349,7 @@ fn iterate_method_candidates_for_self_ty<'db>( None, None, visible_from_module, + LookupMode::Path, &mut |adjustments, item, is_visible| { callback.on_inherent_method(adjustments, item, is_visible) }, @@ -1332,6 +1361,7 @@ fn iterate_method_candidates_for_self_ty<'db>( name, None, None, + LookupMode::Path, &mut |adjustments, item, is_visible| { callback.on_trait_method(adjustments, item, is_visible) }, @@ -1346,12 +1376,13 @@ fn iterate_trait_method_candidates( name: Option<&Name>, receiver_ty: Option<&Ty>, receiver_adjustments: Option, + mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; - let canonical_self_ty = ChalkToNextSolver::from_nextsolver(table.canonicalize(self_ty.clone().to_nextsolver(table.interner)), table.interner); - let TraitEnvironment { krate, block, .. } = *table.trait_env; + let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner)); + let TraitEnvironment { krate, .. } = *table.trait_env; 'traits: for &t in traits_in_scope { let data = db.trait_signature(t); @@ -1391,15 +1422,22 @@ fn iterate_trait_method_candidates( for &(_, item) in t.trait_items(db).items.iter() { // Don't pass a `visible_from_module` down to `is_valid_candidate`, // since only inherent methods should be included into visibility checking. - let visible = - match is_valid_trait_method_candidate(table, t, name, receiver_ty, item, self_ty) { - IsValidCandidate::Yes => true, - IsValidCandidate::NotVisible => false, - IsValidCandidate::No => continue, - }; + let visible = match is_valid_trait_method_candidate( + table, + t, + name, + receiver_ty, + item, + self_ty, + mode, + ) { + IsValidCandidate::Yes => true, + IsValidCandidate::NotVisible => false, + IsValidCandidate::No => continue, + }; if !known_implemented { - let goal = generic_implements_goal(db, &table.trait_env, t, &canonical_self_ty); - if db.trait_solve(krate, block, goal.cast(Interner)).no_solution() { + let goal = generic_implements_goal_ns(table, t, canonical_self_ty); + if next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() { continue 'traits; } } @@ -1418,6 +1456,7 @@ fn iterate_inherent_methods( receiver_ty: Option<&Ty>, receiver_adjustments: Option, visible_from_module: VisibleFromModule, + mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; @@ -1441,6 +1480,7 @@ fn iterate_inherent_methods( receiver_adjustments.clone(), callback, traits, + mode, )?; } TyKind::Dyn(_) => { @@ -1454,6 +1494,7 @@ fn iterate_inherent_methods( receiver_adjustments.clone(), callback, traits.into_iter(), + mode, )?; } } @@ -1512,6 +1553,7 @@ fn iterate_inherent_methods( receiver_adjustments: Option, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, traits: impl Iterator, + mode: LookupMode, ) -> ControlFlow<()> { let db = table.db; for t in traits { @@ -1525,6 +1567,7 @@ fn iterate_inherent_methods( receiver_ty, item, self_ty, + mode, ) { IsValidCandidate::Yes => true, IsValidCandidate::NotVisible => false, @@ -1571,22 +1614,17 @@ fn iterate_inherent_methods( } /// Returns the receiver type for the index trait call. -pub(crate) fn resolve_indexing_op( - db: &dyn HirDatabase, - env: Arc, - ty: Canonical, +pub(crate) fn resolve_indexing_op<'db>( + table: &mut InferenceTable<'db>, + ty: next_solver::Canonical<'db, next_solver::Ty<'db>>, index_trait: TraitId, ) -> Option { - let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical(ty); - let interner = table.interner; - let deref_chain = autoderef_method_receiver(&mut table, ty.to_nextsolver(interner)); + let ty = table.instantiate_canonical_ns(ty); + let deref_chain = autoderef_method_receiver(table, ty); for (ty, adj) in deref_chain { //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty); - let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ChalkToNextSolver::from_nextsolver(ty, interner)); - let goal: chalk_ir::Canonical>> = goal.cast(Interner); - let goal = goal.to_nextsolver(interner); - if !next_trait_solve_canonical(db, table.trait_env.krate, table.trait_env.block, goal).no_solution() { + let goal = generic_implements_goal_ns(table, index_trait, ty); + if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() { return Some(adj); } } @@ -1666,6 +1704,7 @@ fn is_valid_trait_method_candidate( receiver_ty: Option<&Ty>, item: AssocItemId, self_ty: &Ty, + mode: LookupMode, ) -> IsValidCandidate { let db = table.db; match item { @@ -1693,6 +1732,35 @@ fn is_valid_trait_method_candidate( let expected_receiver = sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst); + // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext` + let variance = match mode { + LookupMode::MethodCall => rustc_type_ir::Variance::Covariant, + LookupMode::Path => rustc_type_ir::Variance::Invariant, + }; + let res = table + .infer_ctxt + .at( + &next_solver::infer::traits::ObligationCause::dummy(), + table.trait_env.env.to_nextsolver(table.interner), + ) + .relate( + DefineOpaqueTypes::No, + expected_receiver.to_nextsolver(table.interner), + variance, + receiver_ty.to_nextsolver(table.interner), + ); + let Ok(infer_ok) = res else { + return IsValidCandidate::No; + }; + + if !infer_ok.obligations.is_empty() { + let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt); + for pred in infer_ok.into_obligations() { + ctxt.register_predicate_obligation(&table.infer_ctxt, pred); + } + check_that!(ctxt.select_all_or_error(&table.infer_ctxt).is_empty()); + } + check_that!(table.unify(receiver_ty, &expected_receiver)); } @@ -1839,53 +1907,36 @@ fn generic_implements_goal( Canonical { binders, value } } -/* /// This creates Substs for a trait with the given Self type and type variables /// for all other parameters, to query the trait solver with it. #[tracing::instrument(skip_all)] fn generic_implements_goal_ns<'db>( - db: &'db dyn HirDatabase, - interner: DbInterner<'db>, - env: &TraitEnvironment, + table: &mut InferenceTable<'db>, trait_: TraitId, - self_ty: &crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, -) -> crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> { - let variables = self_ty.variables; - let trait_ref = TyBuilder::trait_ref(db, trait_) - .push(ChalkToNextSolver::from_nextsolver(self_ty.value, interner)) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, variables.len()) - .build(); - - let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); - let args = infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_)); - - rustc_type_ir::TraitRef::new(interner, SolverDefId::TraitId(trait_)).with_self_ty(interner, self_ty.value); - - - let kinds = - binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| { - let vk = match it.data(Interner) { - GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General), - GenericArgData::Lifetime(_) => VariableKind::Lifetime, - GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()), - }; - WithKind::new(vk, UniverseIndex::ROOT) - })); - let binders = CanonicalVarKinds::from_iter(Interner, kinds); + self_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, +) -> next_solver::Canonical<'db, next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> { + let args = table.infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_)); + let self_ty = table.instantiate_canonical_ns(self_ty); + let trait_ref = + rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args) + .with_replaced_self_ty(table.infer_ctxt.interner, self_ty); + let goal = next_solver::Goal::new( + table.infer_ctxt.interner, + table.trait_env.env.to_nextsolver(table.infer_ctxt.interner), + trait_ref, + ); - let obligation = trait_ref.cast(Interner); - let value = InEnvironment::new(&env.env, obligation); - crate::next_solver::Canonical { max_universe, value, variables } + table.canonicalize(goal) } -*/ fn autoderef_method_receiver<'db>( table: &mut InferenceTable<'db>, - ty: crate::next_solver::Ty<'db>, -) -> Vec<(crate::next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> { + ty: next_solver::Ty<'db>, +) -> Vec<(next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> { let interner = table.interner; let mut deref_chain = Vec::new(); - let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ChalkToNextSolver::from_nextsolver(ty, interner), false, true); + let mut autoderef = + autoderef::Autoderef::new_no_tracking(table, ty.to_chalk(interner), false, true); while let Some((ty, derefs)) = autoderef.next() { deref_chain.push(( autoderef.table.canonicalize(ty.to_nextsolver(interner)), @@ -1894,11 +1945,11 @@ fn autoderef_method_receiver<'db>( } // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) if let Some((rustc_type_ir::Array(parameters, _), variables, max_universe, adj)) = - deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables.clone(), d.0.max_universe, d.1.clone())) + deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables, d.0.max_universe, d.1.clone())) { - let unsized_ty = crate::next_solver::Ty::new_slice(interner, parameters); + let unsized_ty = next_solver::Ty::new_slice(interner, parameters); deref_chain.push(( - crate::next_solver::Canonical { max_universe, value: unsized_ty, variables, }, + next_solver::Canonical { max_universe, value: unsized_ty, variables }, ReceiverAdjustments { unsize_array: true, ..adj.clone() }, )); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 8c48a16537a2e..6465099dffd7f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -34,8 +34,7 @@ pub use eval::{ }; pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_body_query}; pub use monomorphization::{ - monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query, - monomorphized_mir_body_query, + monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query, }; use rustc_hash::FxHashMap; use smallvec::{SmallVec, smallvec}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index b0b922316914b..555b87850924c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -38,7 +38,6 @@ struct Filler<'a> { trait_env: Arc, subst: &'a Substitution, generics: Option, - owner: DefWithBodyId, } impl FallibleTypeFolder for Filler<'_> { type Error = MirLowerError; @@ -66,7 +65,11 @@ impl FallibleTypeFolder for Filler<'_> { })) .intern(Interner)) } - TyKind::OpaqueType(id, subst) => { + TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { + opaque_ty_id: id, + substitution: subst, + })) + | TyKind::OpaqueType(id, subst) => { let impl_trait_id = self.db.lookup_intern_impl_trait_id((*id).into()); let subst = subst.clone().try_fold_with(self.as_dyn(), outer_binder)?; match impl_trait_id { @@ -74,7 +77,6 @@ impl FallibleTypeFolder for Filler<'_> { let infer = self.db.infer(func.into()); let filler = &mut Filler { db: self.db, - owner: self.owner, trait_env: self.trait_env.clone(), subst: &subst, generics: Some(generics(self.db, func.into())), @@ -306,7 +308,7 @@ pub fn monomorphized_mir_body_query( trait_env: Arc, ) -> Result, MirLowerError> { let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); - let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; + let filler = &mut Filler { db, subst: &subst, trait_env, generics }; let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; @@ -330,23 +332,9 @@ pub fn monomorphized_mir_body_for_closure_query( ) -> Result, MirLowerError> { let InternedClosure(owner, _) = db.lookup_intern_closure(closure); let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); - let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; + let filler = &mut Filler { db, subst: &subst, trait_env, generics }; let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(Arc::new(body)) } - -// FIXME: remove this function. Monomorphization is a time consuming job and should always be a query. -pub fn monomorphize_mir_body_bad( - db: &dyn HirDatabase, - mut body: MirBody, - subst: Substitution, - trait_env: Arc, -) -> Result { - let owner = body.owner; - let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); - let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; - filler.fill_body(&mut body)?; - Ok(body) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 21762aa66a858..0225deebe4f31 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -5,11 +5,10 @@ pub mod abi; mod consts; mod def_id; pub mod fold; -mod fulfill; +pub mod fulfill; mod generic_arg; pub mod generics; pub mod infer; -//mod infer_new; pub mod interner; mod ir_print; pub mod mapping; @@ -24,7 +23,6 @@ pub mod util; pub use consts::*; pub use def_id::*; pub use generic_arg::*; -//pub use infer_new::*; pub use interner::*; pub use opaques::*; pub use predicate::*; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index 0820006e5dfb0..5d11525cd199f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -1,14 +1,28 @@ +//! This module contains code to canonicalize values into a `Canonical<'db, T>`. +//! +//! For an overview of what canonicalization is and how it fits into +//! rustc, check out the [chapter in the rustc dev guide][c]. +//! +//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use rustc_hash::FxHashMap; use rustc_index::Idx; -use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _}; use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar}; -use rustc_type_ir::{BoundVar, CanonicalQueryInput, CanonicalTyVarKind, DebruijnIndex, Flags, InferConst, RegionKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex}; +use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _}; +use rustc_type_ir::{ + BoundVar, CanonicalQueryInput, CanonicalTyVarKind, DebruijnIndex, Flags, InferConst, + RegionKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + UniverseIndex, +}; use smallvec::SmallVec; use tracing::debug; use crate::next_solver::infer::InferCtxt; -use crate::next_solver::{Binder, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty, TyKind}; +use crate::next_solver::{ + Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind, + CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty, + TyKind, +}; /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores @@ -65,7 +79,7 @@ impl<'db> InferCtxt<'db> { // `param_env` because they are treated differently by trait selection. let canonical_param_env = Canonicalizer::canonicalize( param_env, - None, + self, self.interner, &CanonicalizeFreeRegionsOtherThanStatic, query_state, @@ -74,7 +88,7 @@ impl<'db> InferCtxt<'db> { let canonical = Canonicalizer::canonicalize_with_base( canonical_param_env, value, - Some(self), + self, self.interner, &CanonicalizeAllFreeRegions, query_state, @@ -115,7 +129,7 @@ impl<'db> InferCtxt<'db> { let mut query_state = OriginalQueryValues::default(); Canonicalizer::canonicalize( value, - Some(self), + self, self.interner, &CanonicalizeQueryResponse, &mut query_state, @@ -129,7 +143,7 @@ impl<'db> InferCtxt<'db> { let mut query_state = OriginalQueryValues::default(); Canonicalizer::canonicalize( value, - Some(self), + self, self.interner, &CanonicalizeUserTypeAnnotation, &mut query_state, @@ -165,7 +179,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { canonicalizer: &mut Canonicalizer<'_, 'db>, mut r: Region<'db>, ) -> Region<'db> { - let infcx = canonicalizer.infcx.unwrap(); + let infcx = canonicalizer.infcx; if let RegionKind::ReVar(vid) = r.kind() { r = infcx @@ -180,12 +194,14 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { }; match r.kind() { - RegionKind::ReLateParam(_) | RegionKind::ReErased | RegionKind::ReStatic | RegionKind::ReEarlyParam(..) | RegionKind::ReError(..) => r, + RegionKind::ReLateParam(_) + | RegionKind::ReErased + | RegionKind::ReStatic + | RegionKind::ReEarlyParam(..) + | RegionKind::ReError(..) => r, - RegionKind::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( - CanonicalVarKind::PlaceholderRegion(placeholder), - r, - ), + RegionKind::RePlaceholder(placeholder) => canonicalizer + .canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r), RegionKind::ReVar(vid) => { let universe = infcx @@ -194,10 +210,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { .unwrap_region_constraints() .probe_value(vid) .unwrap_err(); - canonicalizer.canonical_var_for_region( - CanonicalVarKind::Region(universe), - r, - ) + canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r) } _ => { @@ -240,7 +253,7 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { RegionKind::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), RegionKind::RePlaceholder(..) | RegionKind::ReBound(..) => { // We only expect region names that the user can type. - panic!("unexpected region in query response: `{:?}`", r) + panic!("unexpected region in query response: `{r:?}`") } } } @@ -296,7 +309,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic { struct Canonicalizer<'cx, 'db> { /// Set to `None` to disable the resolution of inference variables. - infcx: Option<&'cx InferCtxt<'db>>, + infcx: &'cx InferCtxt<'db>, tcx: DbInterner<'db>, variables: SmallVec<[CanonicalVarKind<'db>; 8]>, query_state: &'cx mut OriginalQueryValues<'db>, @@ -350,14 +363,14 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { // We need to canonicalize the *root* of our ty var. // This is so that our canonical response correctly reflects // any equated inference vars correctly! - let root_vid = self.infcx.unwrap().root_var(vid); + let root_vid = self.infcx.root_var(vid); if root_vid != vid { t = Ty::new_var(self.tcx, root_vid); vid = root_vid; } debug!("canonical: type var found with vid {:?}", vid); - match self.infcx.unwrap().probe_ty_var(vid) { + match self.infcx.probe_ty_var(vid) { // `t` could be a float / int variable; canonicalize that instead. Ok(t) => { debug!("(resolved to {:?})", t); @@ -380,29 +393,25 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { } TyKind::Infer(IntVar(vid)) => { - let nt = self.infcx.unwrap().opportunistic_resolve_int_var(vid); + let nt = self.infcx.opportunistic_resolve_int_var(vid); if nt != t { - return self.fold_ty(nt); + self.fold_ty(nt) } else { - self.canonicalize_ty_var( - CanonicalVarKind::Ty(CanonicalTyVarKind::Int), - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t) } } TyKind::Infer(FloatVar(vid)) => { - let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid); + let nt = self.infcx.opportunistic_resolve_float_var(vid); if nt != t { - return self.fold_ty(nt); + self.fold_ty(nt) } else { - self.canonicalize_ty_var( - CanonicalVarKind::Ty(CanonicalTyVarKind::Float), - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t) } } - TyKind::Infer(InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_)) => { + TyKind::Infer( + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_), + ) => { panic!("encountered a fresh type during canonicalization") } @@ -410,10 +419,7 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { if !self.canonicalize_mode.preserve_universes() { placeholder.universe = UniverseIndex::ROOT; } - self.canonicalize_ty_var( - CanonicalVarKind::PlaceholderTy(placeholder), - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t) } TyKind::Bound(debruijn, _) => { @@ -465,14 +471,14 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { // We need to canonicalize the *root* of our const var. // This is so that our canonical response correctly reflects // any equated inference vars correctly! - let root_vid = self.infcx.unwrap().root_const_var(vid); + let root_vid = self.infcx.root_const_var(vid); if root_vid != vid { ct = Const::new_var(self.tcx, root_vid); vid = root_vid; } debug!("canonical: const var found with vid {:?}", vid); - match self.infcx.unwrap().probe_const_var(vid) { + match self.infcx.probe_const_var(vid) { Ok(c) => { debug!("(resolved to {:?})", c); return self.fold_const(c); @@ -485,10 +491,7 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { // FIXME: perf problem described in #55921. ui = UniverseIndex::ROOT; } - return self.canonicalize_const_var( - CanonicalVarKind::Const(ui), - ct, - ); + return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct); } } } @@ -503,10 +506,8 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { } } ConstKind::Placeholder(placeholder) => { - return self.canonicalize_const_var( - CanonicalVarKind::PlaceholderConst(placeholder), - ct, - ); + return self + .canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct); } _ => {} } @@ -524,7 +525,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { /// `canonicalize_query` and `canonicalize_response`. fn canonicalize( value: V, - infcx: Option<&InferCtxt<'db>>, + infcx: &InferCtxt<'db>, tcx: DbInterner<'db>, canonicalize_region_mode: &dyn CanonicalizeMode, query_state: &mut OriginalQueryValues<'db>, @@ -551,7 +552,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { fn canonicalize_with_base( base: Canonical<'db, U>, value: V, - infcx: Option<&InferCtxt<'db>>, + infcx: &InferCtxt<'db>, tcx: DbInterner<'db>, canonicalize_region_mode: &dyn CanonicalizeMode, query_state: &mut OriginalQueryValues<'db>, @@ -596,7 +597,8 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { // anymore. debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); - let canonical_variables = CanonicalVars::new_from_iter(tcx, canonicalizer.universe_canonicalized_variables()); + let canonical_variables = + CanonicalVars::new_from_iter(tcx, canonicalizer.universe_canonicalized_variables()); let max_universe = canonical_variables .iter() @@ -690,15 +692,11 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { self.variables .iter() .map(|v| match *v { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { - return *v; - } + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => *v, CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) } - CanonicalVarKind::Region(u) => { - CanonicalVarKind::Region(reverse_universe_map[&u]) - } + CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]), CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(Placeholder { @@ -735,14 +733,8 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { /// /// (This works because unification never fails -- and hence trait /// selection is never affected -- due to a universe mismatch.) - fn canonical_var_for_region_in_root_universe( - &mut self, - r: Region<'db>, - ) -> Region<'db> { - self.canonical_var_for_region( - CanonicalVarKind::Region(UniverseIndex::ROOT), - r, - ) + fn canonical_var_for_region_in_root_universe(&mut self, r: Region<'db>) -> Region<'db> { + self.canonical_var_for_region(CanonicalVarKind::Region(UniverseIndex::ROOT), r) } /// Creates a canonical variable (with the given `info`) @@ -762,9 +754,13 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> { - debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); + debug_assert_eq!(ty_var, self.infcx.shallow_resolve(ty_var)); let var = self.canonical_var(info, ty_var.into()); - Ty::new_bound(self.tcx, self.binder_index, BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var }) + Ty::new_bound( + self.tcx, + self.binder_index, + BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var }, + ) } /// Given a type variable `const_var` of the given kind, first check @@ -776,10 +772,8 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { info: CanonicalVarKind<'db>, const_var: Const<'db>, ) -> Const<'db> { - debug_assert!( - !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var)) - ); + debug_assert_eq!(const_var, self.infcx.shallow_resolve_const(const_var)); let var = self.canonical_var(info, const_var.into()); - Const::new_bound(self.tcx, self.binder_index, var) + Const::new_bound(self.tcx, self.binder_index, BoundConst { var }) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 894c91e0f49db..2630f2a8cc4e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -503,7 +503,10 @@ impl<'db> InferCtxt<'db> { } pub fn next_ty_vid(&self) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), TypeVariableOrigin { param_def_id: None }) + self.inner + .borrow_mut() + .type_variables() + .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }) } pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> { @@ -526,11 +529,13 @@ impl<'db> InferCtxt<'db> { } pub fn next_const_vid(&self) -> ConstVid { - self - .inner + self.inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin: ConstVariableOrigin { param_def_id: None }, universe: self.universe() }) + .new_key(ConstVariableValue::Unknown { + origin: ConstVariableOrigin { param_def_id: None }, + universe: self.universe(), + }) .vid } @@ -566,9 +571,7 @@ impl<'db> InferCtxt<'db> { } pub fn next_float_var(&self) -> Ty<'db> { - let next_float_var_id = - self.inner.borrow_mut().float_unification_table().new_key(FloatVarValue::Unknown); - Ty::new_float_var(self.interner, next_float_var_id) + Ty::new_float_var(self.interner, self.next_float_vid()) } pub fn next_float_vid(&self) -> FloatVid { @@ -815,9 +818,7 @@ impl<'db> InferCtxt<'db> { match value { IntVarValue::IntType(ty) => Some(Ty::new_int(self.interner, ty)), IntVarValue::UintType(ty) => Some(Ty::new_uint(self.interner, ty)), - IntVarValue::Unknown => { - None - } + IntVarValue::Unknown => None, } } @@ -839,9 +840,7 @@ impl<'db> InferCtxt<'db> { let value = inner.float_unification_table().probe_value(vid); match value { FloatVarValue::Known(ty) => Some(Ty::new_float(self.interner, ty)), - FloatVarValue::Unknown => { - None - } + FloatVarValue::Unknown => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 79c402ff29c3d..f66b8dace30a6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -141,7 +141,10 @@ impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db pub trait ChalkToNextSolver<'db, Out> { fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out; - fn from_nextsolver(out: Out, interner: DbInterner<'db>) -> Self; +} + +pub trait NextSolverToChalk<'db, Out> { + fn to_chalk(self, interner: DbInterner<'db>) -> Out; } impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { @@ -428,342 +431,11 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { }, ) } +} - fn from_nextsolver(out: Ty<'db>, interner: DbInterner<'db>) -> Self { - use crate::{Scalar, TyKind}; - use chalk_ir::{FloatTy, IntTy, UintTy}; - match out.kind() { - rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool), - rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char), - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => { - TyKind::Scalar(Scalar::Int(IntTy::I8)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => { - TyKind::Scalar(Scalar::Int(IntTy::I16)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => { - TyKind::Scalar(Scalar::Int(IntTy::I32)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => { - TyKind::Scalar(Scalar::Int(IntTy::I64)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => { - TyKind::Scalar(Scalar::Int(IntTy::I128)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => { - TyKind::Scalar(Scalar::Int(IntTy::Isize)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => { - TyKind::Scalar(Scalar::Uint(UintTy::U8)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => { - TyKind::Scalar(Scalar::Uint(UintTy::U16)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => { - TyKind::Scalar(Scalar::Uint(UintTy::U32)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => { - TyKind::Scalar(Scalar::Uint(UintTy::U64)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => { - TyKind::Scalar(Scalar::Uint(UintTy::U128)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => { - TyKind::Scalar(Scalar::Uint(UintTy::Usize)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => { - TyKind::Scalar(Scalar::Float(FloatTy::F16)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => { - TyKind::Scalar(Scalar::Float(FloatTy::F32)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => { - TyKind::Scalar(Scalar::Float(FloatTy::F64)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => { - TyKind::Scalar(Scalar::Float(FloatTy::F128)) - } - rustc_type_ir::TyKind::Str => TyKind::Str, - rustc_type_ir::TyKind::Error(_) => TyKind::Error, - rustc_type_ir::TyKind::Never => TyKind::Never, - - rustc_type_ir::TyKind::Adt(def, args) => { - let adt_id = def.inner().id; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - TyKind::Adt(chalk_ir::AdtId(adt_id), subst) - } - - rustc_type_ir::TyKind::Infer(infer_ty) => { - let (var, kind) = match infer_ty { - rustc_type_ir::InferTy::TyVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::General) - } - rustc_type_ir::InferTy::IntVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::Integer) - } - rustc_type_ir::InferTy::FloatVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::Float) - } - _ => todo!(), - }; - TyKind::InferenceVar(var, kind) - } - - rustc_type_ir::TyKind::Ref(r, ty, mutability) => { - let mutability = match mutability { - rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, - rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, - }; - let r = ChalkToNextSolver::from_nextsolver(r, interner); - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - TyKind::Ref(mutability, r, ty) - } - - rustc_type_ir::TyKind::Tuple(tys) => { - let size = tys.len(); - let subst = Substitution::from_iter( - Interner, - tys.iter().map(|ty| { - chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver( - ty, interner, - )) - .intern(Interner) - }), - ); - TyKind::Tuple(size, subst) - } - - rustc_type_ir::TyKind::Array(ty, const_) => { - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - let const_ = ChalkToNextSolver::from_nextsolver(const_, interner); - TyKind::Array(ty, const_) - } - - rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind { - rustc_type_ir::AliasTyKind::Projection => { - let assoc_ty_id = match alias_ty.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let associated_ty_id = to_assoc_type_id(assoc_ty_id); - let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); - TyKind::AssociatedType(associated_ty_id, substitution) - } - rustc_type_ir::AliasTyKind::Opaque => { - let opaque_ty_id = match alias_ty.def_id { - SolverDefId::InternedOpaqueTyId(id) => id, - _ => unreachable!(), - }; - let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); - TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { - opaque_ty_id: opaque_ty_id.into(), - substitution, - })) - } - rustc_type_ir::AliasTyKind::Inherent => todo!(), - rustc_type_ir::AliasTyKind::Free => todo!(), - }, - - rustc_type_ir::TyKind::Placeholder(placeholder) => { - let ui = chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }; - let placeholder_index = - chalk_ir::PlaceholderIndex { idx: placeholder.bound.var.as_usize(), ui }; - TyKind::Placeholder(placeholder_index) - } - - rustc_type_ir::TyKind::Bound(debruijn_index, ty) => { - TyKind::BoundVar(chalk_ir::BoundVar { - debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - index: ty.var.as_usize(), - }) - } - - rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => { - let num_binders = bound_sig.bound_vars().len(); - let sig = chalk_ir::FnSig { - abi: fn_header.abi, - safety: match fn_header.safety { - crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, - crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: fn_header.c_variadic, - }; - let args = GenericArgs::new_from_iter( - interner, - bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), - ); - let substitution = ChalkToNextSolver::from_nextsolver(args, interner); - let substitution = chalk_ir::FnSubst(substitution); - let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; - TyKind::Function(fnptr) - } - - rustc_type_ir::TyKind::Dynamic(preds, region, dyn_kind) => { - assert!(matches!(dyn_kind, rustc_type_ir::DynKind::Dyn)); - let self_ty = Ty::new_bound( - interner, - DebruijnIndex::from_u32(1), - BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) }, - ); - let bounds = chalk_ir::QuantifiedWhereClauses::from_iter( - Interner, - preds.iter().map(|p| { - let binders = chalk_ir::VariableKinds::from_iter( - Interner, - p.bound_vars().iter().map(|b| match b { - BoundVarKind::Ty(kind) => { - chalk_ir::VariableKind::Ty(TyVariableKind::General) - } - BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime, - BoundVarKind::Const => chalk_ir::VariableKind::Const( - crate::TyKind::Error.intern(Interner), - ), - }), - ); - let where_clause = match p.skip_binder() { - rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { - let trait_ref = TraitRef::new( - interner, - trait_ref.def_id, - [self_ty.clone().into()] - .into_iter() - .chain(trait_ref.args.iter()), - ); - let trait_id = match trait_ref.def_id { - SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; - let substitution = - ChalkToNextSolver::from_nextsolver(trait_ref.args, interner); - let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; - chalk_ir::WhereClause::Implemented(trait_ref) - } - rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => { - let trait_id = match trait_ { - SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; - let substitution = chalk_ir::Substitution::empty(Interner); - let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; - chalk_ir::WhereClause::Implemented(trait_ref) - } - rustc_type_ir::ExistentialPredicate::Projection( - existential_projection, - ) => { - let projection = ProjectionPredicate { - projection_term: AliasTerm::new( - interner, - existential_projection.def_id, - [self_ty.clone().into()] - .iter() - .chain(existential_projection.args.clone().iter()), - ), - term: existential_projection.term.clone(), - }; - let associated_ty_id = match projection.projection_term.def_id { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => unreachable!(), - }; - let substitution = ChalkToNextSolver::from_nextsolver( - projection.projection_term.args, - interner, - ); - let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id, - substitution, - }); - let ty = match projection.term { - Term::Ty(ty) => ty, - _ => unreachable!(), - }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - let alias_eq = chalk_ir::AliasEq { alias, ty }; - chalk_ir::WhereClause::AliasEq(alias_eq) - } - }; - chalk_ir::Binders::new(binders, where_clause) - }), - ); - let binders = chalk_ir::VariableKinds::from1( - Interner, - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - ); - let bounds = chalk_ir::Binders::new(binders, bounds); - let dyn_ty = chalk_ir::DynTy { - bounds, - lifetime: ChalkToNextSolver::from_nextsolver(region, interner), - }; - TyKind::Dyn(dyn_ty) - } - - rustc_type_ir::TyKind::Slice(ty) => { - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - TyKind::Slice(ty) - } - - rustc_type_ir::TyKind::Foreign(def_id) => { - let id = match def_id { - SolverDefId::TypeAliasId(id) => to_foreign_def_id(id), - _ => unreachable!(), - }; - TyKind::Foreign(id) - } - rustc_type_ir::TyKind::Pat(_, _) => todo!(), - rustc_type_ir::TyKind::RawPtr(ty, mutability) => { - let mutability = match mutability { - rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, - rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, - }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - TyKind::Raw(mutability, ty) - } - rustc_type_ir::TyKind::FnDef(def_id, args) => { - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - match def_id { - SolverDefId::FunctionId(id) => { - TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst) - } - SolverDefId::Ctor(Ctor::Enum(e)) => TyKind::FnDef( - CallableDefId::EnumVariantId(e).to_chalk(interner.db()), - subst, - ), - SolverDefId::Ctor(Ctor::Struct(s)) => { - TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst) - } - _ => unreachable!("Unexpected def id {:?}", def_id), - } - } - - rustc_type_ir::TyKind::Closure(def_id, args) => { - let id = match def_id { - SolverDefId::InternedClosureId(id) => id, - _ => unreachable!(), - }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - TyKind::Closure(id.into(), subst) - } - rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(), - rustc_type_ir::TyKind::Coroutine(def_id, args) => { - let id = match def_id { - SolverDefId::InternedCoroutineId(id) => id, - _ => unreachable!(), - }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - TyKind::Coroutine(id.into(), subst) - } - rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { - let id = match def_id { - SolverDefId::InternedCoroutineId(id) => id, - _ => unreachable!(), - }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - TyKind::CoroutineWitness(id.into(), subst) - } - - rustc_type_ir::TyKind::Param(_) => todo!(), - rustc_type_ir::TyKind::UnsafeBinder(_) => todo!(), - } - .intern(Interner) +impl<'db> NextSolverToChalk<'db, chalk_ir::Ty> for Ty<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Ty { + convert_ty_for_result(interner, self) } } @@ -799,39 +471,11 @@ impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { }, ) } +} - fn from_nextsolver(out: Region<'db>, interner: DbInterner<'db>) -> Self { - match out.kind() { - rustc_type_ir::RegionKind::ReEarlyParam(early) => todo!(), - rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new( - Interner, - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(db.as_u32()), - bound.var.as_usize(), - )), - ), - rustc_type_ir::RegionKind::ReLateParam(_) => todo!(), - rustc_type_ir::RegionKind::ReStatic => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Static) - } - rustc_type_ir::RegionKind::ReVar(vid) => chalk_ir::Lifetime::new( - Interner, - chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())), - ), - rustc_type_ir::RegionKind::RePlaceholder(placeholder) => chalk_ir::Lifetime::new( - Interner, - chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { - idx: placeholder.bound.var.as_usize(), - ui: chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }, - }), - ), - rustc_type_ir::RegionKind::ReErased => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Erased) - } - rustc_type_ir::RegionKind::ReError(_) => { - chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Error) - } - } +impl<'db> NextSolverToChalk<'db, chalk_ir::Lifetime> for Region<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Lifetime { + convert_region_for_result(interner, self) } } @@ -877,61 +521,11 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { }, ) } +} - fn from_nextsolver(out: Const<'db>, interner: DbInterner<'db>) -> Self { - let value: chalk_ir::ConstValue = match out.kind() { - rustc_type_ir::ConstKind::Param(_) => unimplemented!(), - rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { - chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32())) - } - rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => { - panic!("Vars should not be freshened.") - } - rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { - chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - var.index(), - )) - } - rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { - chalk_ir::ConstValue::Placeholder(chalk_ir::PlaceholderIndex { - ui: chalk_ir::UniverseIndex { counter: placeholder_const.universe.as_usize() }, - idx: placeholder_const.bound.as_usize(), - }) - } - rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => { - let id = match unevaluated_const.def { - SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), - SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), - _ => unreachable!(), - }; - let subst = ChalkToNextSolver::from_nextsolver(unevaluated_const.args, interner); - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::UnevaluatedConst(id, subst), - }) - } - rustc_type_ir::ConstKind::Value(value_const) => { - let bytes = value_const.value.inner(); - let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - // SAFETY: will never use this without a db - interned: ConstScalar::Bytes(bytes.0.clone(), unsafe { - std::mem::transmute::, MemoryMap<'static>>(bytes.1.clone()) - }), - }); - return chalk_ir::ConstData { - ty: ChalkToNextSolver::from_nextsolver(value_const.ty, interner), - value, - } - .intern(Interner); - } - rustc_type_ir::ConstKind::Error(_) => { - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Unknown, - }) - } - rustc_type_ir::ConstKind::Expr(_) => unimplemented!(), - }; - chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) +impl<'db> NextSolverToChalk<'db, chalk_ir::Const> for Const<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Const { + convert_const_for_result(interner, self) } } @@ -946,13 +540,6 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys>> ), } } - - fn from_nextsolver( - out: rustc_type_ir::FnSigTys>, - interner: DbInterner<'db>, - ) -> Self { - todo!() - } } impl< @@ -971,13 +558,6 @@ impl< binders.to_nextsolver(interner), ) } - - fn from_nextsolver( - out: rustc_type_ir::Binder, U>, - interner: DbInterner<'db>, - ) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds { @@ -987,10 +567,6 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind { @@ -1001,10 +577,6 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind BoundVarKind::Const, } } - - fn from_nextsolver(out: BoundVarKind, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg { @@ -1015,11 +587,8 @@ impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg const_.to_nextsolver(interner).into(), } } - - fn from_nextsolver(out: GenericArg<'db>, interner: DbInterner<'db>) -> Self { - todo!() - } } + impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution { fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> { GenericArgs::new_from_iter( @@ -1027,30 +596,11 @@ impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution GenericArg<'db> { arg.to_nextsolver(interner) }), ) } +} - fn from_nextsolver(out: GenericArgs<'db>, interner: DbInterner<'db>) -> Self { - let mut substs = Vec::with_capacity(out.len()); - for arg in out.iter() { - match arg.clone().kind() { - rustc_type_ir::GenericArgKind::Type(ty) => { - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner)); - } - rustc_type_ir::GenericArgKind::Lifetime(region) => { - let lifetime = ChalkToNextSolver::from_nextsolver(region, interner); - substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner)); - } - rustc_type_ir::GenericArgKind::Const(const_) => { - substs.push( - chalk_ir::GenericArgData::Const(ChalkToNextSolver::from_nextsolver( - const_, interner, - )) - .intern(Interner), - ); - } - } - } - Substitution::from_iter(Interner, substs) +impl<'db> NextSolverToChalk<'db, chalk_ir::Substitution> for GenericArgs<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Substitution { + convert_args_for_result(interner, self.as_slice()) } } @@ -1067,29 +617,29 @@ impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution }), ) } - - fn from_nextsolver(out: Tys<'db>, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { + fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { rustc_type_ir::DebruijnIndex::from_u32(self.depth()) } +} - fn from_nextsolver(out: rustc_type_ir::DebruijnIndex, interner: DbInterner<'db>) -> Self { - todo!() +impl<'db> NextSolverToChalk<'db, chalk_ir::DebruijnIndex> for rustc_type_ir::DebruijnIndex { + fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::DebruijnIndex { + chalk_ir::DebruijnIndex::new(self.index() as u32) } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex { + fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex { rustc_type_ir::UniverseIndex::from_u32(self.counter as u32) } +} - fn from_nextsolver(out: rustc_type_ir::UniverseIndex, interner: DbInterner<'db>) -> Self { - todo!() +impl<'db> NextSolverToChalk<'db, chalk_ir::UniverseIndex> for rustc_type_ir::UniverseIndex { + fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::UniverseIndex { + chalk_ir::UniverseIndex { counter: self.index() } } } @@ -1109,10 +659,6 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy> } } } - - fn from_nextsolver(out: rustc_type_ir::InferTy, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability { @@ -1122,10 +668,6 @@ impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutabil chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not, } } - - fn from_nextsolver(out: rustc_ast_ir::Mutability, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { @@ -1137,10 +679,6 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant, } } - - fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance { @@ -1151,10 +689,6 @@ impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant, } } - - fn from_nextsolver(out: rustc_type_ir::Variance, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances { @@ -1164,10 +698,6 @@ impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)), ) } - - fn from_nextsolver(out: VariancesOf, interner: DbInterner<'db>) -> Self { - todo!() - } } impl<'db> ChalkToNextSolver<'db, Goal, Predicate<'db>>> @@ -1180,14 +710,18 @@ impl<'db> ChalkToNextSolver<'db, Goal, Predicate<'db>>> self.goal.to_nextsolver(interner), ) } +} - fn from_nextsolver( - out: Goal, Predicate<'db>>, +impl<'db> NextSolverToChalk<'db, chalk_ir::InEnvironment>> + for Goal, Predicate<'db>> +{ + fn to_chalk( + self, interner: DbInterner<'db>, - ) -> Self { + ) -> chalk_ir::InEnvironment> { chalk_ir::InEnvironment { - environment: ChalkToNextSolver::from_nextsolver(out.param_env, interner), - goal: ChalkToNextSolver::from_nextsolver(out.predicate, interner), + environment: self.param_env.to_chalk(interner), + goal: self.predicate.to_chalk(interner), } } } @@ -1224,11 +758,15 @@ impl<'db, T: HasInterner + ChalkToNextSolver<'db, U>, U> variables, } } +} - fn from_nextsolver(out: Canonical<'db, U>, interner: DbInterner<'db>) -> Self { +impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner> + NextSolverToChalk<'db, chalk_ir::Canonical> for Canonical<'db, T> +{ + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Canonical { let binders = chalk_ir::CanonicalVarKinds::from_iter( Interner, - out.variables.iter().map(|v| match v { + self.variables.iter().map(|v| match v { rustc_type_ir::CanonicalVarKind::Ty( rustc_type_ir::CanonicalTyVarKind::General(ui), ) => chalk_ir::CanonicalVarKind::new( @@ -1247,20 +785,20 @@ impl<'db, T: HasInterner + ChalkToNextSolver<'db, U>, U> chalk_ir::UniverseIndex::root(), ) } - rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => todo!(), rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new( chalk_ir::VariableKind::Lifetime, chalk_ir::UniverseIndex { counter: ui.as_usize() }, ), - rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => todo!(), rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new( chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)), chalk_ir::UniverseIndex { counter: ui.as_usize() }, ), - rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => todo!(), + rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(), + rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(), + rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(), }), ); - let value = ChalkToNextSolver::from_nextsolver(out.value, interner); + let value = self.value.to_chalk(interner); chalk_ir::Canonical { binders, value } } } @@ -1281,9 +819,16 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."), chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."), chalk_ir::GoalData::EqGoal(eq_goal) => { + let arg_to_term = |g: &chalk_ir::GenericArg| match g.data(Interner) { + chalk_ir::GenericArgData::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)), + chalk_ir::GenericArgData::Const(const_) => { + Term::Const(const_.to_nextsolver(interner)) + } + chalk_ir::GenericArgData::Lifetime(lifetime) => unreachable!(), + }; let pred_kind = PredicateKind::AliasRelate( - Term::Ty(eq_goal.a.assert_ty_ref(Interner).clone().to_nextsolver(interner)), - Term::Ty(eq_goal.b.assert_ty_ref(Interner).clone().to_nextsolver(interner)), + arg_to_term(&eq_goal.a), + arg_to_term(&eq_goal.b), rustc_type_ir::AliasRelationDirection::Equate, ); let pred_kind = @@ -1314,123 +859,11 @@ impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."), } } +} - fn from_nextsolver(out: Predicate<'db>, interner: DbInterner<'db>) -> Self { - chalk_ir::Goal::new( - Interner, - match out.kind().skip_binder() { - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( - trait_pred, - )) => { - let trait_ref = - ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner); - let where_clause = chalk_ir::WhereClause::Implemented(trait_ref); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection( - proj_predicate, - )) => { - let associated_ty_id = match proj_predicate.def_id() { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => unreachable!(), - }; - let substitution = ChalkToNextSolver::from_nextsolver( - proj_predicate.projection_term.args, - interner, - ); - let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id, - substitution, - }); - let ty = match proj_predicate.term.kind() { - rustc_type_ir::TermKind::Ty(ty) => ty, - rustc_type_ir::TermKind::Const(_) => todo!(), - }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - let alias_eq = chalk_ir::AliasEq { alias, ty }; - let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives( - outlives, - )) => { - let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner); - let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner); - let where_clause = - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - lifetime, - ty, - }); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::RegionOutlives(outlives), - ) => { - let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner); - let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner); - let where_clause = - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a, - b, - }); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(_) => todo!(), - rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(), - rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(), - rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(), - rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(), - rustc_type_ir::PredicateKind::Ambiguous => todo!(), - rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(), - rustc_type_ir::PredicateKind::AliasRelate( - alias_term, - ty_term, - alias_relation_direction, - ) => { - let ty = match ty_term { - Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner), - Term::Const(..) => todo!(), - }; - match alias_term { - Term::Ty(alias_ty) => match alias_ty.kind() { - rustc_type_ir::TyKind::Alias(kind, alias) => match kind { - rustc_type_ir::AliasTyKind::Projection => { - let associated_ty_id = match alias.def_id { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => todo!(), - }; - let substitution = - ChalkToNextSolver::from_nextsolver(alias.args, interner); - let proj_ty = - chalk_ir::ProjectionTy { associated_ty_id, substitution }; - let alias = chalk_ir::AliasTy::Projection(proj_ty); - let alias_eq = chalk_ir::AliasEq { alias, ty }; - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(alias_eq), - )) - } - _ => todo!(), - }, - rustc_type_ir::TyKind::Infer(var) => { - assert!(matches!( - alias_relation_direction, - rustc_type_ir::AliasRelationDirection::Equate - )); - let a: chalk_ir::Ty<_> = - ChalkToNextSolver::from_nextsolver(alias_ty, interner); - let eq_goal = chalk_ir::EqGoal { - a: chalk_ir::GenericArgData::Ty(a).intern(Interner), - b: chalk_ir::GenericArgData::Ty(ty).intern(Interner), - }; - chalk_ir::GoalData::EqGoal(eq_goal) - } - _ => todo!("Unexpected alias term {:?}", alias_term), - }, - Term::Const(..) => todo!(), - } - } - }, - ) +impl<'db> NextSolverToChalk<'db, chalk_ir::Goal> for Predicate<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Goal { + chalk_ir::Goal::new(Interner, self.kind().skip_binder().to_chalk(interner)) } } @@ -1444,12 +877,14 @@ impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment, interner: DbInterner<'db>) -> Self { +impl<'db> NextSolverToChalk<'db, chalk_ir::Environment> for ParamEnv<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Environment { let clauses = chalk_ir::ProgramClauses::from_iter( Interner, - out.clauses.iter().map(|c| -> chalk_ir::ProgramClause { - ChalkToNextSolver::from_nextsolver(c, interner) + self.clauses.iter().filter_map(|c| -> Option> { + c.to_chalk(interner) }), ); chalk_ir::Environment { clauses } @@ -1460,15 +895,19 @@ impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause) -> Clause<'db> { Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner))) } +} - fn from_nextsolver(out: Clause<'db>, interner: DbInterner<'db>) -> Self { - chalk_ir::ProgramClause::new( +impl<'db> NextSolverToChalk<'db, Option>> for Clause<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> Option> { + let value: chalk_ir::ProgramClauseImplication = + as NextSolverToChalk< + 'db, + Option>, + >>::to_chalk(self.0.kind().skip_binder(), interner)?; + Some(chalk_ir::ProgramClause::new( Interner, - chalk_ir::ProgramClauseData(chalk_ir::Binders::empty( - Interner, - ChalkToNextSolver::from_nextsolver(out.0.kind().skip_binder(), interner), - )), - ) + chalk_ir::ProgramClauseData(chalk_ir::Binders::empty(Interner, value)), + )) } } @@ -1480,13 +919,25 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> assert!(self.constraints.is_empty(Interner)); self.consequence.to_nextsolver(interner) } - fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self { - chalk_ir::ProgramClauseImplication { - consequence: ChalkToNextSolver::from_nextsolver(out, interner), +} + +impl<'db> NextSolverToChalk<'db, Option>> + for PredicateKind<'db> +{ + fn to_chalk( + self, + interner: DbInterner<'db>, + ) -> Option> { + let chalk_ir::GoalData::DomainGoal(consequence) = self.to_chalk(interner) else { + return None; + }; + + Some(chalk_ir::ProgramClauseImplication { + consequence, conditions: chalk_ir::Goals::empty(Interner), constraints: chalk_ir::Constraints::empty(Interner), priority: chalk_ir::ClausePriority::High, - } + }) } } @@ -1606,13 +1057,15 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal panic!("Should not be constructed."), } } +} - fn from_nextsolver(out: PredicateKind<'db>, interner: DbInterner<'db>) -> Self { - let domain_goal = match out { +impl<'db> NextSolverToChalk<'db, chalk_ir::GoalData> for PredicateKind<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::GoalData { + match self { rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => { - let trait_ref = ChalkToNextSolver::from_nextsolver(trait_pred.trait_ref, interner); + let trait_ref = trait_pred.trait_ref.to_chalk(interner); let where_clause = chalk_ir::WhereClause::Implemented(trait_ref); - chalk_ir::DomainGoal::Holds(where_clause) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) } rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection( proj_predicate, @@ -1621,82 +1074,67 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal to_assoc_type_id(id), _ => unreachable!(), }; - let substitution = ChalkToNextSolver::from_nextsolver( - proj_predicate.projection_term.args, - interner, - ); + let substitution = proj_predicate.projection_term.args.to_chalk(interner); let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id, substitution, }); let ty = match proj_predicate.term.kind() { rustc_type_ir::TermKind::Ty(ty) => ty, - rustc_type_ir::TermKind::Const(_) => todo!(), + rustc_type_ir::TermKind::Const(_) => unimplemented!(), }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let ty = ty.to_chalk(interner); let alias_eq = chalk_ir::AliasEq { alias, ty }; let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq); - chalk_ir::DomainGoal::Holds(where_clause) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) } rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives( outlives, )) => { - let lifetime = ChalkToNextSolver::from_nextsolver(outlives.1, interner); - let ty = ChalkToNextSolver::from_nextsolver(outlives.0, interner); + let lifetime = outlives.1.to_chalk(interner); + let ty = outlives.0.to_chalk(interner); let where_clause = chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty }); - chalk_ir::DomainGoal::Holds(where_clause) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) } rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives( outlives, )) => { - let a = ChalkToNextSolver::from_nextsolver(outlives.0, interner); - let b = ChalkToNextSolver::from_nextsolver(outlives.1, interner); + let a = outlives.0.to_chalk(interner); + let b = outlives.1.to_chalk(interner); let where_clause = chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b }); - chalk_ir::DomainGoal::Holds(where_clause) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) } - rustc_type_ir::PredicateKind::Clause(_) => todo!(), - rustc_type_ir::PredicateKind::DynCompatible(_) => todo!(), - rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => todo!(), - rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => todo!(), - rustc_type_ir::PredicateKind::ConstEquate(_, _) => todo!(), - rustc_type_ir::PredicateKind::Ambiguous => todo!(), - rustc_type_ir::PredicateKind::NormalizesTo(normalizes_to) => todo!(), rustc_type_ir::PredicateKind::AliasRelate( alias_term, - ty_term, + target_term, alias_relation_direction, ) => { - let alias = match alias_term { - Term::Ty(alias_ty) => match alias_ty.kind() { - rustc_type_ir::TyKind::Alias(kind, alias) => match kind { - rustc_type_ir::AliasTyKind::Projection => { - let associated_ty_id = match alias.def_id { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => todo!(), - }; - let substitution = - ChalkToNextSolver::from_nextsolver(alias.args, interner); - let proj_ty = - chalk_ir::ProjectionTy { associated_ty_id, substitution }; - chalk_ir::AliasTy::Projection(proj_ty) - } - _ => todo!(), - }, - _ => todo!(), - }, - Term::Const(..) => todo!(), - }; - let ty = match ty_term { - Term::Ty(ty) => ChalkToNextSolver::from_nextsolver(ty, interner), - Term::Const(..) => todo!(), + let term_to_generic_arg = |term: Term<'db>| match term { + Term::Ty(ty) => chalk_ir::GenericArg::new( + Interner, + chalk_ir::GenericArgData::Ty(ty.to_chalk(interner)), + ), + Term::Const(const_) => chalk_ir::GenericArg::new( + Interner, + chalk_ir::GenericArgData::Const(const_.to_chalk(interner)), + ), }; - let alias_eq = chalk_ir::AliasEq { alias, ty }; - chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq(alias_eq)) + + chalk_ir::GoalData::EqGoal(chalk_ir::EqGoal { + a: term_to_generic_arg(alias_term), + b: term_to_generic_arg(target_term), + }) } - }; - domain_goal + rustc_type_ir::PredicateKind::Clause(_) => unimplemented!(), + rustc_type_ir::PredicateKind::DynCompatible(_) => unimplemented!(), + rustc_type_ir::PredicateKind::Subtype(_) => unimplemented!(), + rustc_type_ir::PredicateKind::Coerce(_) => unimplemented!(), + rustc_type_ir::PredicateKind::ConstEquate(_, _) => unimplemented!(), + rustc_type_ir::PredicateKind::Ambiguous => unimplemented!(), + rustc_type_ir::PredicateKind::NormalizesTo(_) => unimplemented!(), + } } } @@ -1705,13 +1143,12 @@ impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef let args = self.substitution.to_nextsolver(interner); TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args) } +} - fn from_nextsolver(out: TraitRef<'db>, interner: DbInterner<'db>) -> Self { - let trait_id = match out.def_id { - SolverDefId::TraitId(id) => to_chalk_trait_id(id), - _ => unreachable!(), - }; - let substitution = ChalkToNextSolver::from_nextsolver(out.args, interner); +impl<'db> NextSolverToChalk<'db, chalk_ir::TraitRef> for TraitRef<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::TraitRef { + let trait_id = to_chalk_trait_id(self.def_id.0); + let substitution = self.args.to_chalk(interner); chalk_ir::TraitRef { trait_id, substitution } } } @@ -1754,9 +1191,17 @@ impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause, interner: DbInterner<'db>) -> Self { - todo!() +impl<'db, I> NextSolverToChalk<'db, chalk_ir::ConstrainedSubst> for I +where + I: IntoIterator>, +{ + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::ConstrainedSubst { + chalk_ir::ConstrainedSubst { + constraints: chalk_ir::Constraints::empty(Interner), + subst: GenericArgs::new_from_iter(interner, self).to_chalk(interner), + } } } @@ -1764,51 +1209,7 @@ pub fn convert_canonical_args_for_result<'db>( interner: DbInterner<'db>, args: Canonical<'db, Vec>>, ) -> chalk_ir::Canonical> { - let Canonical { value, variables, max_universe } = args; - let binders = CanonicalVarKinds::from_iter( - Interner, - variables.iter().map(|v| match v { - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::General(_)) => { - CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex::ROOT, - ) - } - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) => { - CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Integer), - chalk_ir::UniverseIndex::ROOT, - ) - } - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Float) => { - CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Float), - chalk_ir::UniverseIndex::ROOT, - ) - } - rustc_type_ir::CanonicalVarKind::Region(universe_index) => CanonicalVarKind::new( - chalk_ir::VariableKind::Lifetime, - chalk_ir::UniverseIndex::ROOT, - ), - rustc_type_ir::CanonicalVarKind::Const(universe_index) => CanonicalVarKind::new( - chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner)), - chalk_ir::UniverseIndex::ROOT, - ), - rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(), - rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(), - rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(), - }), - ); - chalk_ir::Canonical { - binders, - value: chalk_ir::ConstrainedSubst { - constraints: chalk_ir::Constraints::empty(Interner), - subst: ChalkToNextSolver::from_nextsolver( - GenericArgs::new_from_iter(interner, value), - interner, - ), - }, - } + args.to_chalk(interner) } pub fn convert_args_for_result<'db>( @@ -1897,7 +1298,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::TyKind::Adt(def, args) => { let adt_id = def.inner().id; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); + let subst = convert_args_for_result(interner, args.as_slice()); TyKind::Adt(chalk_ir::AdtId(adt_id), subst) } @@ -1912,7 +1313,11 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) rustc_type_ir::InferTy::FloatVar(var) => { (InferenceVar::from(var.as_u32()), TyVariableKind::Float) } - _ => todo!(), + rustc_type_ir::InferTy::FreshFloatTy(..) + | rustc_type_ir::InferTy::FreshIntTy(..) + | rustc_type_ir::InferTy::FreshTy(..) => { + panic!("Freshening shouldn't happen.") + } }; TyKind::InferenceVar(var, kind) } @@ -1932,7 +1337,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) let subst = Substitution::from_iter( Interner, tys.iter().map(|ty| { - chalk_ir::GenericArgData::Ty(ChalkToNextSolver::from_nextsolver(ty, interner)) + chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty)) .intern(Interner) }), ); @@ -1940,8 +1345,8 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) } rustc_type_ir::TyKind::Array(ty, const_) => { - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); - let const_ = ChalkToNextSolver::from_nextsolver(const_, interner); + let ty = convert_ty_for_result(interner, ty); + let const_ = convert_const_for_result(interner, const_); TyKind::Array(ty, const_) } @@ -1952,7 +1357,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) _ => unreachable!(), }; let associated_ty_id = to_assoc_type_id(assoc_ty_id); - let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); + let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); TyKind::AssociatedType(associated_ty_id, substitution) } rustc_type_ir::AliasTyKind::Opaque => { @@ -1960,14 +1365,14 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedOpaqueTyId(id) => id, _ => unreachable!(), }; - let substitution = ChalkToNextSolver::from_nextsolver(alias_ty.args, interner); + let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id: opaque_ty_id.into(), substitution, })) } - rustc_type_ir::AliasTyKind::Inherent => todo!(), - rustc_type_ir::AliasTyKind::Free => todo!(), + rustc_type_ir::AliasTyKind::Inherent => unimplemented!(), + rustc_type_ir::AliasTyKind::Free => unimplemented!(), }, // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion. @@ -2002,7 +1407,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) interner, bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), ); - let substitution = ChalkToNextSolver::from_nextsolver(args, interner); + let substitution = convert_args_for_result(interner, args.as_slice()); let substitution = chalk_ir::FnSubst(substitution); let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; TyKind::Function(fnptr) @@ -2045,11 +1450,11 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) let trait_ref = TraitRef::new( interner, trait_ref.def_id, - [self_ty.clone().into()].into_iter().chain(trait_ref.args.iter()), + [self_ty.into()].into_iter().chain(trait_ref.args.iter()), ); let trait_id = to_chalk_trait_id(trait_ref.def_id.0); let substitution = - ChalkToNextSolver::from_nextsolver(trait_ref.args, interner); + convert_args_for_result(interner, trait_ref.args.as_slice()); let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; chalk_ir::WhereClause::Implemented(trait_ref) } @@ -2067,19 +1472,19 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) projection_term: AliasTerm::new( interner, existential_projection.def_id, - [self_ty.clone().into()] + [self_ty.into()] .iter() - .chain(existential_projection.args.clone().iter()), + .chain(existential_projection.args.iter()), ), - term: existential_projection.term.clone(), + term: existential_projection.term, }; let associated_ty_id = match projection.projection_term.def_id { SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), _ => unreachable!(), }; - let substitution = ChalkToNextSolver::from_nextsolver( - projection.projection_term.args, + let substitution = convert_args_for_result( interner, + projection.projection_term.args.as_slice(), ); let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id, @@ -2089,7 +1494,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) Term::Ty(ty) => ty, _ => unreachable!(), }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let ty = convert_ty_for_result(interner, ty); let alias_eq = chalk_ir::AliasEq { alias, ty }; chalk_ir::WhereClause::AliasEq(alias_eq) } @@ -2108,7 +1513,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) } rustc_type_ir::TyKind::Slice(ty) => { - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let ty = convert_ty_for_result(interner, ty); TyKind::Slice(ty) } @@ -2119,29 +1524,24 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) }; TyKind::Foreign(to_foreign_def_id(def_id)) } - rustc_type_ir::TyKind::Pat(_, _) => todo!(), + rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(), rustc_type_ir::TyKind::RawPtr(ty, mutability) => { let mutability = match mutability { rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, }; - let ty = ChalkToNextSolver::from_nextsolver(ty, interner); + let ty = convert_ty_for_result(interner, ty); TyKind::Raw(mutability, ty) } rustc_type_ir::TyKind::FnDef(def_id, args) => { - let subst = ChalkToNextSolver::from_nextsolver(args, interner); - match def_id { - SolverDefId::FunctionId(id) => { - TyKind::FnDef(CallableDefId::FunctionId(id).to_chalk(interner.db()), subst) - } - SolverDefId::Ctor(Ctor::Enum(e)) => { - TyKind::FnDef(CallableDefId::EnumVariantId(e).to_chalk(interner.db()), subst) - } - SolverDefId::Ctor(Ctor::Struct(s)) => { - TyKind::FnDef(CallableDefId::StructId(s).to_chalk(interner.db()), subst) - } - _ => unreachable!("Unexpected def id {:?}", def_id), - } + let id = match def_id { + SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), + SolverDefId::Ctor(Ctor::Struct(id)) => CallableDefId::StructId(id), + SolverDefId::Ctor(Ctor::Enum(id)) => CallableDefId::EnumVariantId(id), + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::FnDef(id.to_chalk(interner.db()), subst) } rustc_type_ir::TyKind::Closure(def_id, args) => { @@ -2149,16 +1549,16 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedClosureId(id) => id, _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); + let subst = convert_args_for_result(interner, args.as_slice()); TyKind::Closure(id.into(), subst) } - rustc_type_ir::TyKind::CoroutineClosure(_, _) => todo!(), + rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(), rustc_type_ir::TyKind::Coroutine(def_id, args) => { let id = match def_id { SolverDefId::InternedCoroutineId(id) => id, _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); + let subst = convert_args_for_result(interner, args.as_slice()); TyKind::Coroutine(id.into(), subst) } rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { @@ -2166,7 +1566,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) SolverDefId::InternedCoroutineId(id) => id, _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(args, interner); + let subst = convert_args_for_result(interner, args.as_slice()); TyKind::CoroutineWitness(id.into(), subst) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index b9b2950a94a3b..385149d78432e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -9,12 +9,12 @@ use rustc_type_ir::{ solve::{Certainty, NoSolution}, }; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ TraitRefExt, db::HirDatabase, next_solver::{ - ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, - mapping::ChalkToNextSolver, + ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, mapping::ChalkToNextSolver, util::sizedness_fast_path, }, }; @@ -200,7 +200,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { SolverDefId::StaticId(c) => GeneralConstId::StaticId(c), _ => unreachable!(), }; - let subst = ChalkToNextSolver::from_nextsolver(uv.args, self.interner); + let subst = uv.args.to_chalk(self.interner); let ec = self.cx().db.const_eval(c, subst, None).ok()?; Some(ec.to_nextsolver(self.interner)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 3b7d4d2184a59..7ec5231a7341a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -49,7 +49,7 @@ fn let_stmt_coerce() { //- minicore: coerce_unsized fn test() { let x: &[isize] = &[1]; - // ^^^^ adjustments: Deref(None), Borrow(Ref('?2, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?1, Not)), Pointer(Unsize) let x: *const [isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) } @@ -96,7 +96,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { foo(&[1]) - // ^^^^ adjustments: Deref(None), Borrow(Ref('?11, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?1, Not)), Pointer(Unsize) } else { &[1] }; @@ -148,7 +148,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref('?11, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?1, Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; @@ -881,7 +881,7 @@ fn adjust_index() { fn test() { let x = [1, 2, 3]; x[2] = 6; - // ^ adjustments: Borrow(Ref('?8, Mut)) + // ^ adjustments: Borrow(Ref('?0, Mut)) } ", ); @@ -906,11 +906,11 @@ impl core::ops::IndexMut for StructMut { } fn test() { Struct[0]; - // ^^^^^^ adjustments: Borrow(Ref('?2, Not)) + // ^^^^^^ adjustments: Borrow(Ref('?0, Not)) StructMut[0]; - // ^^^^^^^^^ adjustments: Borrow(Ref('?5, Not)) + // ^^^^^^^^^ adjustments: Borrow(Ref('?1, Not)) &mut StructMut[0]; - // ^^^^^^^^^ adjustments: Borrow(Ref('?8, Mut)) + // ^^^^^^^^^ adjustments: Borrow(Ref('?2, Mut)) }", ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index df9061d23bf5d..d79639b93727b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -589,6 +589,7 @@ fn main() { "attrs_shim", "attrs_shim", "return_type_impl_traits_shim", + "generic_predicates_ns_shim", "infer_shim", "function_signature_shim", "function_signature_with_source_map_shim", @@ -605,8 +606,6 @@ fn main() { "impl_signature_shim", "impl_signature_with_source_map_shim", "callable_item_signature_shim", - "adt_variance_shim", - "variances_of_shim", "trait_impls_in_deps_shim", "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", @@ -615,7 +614,6 @@ fn main() { "impl_trait_with_diagnostics_ns_shim", "impl_self_ty_with_diagnostics_ns_shim", "generic_predicates_ns_shim", - "generic_predicates_ns_shim", "value_ty_shim", "generic_predicates_shim", "lang_item", @@ -691,6 +689,7 @@ fn main() { "attrs_shim", "attrs_shim", "return_type_impl_traits_shim", + "generic_predicates_ns_shim", "infer_shim", "function_signature_with_source_map_shim", "expr_scopes_shim", @@ -706,7 +705,6 @@ fn main() { "impl_trait_with_diagnostics_ns_shim", "impl_self_ty_with_diagnostics_ns_shim", "generic_predicates_ns_shim", - "generic_predicates_ns_shim", "generic_predicates_shim", ] "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 5d088e40cdeda..6490554b22b7d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -202,7 +202,7 @@ fn expr_macro_def_expanded_in_various_places() { 100..119 'for _ ...!() {}': {unknown} 100..119 'for _ ...!() {}': &'? mut {unknown} 100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 100..119 'for _ ...!() {}': Option<{unknown}> + 100..119 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () @@ -296,7 +296,7 @@ fn expr_macro_rules_expanded_in_various_places() { 114..133 'for _ ...!() {}': {unknown} 114..133 'for _ ...!() {}': &'? mut {unknown} 114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 114..133 'for _ ...!() {}': Option<{unknown}> + 114..133 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index f09b3ef6bfd0f..d50daf0f0d5be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1876,9 +1876,9 @@ impl Foo { } fn test() { Foo.foo(); - //^^^ adjustments: Borrow(Ref('?1, Not)) + //^^^ adjustments: Borrow(Ref('?0, Not)) (&Foo).foo(); - // ^^^^ adjustments: Deref(None), Borrow(Ref('?3, Not)) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?2, Not)) } "#, ); @@ -1892,7 +1892,7 @@ fn receiver_adjustment_unsize_array() { fn test() { let a = [1, 2, 3]; a.len(); -} //^ adjustments: Borrow(Ref('?7, Not)), Pointer(Unsize) +} //^ adjustments: Borrow(Ref('?0, Not)), Pointer(Unsize) "#, ); } @@ -2105,7 +2105,7 @@ impl Foo { } fn test() { Box::new(Foo).foo(); - //^^^^^^^^^^^^^ adjustments: Deref(None), Borrow(Ref('?5, Not)) + //^^^^^^^^^^^^^ adjustments: Deref(None), Borrow(Ref('?0, Not)) } "#, ); @@ -2123,7 +2123,7 @@ impl Foo { use core::mem::ManuallyDrop; fn test() { ManuallyDrop::new(Foo).foo(); - //^^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('?6, Not)) + //^^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('?0, Not)) } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index 6a9135622deb6..baca7f2318e22 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -362,12 +362,12 @@ fn diverging_expression_3_break() { 140..141 'x': u32 149..175 '{ for ...; }; }': u32 151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 151..172 'for a ...eak; }': {unknown} + 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': ! - 151..172 'for a ...eak; }': {unknown} - 151..172 'for a ...eak; }': &'? mut {unknown} + 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter + 151..172 'for a ...eak; }': &'? mut <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 151..172 'for a ...eak; }': Option<{unknown}> + 151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item> 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () @@ -379,12 +379,12 @@ fn diverging_expression_3_break() { 226..227 'x': u32 235..253 '{ for ... {}; }': u32 237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 237..250 'for a in b {}': {unknown} + 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': ! - 237..250 'for a in b {}': {unknown} - 237..250 'for a in b {}': &'? mut {unknown} + 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter + 237..250 'for a in b {}': &'? mut <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 237..250 'for a in b {}': Option<{unknown}> + 237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item> 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () @@ -395,12 +395,12 @@ fn diverging_expression_3_break() { 304..305 'x': u32 313..340 '{ for ...; }; }': u32 315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 315..337 'for a ...urn; }': {unknown} + 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': ! - 315..337 'for a ...urn; }': {unknown} - 315..337 'for a ...urn; }': &'? mut {unknown} + 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter + 315..337 'for a ...urn; }': &'? mut <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 315..337 'for a ...urn; }': Option<{unknown}> + 315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item> 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs index 11d1a58e5367e..256ca7defb78a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs @@ -134,6 +134,9 @@ static ALIAS: AliasTy = { "#, ); + // FIXME(next-solver): This should emit type mismatch error but leaving it for now + // as we should fully migrate into next-solver without chalk-ir and TAIT should be + // reworked on r-a to handle `#[define_opaque(T)]` check_infer_with_mismatches( r#" trait Trait {} @@ -155,7 +158,6 @@ static ALIAS: i32 = { 191..193 '_a': impl Trait + ?Sized 205..211 'Struct': Struct 217..218 '5': i32 - 205..211: expected impl Trait + ?Sized, got Struct "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 4949d4016bf15..60a2641e1a20e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -48,12 +48,12 @@ fn infer_pattern() { 83..84 '1': i32 86..93 '"hello"': &'static str 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 101..151 'for (e... }': {unknown} + 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': ! - 101..151 'for (e... }': {unknown} - 101..151 'for (e... }': &'? mut {unknown} + 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter + 101..151 'for (e... }': &'? mut <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 101..151 'for (e... }': Option<({unknown}, {unknown})> + 101..151 'for (e... }': Option<<{unknown} as Iterator>::Item> 101..151 'for (e... }': () 101..151 'for (e... }': () 101..151 'for (e... }': () @@ -719,28 +719,28 @@ fn test() { 51..58 'loop {}': ! 56..58 '{}': () 72..171 '{ ... x); }': () - 78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32 + 78..81 'foo': fn foo<&'? (i32, &'static str), i32, impl FnOnce(&'? (i32, &'static str)) -> i32>(&'? (i32, &'static str), impl FnOnce(&'? (i32, &'static str)) -> i32) -> i32 78..105 'foo(&(...y)| x)': i32 82..91 '&(1, "a")': &'? (i32, &'static str) 83..91 '(1, "a")': (i32, &'static str) 84..85 '1': i32 87..90 '"a"': &'static str - 93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32 - 94..101 '&(x, y)': &'? (i32, &'? str) - 95..101 '(x, y)': (i32, &'? str) + 93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'static str)) -> i32 + 94..101 '&(x, y)': &'? (i32, &'static str) + 95..101 '(x, y)': (i32, &'static str) 96..97 'x': i32 - 99..100 'y': &'? str + 99..100 'y': &'static str 103..104 'x': i32 - 142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32 + 142..145 'foo': fn foo<&'? (i32, &'static str), &'? i32, impl FnOnce(&'? (i32, &'static str)) -> &'? i32>(&'? (i32, &'static str), impl FnOnce(&'? (i32, &'static str)) -> &'? i32) -> &'? i32 142..168 'foo(&(...y)| x)': &'? i32 146..155 '&(1, "a")': &'? (i32, &'static str) 147..155 '(1, "a")': (i32, &'static str) 148..149 '1': i32 151..154 '"a"': &'static str - 157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32 - 158..164 '(x, y)': (i32, &'? str) + 157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'static str)) -> &'? i32 + 158..164 '(x, y)': (i32, &'static str) 159..160 'x': &'? i32 - 162..163 'y': &'? &'? str + 162..163 'y': &'? &'static str 166..167 'x': &'? i32 "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 6a3f2286215f4..eacc4603ea1af 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -268,12 +268,12 @@ fn infer_std_crash_5() { expect![[r#" 26..322 '{ ... } }': () 32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 32..320 'for co... }': {unknown} + 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter 32..320 'for co... }': ! - 32..320 'for co... }': {unknown} - 32..320 'for co... }': &'? mut {unknown} + 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter + 32..320 'for co... }': &'? mut <{unknown} as IntoIterator>::IntoIter 32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 32..320 'for co... }': Option<{unknown}> + 32..320 'for co... }': Option<<{unknown} as Iterator>::Item> 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () @@ -628,7 +628,7 @@ fn issue_4053_diesel_where_clauses() { 65..69 'self': Self 267..271 'self': Self 466..470 'self': SelectStatement - 488..522 '{ ... }': () + 488..522 '{ ... }': as BoxedDsl>::Output 498..502 'self': SelectStatement 498..508 'self.order': O 498..515 'self.o...into()': dyn QueryFragment + '? @@ -1248,7 +1248,7 @@ fn test() { 16..66 'for _ ... }': {unknown} 16..66 'for _ ... }': &'? mut {unknown} 16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 16..66 'for _ ... }': Option<{unknown}> + 16..66 'for _ ... }': Option<<{unknown} as Iterator>::Item> 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index e4ee52f45eb75..97473bbabba04 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -20,7 +20,7 @@ impl<'a> IntoIterator for &'a Grid { "#, expect![[r#" 150..154 'self': &'a Grid - 174..181 '{ }': impl Iterator + 174..181 '{ }': impl Iterator "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index a995a45f6e752..e7357ed5aa78b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -1954,6 +1954,8 @@ fn closure_return_inferred() { ); } +// FIXME(next-solver): `&'? str` in 231..262 seems suspicious. +// Should revisit this once we fully migrated into next-solver without chalk-ir. #[test] fn coroutine_types_inferred() { check_infer( @@ -1998,7 +2000,7 @@ fn test() { 225..360 'match ... }': () 231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str> 231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str> - 231..262 'Pin::n...usize)': CoroutineState + 231..262 'Pin::n...usize)': CoroutineState 240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str 245..246 'g': |usize| yields i64 -> &'static str 255..261 '0usize': usize diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index a311e579744df..7a946f7ec7ced 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1,6 +1,8 @@ use cov_mark::check; use expect_test::expect; +use crate::tests::infer_with_mismatches; + use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; #[test] @@ -2460,7 +2462,7 @@ use core::ops::Index; type Key = ::Key; -pub trait UnificationStoreBase: Index> { +pub trait UnificationStoreBase: Index> { type Key; fn len(&self) -> usize; @@ -3634,8 +3636,7 @@ fn minimized() { #[test] fn no_builtin_binop_expectation_for_general_ty_var() { - // FIXME: Ideally type mismatch should be reported on `take_u32(42 - p)`. - check_types( + infer_with_mismatches( r#" //- minicore: add use core::ops::Add; @@ -3659,6 +3660,7 @@ fn minimized() { take_u32(42 + p); } "#, + true, ); } @@ -4188,6 +4190,8 @@ fn g(p:

::Pointer) { ); } +// FIXME(next-solver): Was `&'a T` but now getting error lifetime. +// This might be fixed once we migrate into next-solver fully without chalk-ir in lowering. #[test] fn gats_with_impl_trait() { // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot @@ -4211,21 +4215,21 @@ fn f(v: impl Trait) { } fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); - //^ &'a T + //^ &'? T let a = v.get::<()>(); //^ = &'a T> as Trait>::Assoc<()> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); - //^ &'a i32 + //^ &'? i32 let a = v.get::(); - //^ &'a i64 + //^ &'? i64 } fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { let a = v.get::(); - //^ &'a i32 + //^ &'? i32 let a = v.get::(); - //^ &'a i64 + //^ &'? i64 } "#, ); @@ -4255,8 +4259,8 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { 127..128 'v': &'? (dyn Trait = &'a i32> + '?) 164..195 '{ ...f(); }': () 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': {unknown} - 170..192 'v.get:...eref()': &'? {unknown} + 170..184 'v.get::()': = &'a i32> + '? as Trait>::Assoc + 170..192 'v.get:...eref()': {unknown} "#]], ); } @@ -4931,6 +4935,8 @@ fn main() { ); } +// FIXME(next-solver): Was `>::Error` but now getting error lifetime. +// This might be fixed once we migrate into next-solver fully without chalk-ir in lowering. #[test] fn new_solver_crash_1() { check_infer( @@ -4947,7 +4953,7 @@ where "#, expect![[r#" 84..86 'de': D - 135..138 '{ }': >::Error + 135..138 '{ }': >::Error "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 0c58e031c3a0f..a6377243ed984 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -21,9 +21,17 @@ use stdx::never; use triomphe::Arc; use crate::{ - db::HirDatabase, infer::unify::InferenceTable, next_solver::{ - infer::{DbInternerInferExt, InferCtxt}, mapping::{convert_canonical_args_for_result, ChalkToNextSolver}, util::mini_canonicalize, DbInterner, GenericArg, Predicate, SolverContext, Span - }, utils::UnevaluatedConstEvaluatorFolder, AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause + AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, + ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, + db::HirDatabase, + infer::unify::InferenceTable, + next_solver::{ + DbInterner, GenericArg, Predicate, SolverContext, Span, + infer::{DbInternerInferExt, InferCtxt}, + mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, + util::mini_canonicalize, + }, + utils::UnevaluatedConstEvaluatorFolder, }; /// A set of clauses that we assume to be true. E.g. if we are inside this function: @@ -282,30 +290,18 @@ pub fn next_trait_solve( } } -pub fn next_trait_solve_canonical<'db>( - db: &'db dyn HirDatabase, - krate: Crate, - block: Option, +pub fn next_trait_solve_canonical_in_ctxt<'db>( + infer_ctxt: &InferCtxt<'db>, goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>, ) -> NextTraitSolveResult { - // FIXME: should use analysis_in_body, but that needs GenericDefId::Block - let context = SolverContext( - DbInterner::new_with(db, Some(krate), block) - .infer_ctxt() - .build(TypingMode::non_body_analysis()), - ); + let context = SolverContext(infer_ctxt.clone()); tracing::info!(?goal); - let (goal, var_values) = - context.instantiate_canonical(&goal); + let (goal, var_values) = context.instantiate_canonical(&goal); tracing::info!(?var_values); - let res = context.evaluate_root_goal( - goal.clone(), - Span::dummy(), - None - ); + let res = context.evaluate_root_goal(goal, Span::dummy(), None); let vars = var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect(); @@ -318,13 +314,10 @@ pub fn next_trait_solve_canonical<'db>( match res { Err(_) => NextTraitSolveResult::NoSolution, Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( - convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args) + convert_canonical_args_for_result(infer_ctxt.interner, args), ), Ok((_, Certainty::Maybe(_), args)) => { - let subst = convert_canonical_args_for_result( - DbInterner::new_with(db, Some(krate), block), - args, - ); + let subst = convert_canonical_args_for_result(infer_ctxt.interner, args); NextTraitSolveResult::Uncertain(chalk_ir::Canonical { binders: subst.binders, value: subst.value.subst, diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 79a154a5d8e6e..c230bbad0bc45 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -14,7 +14,11 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::Name, }; -use hir_ty::{db::HirDatabase, method_resolution, next_solver::{mapping::ChalkToNextSolver, DbInterner}}; +use hir_ty::{ + db::HirDatabase, + method_resolution, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, +}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -271,7 +275,11 @@ fn resolve_impl_trait_item<'db>( // // FIXME: resolve type aliases (which are not yielded by iterate_path_candidates) _ = method_resolution::iterate_path_candidates( - &canonical.to_nextsolver(DbInterner::new_with(db, Some(environment.krate), environment.block)), + &canonical.to_nextsolver(DbInterner::new_with( + db, + Some(environment.krate), + environment.block, + )), db, environment, &traits_in_scope, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 6121c61ea3f49..445afa75f3f4f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -10,7 +10,8 @@ use crate::{ fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, pos) = position(ra_fixture); let config = TEST_CONFIG; - let (completion_context, _analysis) = CompletionContext::new(&db, pos, &config).unwrap(); + let (completion_context, _analysis) = + salsa::attach(&db, || CompletionContext::new(&db, pos, &config).unwrap()); let ty = completion_context .expected_type diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index ac54ac0950f39..8613581292f75 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -526,8 +526,7 @@ fn main() { fn run(_t: Rate<5>) { } fn main() { - run(f()) // FIXME: remove this error - //^^^ error: expected Rate<5>, found Rate<_> + run(f()) } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs index 46b633b8a3250..875b4d9b06cec 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs @@ -2,7 +2,10 @@ use expect_test::{Expect, expect}; use hir::{FilePosition, FileRange}; use ide_db::{ EditionedFileId, FxHashSet, - base_db::{SourceDatabase, salsa::Durability}, + base_db::{ + SourceDatabase, + salsa::{self, Durability}, + }, }; use test_utils::RangeOrOffset; use triomphe::Arc; @@ -116,7 +119,7 @@ fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { let rule: SsrRule = rule.parse().unwrap(); match_finder.add_rule(rule).unwrap(); } - let edits = match_finder.edits(); + let edits = salsa::attach(&db, || match_finder.edits()); if edits.is_empty() { panic!("No edits were made"); } @@ -155,8 +158,12 @@ fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { ) .unwrap(); match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - let matched_strings: Vec = - match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect(); + let matched_strings: Vec = salsa::attach(&db, || match_finder.matches()) + .flattened() + .matches + .iter() + .map(|m| m.matched_text()) + .collect(); if matched_strings != expected && !expected.is_empty() { print_match_debug_info(&match_finder, position.file_id, expected[0]); } diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index 11518d1fbf306..72436307d2cee 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -47,7 +47,8 @@ fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect let (analysis, position) = fixture::position(ra_fixture); let sema = &Semantics::new(&analysis.db); let (cursor_def, docs, range) = def_under_cursor(sema, &position); - let res = rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range)); + let res = + salsa::attach(sema.db, || rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range))); expect.assert_eq(&res) } From ce2f518b5393c48370f67725a4e15573b49f2c7d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 9 Sep 2025 21:57:19 +0300 Subject: [PATCH 178/251] Upgrade rustc crates and handle changes to canonicalization They have to do with diagnostics, we could probably not support them but we will also someday want good diagnostics. The code is mostly copied from rustc. --- src/tools/rust-analyzer/Cargo.lock | 45 +++---- src/tools/rust-analyzer/Cargo.toml | 16 +-- .../infer/canonical/canonicalizer.rs | 41 +++--- .../src/next_solver/infer/canonical/mod.rs | 59 ++++----- .../hir-ty/src/next_solver/infer/context.rs | 8 ++ .../hir-ty/src/next_solver/infer/mod.rs | 8 ++ .../next_solver/infer/snapshot/undo_log.rs | 4 +- .../src/next_solver/infer/type_variable.rs | 117 ++++++++++++++++++ .../hir-ty/src/next_solver/infer/unify_key.rs | 3 + .../crates/hir-ty/src/next_solver/mapping.rs | 42 +++---- .../crates/hir-ty/src/next_solver/solver.rs | 12 +- .../crates/hir-ty/src/next_solver/util.rs | 17 ++- 12 files changed, 256 insertions(+), 116 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 344e6d101fe35..b70b89ea543d8 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6789d94fb3e6e30d62f55e99a321ba63484a8bb3b4ead338687c9ddc282d28" +checksum = "8da95e732b424802b1f043ab4007c78a0fc515ab249587abbea4634bf5fdce9a" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1875,24 +1875,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaab80bda0f05e9842e3afb7779b0bad0a4b54e0f7ba6deb5705dcf86482811d" +checksum = "3838d9d7a3a5cdc511cfb6ad78740ce532f75a2366d3fc3b9853ea1b5c872779" [[package]] name = "ra-ap-rustc_hashes" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bd405e538102b5f699241794b2eefee39d5414c0e4bc72435e91430c51f905" +checksum = "bdc8995d268d3bb4ece910f575ea5a063d6003e193ec155d15703b65882d53fb" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521621e271aa03b8433dad5981838278d6cfd7d2d8c9f4eb6d427f1d671f90fc" +checksum = "ed0ccdf6e5627c6c3e54e571e52ce0bc8b94d5f0b94b7460269ca68a4706be69" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1900,9 +1900,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245e30f2e1fef258913cc548b36f575549c8af31cbc4649929d21deda96ceeb7" +checksum = "bd28f42362b5c9fb9b8766c3189df02a402b13363600c6885e11027889f03ee6" dependencies = [ "proc-macro2", "quote", @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82681f924500e888c860e60ed99e9bf702a219a69374f59116c4261525a2157" +checksum = "f1c31a82f091b910a27ee53a86a9af28a2df10c3484e2f1bbfe70633aa84dee9" dependencies = [ "memchr", "unicode-properties", @@ -1922,9 +1922,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ce51f2431fbdc7fabd2d957522b6e27f41f68ec2af74b52a6f4116352ce1a" +checksum = "f8cac6c2b5a8924209d4ca682cbc507252c58a664911e0ef463c112882ba6f72" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc85ef3fdb6c084bde84857d8948dc66b752129dc8417a8614ce490e99a143f" +checksum = "a085a1cf902dcca8abbc537faaef154bbccbbb51850f779ce5484ae3782b5d8f" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd81eccf33d9528905d4e5abaa254b3129a6405d6c5f123fed9b73a3d217f35" +checksum = "8ba32e3985367bc34856b41c7604133649d4a367eb5d7bdf50623025731459d8" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1958,10 +1958,11 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cb0da02853698d9c89e1d1c01657b9969752befd56365e8899d4310e52b373" +checksum = "9c9911d72f75d85d21fe88374d7bcec94f2200feffb7234108a24cc3da7c3591" dependencies = [ + "arrayvec", "bitflags 2.9.1", "derive-where", "ena", @@ -1977,9 +1978,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.126.0" +version = "0.128.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc93adeb52c483ede13bee6680466458218243ab479c04fb71bb53925a6e0ff" +checksum = "22f539b87991683ce17cc52e62600fdf2b4a8af43952db30387edc1a576d3b43" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index f325027ee5871..c5ffad544a6b3 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,14 +89,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.126", default-features = false } -ra-ap-rustc_parse_format = { version = "0.126", default-features = false } -ra-ap-rustc_index = { version = "0.126", default-features = false } -ra-ap-rustc_abi = { version = "0.126", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.126", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.126", default-features = false } -ra-ap-rustc_type_ir = { version = "0.126", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.126", default-features = false } +ra-ap-rustc_lexer = { version = "0.128", default-features = false } +ra-ap-rustc_parse_format = { version = "0.128", default-features = false } +ra-ap-rustc_index = { version = "0.128", default-features = false } +ra-ap-rustc_abi = { version = "0.128", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.128", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.128", default-features = false } +ra-ap-rustc_type_ir = { version = "0.128", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.128", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index 5d11525cd199f..ffb9c076fa061 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -10,9 +10,8 @@ use rustc_index::Idx; use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar}; use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _}; use rustc_type_ir::{ - BoundVar, CanonicalQueryInput, CanonicalTyVarKind, DebruijnIndex, Flags, InferConst, - RegionKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, - UniverseIndex, + BoundVar, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind, TyVid, TypeFlags, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, }; use smallvec::SmallVec; use tracing::debug; @@ -316,6 +315,13 @@ struct Canonicalizer<'cx, 'db> { // Note that indices is only used once `var_values` is big enough to be // heap-allocated. indices: FxHashMap, BoundVar>, + /// Maps each `sub_unification_table_root_var` to the index of the first + /// variable which used it. + /// + /// This means in case two type variables have the same sub relations root, + /// we set the `sub_root` of the second variable to the position of the first. + /// Otherwise the `sub_root` of each type variable is just its own position. + sub_root_lookup_table: FxHashMap, canonicalize_mode: &'cx dyn CanonicalizeMode, needs_canonical_flags: TypeFlags, @@ -384,10 +390,9 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { // FIXME: perf problem described in #55921. ui = UniverseIndex::ROOT; } - self.canonicalize_ty_var( - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), - t, - ) + + let sub_root = self.get_or_insert_sub_root(vid); + self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t) } } } @@ -395,17 +400,17 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { TyKind::Infer(IntVar(vid)) => { let nt = self.infcx.opportunistic_resolve_int_var(vid); if nt != t { - self.fold_ty(nt) + return self.fold_ty(nt); } else { - self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t) + self.canonicalize_ty_var(CanonicalVarKind::Int, t) } } TyKind::Infer(FloatVar(vid)) => { let nt = self.infcx.opportunistic_resolve_float_var(vid); if nt != t { - self.fold_ty(nt) + return self.fold_ty(nt); } else { - self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t) + self.canonicalize_ty_var(CanonicalVarKind::Float, t) } } @@ -579,6 +584,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { variables: SmallVec::from_slice(base.variables.as_slice()), query_state, indices: FxHashMap::default(), + sub_root_lookup_table: Default::default(), binder_index: DebruijnIndex::ZERO, }; if canonicalizer.query_state.var_values.spilled() { @@ -673,6 +679,13 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { } } + fn get_or_insert_sub_root(&mut self, vid: TyVid) -> BoundVar { + let root_vid = self.infcx.sub_unification_table_root_var(vid); + let idx = + *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len()); + BoundVar::from(idx) + } + /// Replaces the universe indexes used in `var_values` with their index in /// `query_state.universe_map`. This minimizes the maximum universe used in /// the canonicalized value. @@ -692,9 +705,9 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { self.variables .iter() .map(|v| match *v { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => *v, - CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) + CanonicalVarKind::Int | CanonicalVarKind::Float => *v, + CanonicalVarKind::Ty { ui, sub_root } => { + CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root } } CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]), CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs index ec41111ed8153..8db4320acc9c0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -32,9 +32,10 @@ use crate::next_solver::{ }; use instantiate::CanonicalExt; use rustc_index::IndexVec; +use rustc_type_ir::inherent::IntoKind; use rustc_type_ir::{ - AliasRelationDirection, AliasTyKind, CanonicalTyVarKind, CanonicalVarKind, InferTy, - TypeFoldable, UniverseIndex, Upcast, Variance, + AliasRelationDirection, AliasTyKind, CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, + Upcast, Variance, inherent::{SliceLike, Ty as _}, relate::{ Relate, TypeRelation, VarianceDiagInfo, @@ -78,27 +79,15 @@ impl<'db> InferCtxt<'db> { .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe())) .collect(); - let canonical_inference_vars = - self.instantiate_canonical_vars(canonical.variables, |ui| universes[ui]); - let result = canonical.instantiate(self.interner, &canonical_inference_vars); - (result, canonical_inference_vars) - } - - /// Given the "infos" about the canonical variables from some - /// canonical, creates fresh variables with the same - /// characteristics (see `instantiate_canonical_var` for - /// details). You can then use `instantiate` to instantiate the - /// canonical variable with these inference variables. - fn instantiate_canonical_vars( - &self, - variables: CanonicalVars<'db>, - universe_map: impl Fn(UniverseIndex) -> UniverseIndex, - ) -> CanonicalVarValues<'db> { - CanonicalVarValues { - var_values: self.interner.mk_args_from_iter( - variables.iter().map(|info| self.instantiate_canonical_var(info, &universe_map)), - ), - } + let var_values = CanonicalVarValues::instantiate( + self.interner, + canonical.variables, + |var_values, info| { + self.instantiate_canonical_var(info, &var_values, |ui| universes[ui]) + }, + ); + let result = canonical.instantiate(self.interner, &var_values); + (result, var_values) } /// Given the "info" about a canonical variable, creates a fresh @@ -112,21 +101,27 @@ impl<'db> InferCtxt<'db> { pub fn instantiate_canonical_var( &self, cv_info: CanonicalVarKind>, + previous_var_values: &[GenericArg<'db>], universe_map: impl Fn(UniverseIndex) -> UniverseIndex, ) -> GenericArg<'db> { match cv_info { - CanonicalVarKind::Ty(ty_kind) => { - let ty = match ty_kind { - CanonicalTyVarKind::General(ui) => { - self.next_ty_var_in_universe(universe_map(ui)) + CanonicalVarKind::Ty { ui, sub_root } => { + let vid = self.next_ty_var_id_in_universe(universe_map(ui)); + // If this inference variable is related to an earlier variable + // via subtyping, we need to add that info to the inference context. + if let Some(prev) = previous_var_values.get(sub_root.as_usize()) { + if let TyKind::Infer(InferTy::TyVar(sub_root)) = prev.expect_ty().kind() { + self.sub_unify_ty_vids_raw(vid, sub_root); + } else { + unreachable!() } + } + Ty::new_var(self.interner, vid).into() + } - CanonicalTyVarKind::Int => self.next_int_var(), + CanonicalVarKind::Int => self.next_int_var().into(), - CanonicalTyVarKind::Float => self.next_float_var(), - }; - ty.into() - } + CanonicalVarKind::Float => self.next_float_var().into(), CanonicalVarKind::PlaceholderTy(PlaceholderTy { universe, bound }) => { let universe_mapped = universe_map(universe); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs index 93fd6eeab34e4..45ce7e6f6cc75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs @@ -313,4 +313,12 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { fn reset_opaque_types(&self) { let _ = self.take_opaque_types(); } + + fn sub_unification_table_root_var(&self, var: rustc_type_ir::TyVid) -> rustc_type_ir::TyVid { + self.sub_unification_table_root_var(var) + } + + fn sub_unify_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + self.sub_unify_ty_vids_raw(a, b); + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 2630f2a8cc4e5..ce6c941287325 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -1019,6 +1019,14 @@ impl<'db> InferCtxt<'db> { } } } + + fn sub_unification_table_root_var(&self, var: rustc_type_ir::TyVid) -> rustc_type_ir::TyVid { + self.inner.borrow_mut().type_variables().sub_unification_table_root_var(var) + } + + fn sub_unify_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + self.inner.borrow_mut().type_variables().sub_unify(a, b); + } } /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs index 0fa6421f517de..28ae56f4ee70a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs @@ -25,7 +25,7 @@ pub struct Snapshot { pub(crate) enum UndoLog<'db> { DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'db>, Option>), - TypeVariables(sv::UndoLog>>), + TypeVariables(type_variable::UndoLog<'db>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), @@ -51,6 +51,8 @@ impl_from! { RegionConstraintCollector(region_constraints::UndoLog<'db>), TypeVariables(sv::UndoLog>>), + TypeVariables(sv::UndoLog>), + TypeVariables(type_variable::UndoLog<'db>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs index 5217308af473c..b640039af625b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs @@ -17,12 +17,48 @@ use crate::next_solver::SolverDefId; use crate::next_solver::Ty; use crate::next_solver::infer::InferCtxtUndoLogs; +/// Represents a single undo-able action that affects a type inference variable. +#[derive(Clone)] +pub(crate) enum UndoLog<'tcx> { + EqRelation(sv::UndoLog>>), + SubRelation(sv::UndoLog>), +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'db> From>>> for UndoLog<'db> { + fn from(l: sv::UndoLog>>) -> Self { + UndoLog::EqRelation(l) + } +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'db> From>> for UndoLog<'db> { + fn from(l: sv::UndoLog>) -> Self { + UndoLog::SubRelation(l) + } +} + impl<'db> Rollback>>> for TypeVariableStorage<'db> { fn reverse(&mut self, undo: sv::UndoLog>>) { self.eq_relations.reverse(undo) } } +impl<'tcx> Rollback>> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: sv::UndoLog>) { + self.sub_unification_table.reverse(undo) + } +} + +impl<'tcx> Rollback> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), + UndoLog::SubRelation(undo) => self.sub_unification_table.reverse(undo), + } + } +} + #[derive(Clone, Default)] pub(crate) struct TypeVariableStorage<'db> { /// The origins of each type variable. @@ -31,6 +67,25 @@ pub(crate) struct TypeVariableStorage<'db> { /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. eq_relations: ut::UnificationTableStorage>, + /// Only used by `-Znext-solver` and for diagnostics. Tracks whether + /// type variables are related via subtyping at all, ignoring which of + /// the two is the subtype. + /// + /// When reporting ambiguity errors, we sometimes want to + /// treat all inference vars which are subtypes of each + /// others as if they are equal. For this case we compute + /// the transitive closure of our subtype obligations here. + /// + /// E.g. when encountering ambiguity errors, we want to suggest + /// specifying some method argument or to add a type annotation + /// to a local variable. Because subtyping cannot change the + /// shape of a type, it's fine if the cause of the ambiguity error + /// is only related to the suggested variable via subtyping. + /// + /// Even for something like `let x = returns_arg(); x.method();` the + /// type of `x` is only a supertype of the argument of `returns_arg`. We + /// still want to suggest specifying the type of the argument. + sub_unification_table: ut::UnificationTableStorage, } pub(crate) struct TypeVariableTable<'a, 'db> { @@ -112,6 +167,17 @@ impl<'db> TypeVariableTable<'_, 'db> { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); self.eq_relations().union(a, b); + self.sub_unification_table().union(a, b); + } + + /// Records that `a` and `b` are related via subtyping. We don't track + /// which of the two is the subtype. + /// + /// Precondition: neither `a` nor `b` are known. + pub(crate) fn sub_unify(&mut self, a: TyVid, b: TyVid) { + debug_assert!(self.probe(a).is_unknown()); + debug_assert!(self.probe(b).is_unknown()); + self.sub_unification_table().union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -141,6 +207,10 @@ impl<'db> TypeVariableTable<'_, 'db> { /// for improving error messages. pub(crate) fn new_var(&mut self, universe: UniverseIndex, origin: TypeVariableOrigin) -> TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); + + let sub_key = self.sub_unification_table().new_key(()); + debug_assert_eq!(eq_key.vid, sub_key.vid); + let index = self.storage.values.push(TypeVariableData { origin }); debug_assert_eq!(eq_key.vid, index); @@ -163,6 +233,18 @@ impl<'db> TypeVariableTable<'_, 'db> { self.eq_relations().find(vid).vid } + /// Returns the "root" variable of `vid` in the `sub_unification_table` + /// equivalence table. All type variables that have been are related via + /// equality or subtyping will yield the same root variable (per the + /// union-find algorithm), so `sub_unification_table_root_var(a) + /// == sub_unification_table_root_var(b)` implies that: + /// ```text + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + /// ``` + pub(crate) fn sub_unification_table_root_var(&mut self, vid: TyVid) -> TyVid { + self.sub_unification_table().find(vid).vid + } + /// Retrieves the type to which `vid` has been instantiated, if /// any. pub(crate) fn probe(&mut self, vid: TyVid) -> TypeVariableValue<'db> { @@ -180,6 +262,11 @@ impl<'db> TypeVariableTable<'_, 'db> { self.storage.eq_relations.with_log(self.undo_log) } + #[inline] + fn sub_unification_table(&mut self) -> super::UnificationTable<'_, 'db, TyVidSubKey> { + self.storage.sub_unification_table.with_log(self.undo_log) + } + /// Returns indices of all variables that are not yet /// instantiated. pub(crate) fn unresolved_variables(&mut self) -> Vec { @@ -228,6 +315,36 @@ impl<'db> ut::UnifyKey for TyVidEqKey<'db> { fn tag() -> &'static str { "TyVidEqKey" } + fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { + if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) struct TyVidSubKey { + vid: TyVid, +} + +impl From for TyVidSubKey { + #[inline] // make this function eligible for inlining - it is quite hot. + fn from(vid: TyVid) -> Self { + TyVidSubKey { vid } + } +} + +impl ut::UnifyKey for TyVidSubKey { + type Value = (); + #[inline] + fn index(&self) -> u32 { + self.vid.as_u32() + } + #[inline] + fn from_index(i: u32) -> TyVidSubKey { + TyVidSubKey { vid: TyVid::from_u32(i) } + } + fn tag() -> &'static str { + "TyVidSubKey" + } } impl<'db> ut::UnifyValue for TypeVariableValue<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs index b9afb45ba89da..dc913b262a7c2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs @@ -139,6 +139,9 @@ impl<'db> UnifyKey for ConstVidKey<'db> { fn tag() -> &'static str { "ConstVidKey" } + fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { + if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } + } } impl<'db> UnifyValue for ConstVariableValue<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index f66b8dace30a6..11bc6e6abe94b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -734,15 +734,13 @@ impl<'db, T: HasInterner + ChalkToNextSolver<'db, U>, U> interner, self.binders.iter(Interner).map(|k| match &k.kind { chalk_ir::VariableKind::Ty(ty_variable_kind) => match ty_variable_kind { - TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty( - rustc_type_ir::CanonicalTyVarKind::General(UniverseIndex::ROOT), - ), - TyVariableKind::Integer => { - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) - } - TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Ty( - rustc_type_ir::CanonicalTyVarKind::Float, - ), + // FIXME(next-solver): the info is incorrect, but we have no way to store the information in Chalk. + TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty { + ui: UniverseIndex::ROOT, + sub_root: BoundVar::from_u32(0), + }, + TyVariableKind::Integer => rustc_type_ir::CanonicalVarKind::Int, + TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Float, }, chalk_ir::VariableKind::Lifetime => { rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ROOT) @@ -767,24 +765,20 @@ impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner> let binders = chalk_ir::CanonicalVarKinds::from_iter( Interner, self.variables.iter().map(|v| match v { - rustc_type_ir::CanonicalVarKind::Ty( - rustc_type_ir::CanonicalTyVarKind::General(ui), - ) => chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex { counter: ui.as_usize() }, - ), - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) => { + rustc_type_ir::CanonicalVarKind::Ty { ui, sub_root: _ } => { chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Integer), - chalk_ir::UniverseIndex::root(), - ) - } - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Float) => { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Float), - chalk_ir::UniverseIndex::root(), + chalk_ir::VariableKind::Ty(TyVariableKind::General), + chalk_ir::UniverseIndex { counter: ui.as_usize() }, ) } + rustc_type_ir::CanonicalVarKind::Int => chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Integer), + chalk_ir::UniverseIndex::root(), + ), + rustc_type_ir::CanonicalVarKind::Float => chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Float), + chalk_ir::UniverseIndex::root(), + ), rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new( chalk_ir::VariableKind::Lifetime, chalk_ir::UniverseIndex { counter: ui.as_usize() }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 385149d78432e..dc5073305c8ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -9,6 +9,7 @@ use rustc_type_ir::{ solve::{Certainty, NoSolution}, }; +use crate::next_solver::CanonicalVarKind; use crate::next_solver::mapping::NextSolverToChalk; use crate::{ TraitRefExt, @@ -117,13 +118,14 @@ impl<'db> SolverDelegate for SolverContext<'db> { canonical.instantiate(self.cx(), &values) } - fn instantiate_canonical_var_with_infer( + fn instantiate_canonical_var( &self, - cv_info: rustc_type_ir::CanonicalVarKind, - _span: ::Span, + kind: CanonicalVarKind<'db>, + span: ::Span, + var_values: &[GenericArg<'db>], universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex, - ) -> ::GenericArg { - self.0.instantiate_canonical_var(cv_info, universe_map) + ) -> GenericArg<'db> { + self.0.instantiate_canonical_var(kind, var_values, universe_map) } fn add_item_bounds_for_hidden_type( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index 50b96a160ed10..97d3ea72c93cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -532,17 +532,14 @@ pub(crate) fn mini_canonicalize<'db, T: TypeFoldable>>( max_universe: UniverseIndex::from_u32(1), variables: CanonicalVars::new_from_iter( context.cx(), - vars.iter().map(|(k, v)| match (*k).kind() { + vars.iter().enumerate().map(|(idx, (k, v))| match (*k).kind() { GenericArgKind::Type(ty) => match ty.kind() { - TyKind::Int(..) | TyKind::Uint(..) => { - rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) - } - TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Ty( - rustc_type_ir::CanonicalTyVarKind::Float, - ), - _ => rustc_type_ir::CanonicalVarKind::Ty( - rustc_type_ir::CanonicalTyVarKind::General(UniverseIndex::ZERO), - ), + TyKind::Int(..) | TyKind::Uint(..) => rustc_type_ir::CanonicalVarKind::Int, + TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Float, + _ => rustc_type_ir::CanonicalVarKind::Ty { + ui: UniverseIndex::ZERO, + sub_root: BoundVar::from_usize(idx), + }, }, GenericArgKind::Lifetime(_) => { rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO) From 8407376006546c484bcd72d2743f0e4e1f66ac94 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 9 Sep 2025 22:32:07 +0300 Subject: [PATCH 179/251] Adopt even more custom types in the new solver A lot of simplification and fun. --- .../crates/hir-def/src/lang_item.rs | 13 ++ .../crates/hir-ty/src/display.rs | 43 ++--- .../rust-analyzer/crates/hir-ty/src/layout.rs | 12 +- .../crates/hir-ty/src/method_resolution.rs | 5 +- .../crates/hir-ty/src/mir/eval.rs | 61 +++---- .../crates/hir-ty/src/next_solver/def_id.rs | 63 ++++++- .../infer/canonical/canonicalizer.rs | 4 +- .../src/next_solver/infer/canonical/mod.rs | 4 +- .../crates/hir-ty/src/next_solver/interner.rs | 158 +++++++++--------- .../crates/hir-ty/src/next_solver/mapping.rs | 46 ++--- .../crates/hir-ty/src/next_solver/solver.rs | 12 +- .../crates/hir-ty/src/next_solver/ty.rs | 21 ++- 12 files changed, 220 insertions(+), 222 deletions(-) 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 600f206770016..df0705bf90cbc 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 @@ -84,6 +84,15 @@ impl LangItemTarget { _ => None, } } + + pub fn as_adt(self) -> Option { + match self { + LangItemTarget::Union(it) => Some(it.into()), + LangItemTarget::EnumId(it) => Some(it.into()), + LangItemTarget::Struct(it) => Some(it.into()), + _ => None, + } + } } /// Salsa query. This will look for lang items in a specific crate. @@ -289,6 +298,10 @@ impl LangItem { lang_item(db, start_crate, self).and_then(|t| t.as_trait()) } + pub fn resolve_adt(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_adt()) + } + pub fn resolve_enum(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { lang_item(db, start_crate, self).and_then(|t| t.as_enum()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index fcb79e9ffb579..ea8bdf8bcbae4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -59,7 +59,7 @@ use crate::{ lt_from_placeholder_idx, mir::pad16, next_solver::{ - BoundExistentialPredicate, Ctor, DbInterner, GenericArgs, SolverDefId, + BoundExistentialPredicate, DbInterner, GenericArgs, SolverDefId, mapping::{ ChalkToNextSolver, convert_args_for_result, convert_const_for_result, convert_region_for_result, convert_ty_for_result, @@ -911,14 +911,13 @@ fn render_const_scalar_inner( f.write_str("&")?; render_const_scalar_ns(f, bytes, memory_map, t) } - TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id() { - SolverDefId::AdtId(hir_def::AdtId::StructId(s)) => { + TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id().0 { + hir_def::AdtId::StructId(s) => { let data = f.db.struct_signature(s); write!(f, "&{}", data.name.display(f.db, f.edition()))?; Ok(()) } - SolverDefId::AdtId(_) => f.write_str(""), - _ => unreachable!(), + _ => f.write_str(""), }, _ => { let addr = usize::from_le_bytes(match b.try_into() { @@ -966,10 +965,7 @@ fn render_const_scalar_inner( f.write_str(")") } TyKind::Adt(def, args) => { - let def = match def.def_id() { - SolverDefId::AdtId(def) => def, - _ => unreachable!(), - }; + let def = def.def_id().0; let Ok(layout) = f.db.layout_of_adt(def, args, trait_env.clone()) else { return f.write_str(""); }; @@ -1300,12 +1296,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { sig.hir_fmt(f)?; } TyKind::FnDef(def, args) => { - let def = match def { - SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), - SolverDefId::Ctor(Ctor::Enum(e)) => CallableDefId::EnumVariantId(e), - SolverDefId::Ctor(Ctor::Struct(s)) => CallableDefId::StructId(s), - _ => unreachable!(), - }; + let def = def.0; let sig = db .callable_item_signature(def) .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); @@ -1406,10 +1397,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } TyKind::Adt(def, parameters) => { - let def_id = match def.def_id() { - SolverDefId::AdtId(id) => id, - _ => unreachable!(), - }; + let def_id = def.def_id().0; f.start_location_link(def_id.into()); match f.display_kind { DisplayKind::Diagnostics | DisplayKind::Test => { @@ -1448,7 +1436,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { hir_fmt_generics( f, convert_args_for_result(interner, parameters.as_slice()).as_slice(Interner), - def.def_id().try_into().ok(), + Some(def.def_id().0.into()), None, )?; } @@ -1466,13 +1454,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { projection_ty.hir_fmt(f)?; } - TyKind::Foreign(type_alias) => { - let alias = match type_alias { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let type_alias = db.type_alias_signature(alias); - f.start_location_link(alias.into()); + TyKind::Foreign(alias) => { + let type_alias = db.type_alias_signature(alias.0); + f.start_location_link(alias.0.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); } @@ -1549,10 +1533,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } TyKind::Closure(id, substs) => { - let id = match id { - SolverDefId::InternedClosureId(id) => id, - _ => unreachable!(), - }; + let id = id.0; let substs = convert_args_for_result(interner, substs.as_slice()); if f.display_kind.is_source_code() { if !f.display_kind.allows_opaque() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index f8abb3b7f6fef..2020a8b34b4f9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -25,7 +25,7 @@ use crate::{ consteval_nextsolver::try_const_usize, db::HirDatabase, next_solver::{ - DbInterner, GenericArgs, ParamEnv, SolverDefId, Ty, TyKind, TypingMode, + DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, mapping::{ChalkToNextSolver, convert_args_for_result}, project::solve_normalize::deeply_normalize, @@ -323,14 +323,10 @@ pub fn layout_of_ty_query<'db>( ptr.valid_range_mut().start = 1; Layout::scalar(dl, ptr) } - TyKind::Closure(c, args) => { - let id = match c { - SolverDefId::InternedClosureId(id) => id, - _ => unreachable!(), - }; - let def = db.lookup_intern_closure(id); + TyKind::Closure(id, args) => { + let def = db.lookup_intern_closure(id.0); let infer = db.infer(def.0); - let (captures, _) = infer.closure_info(&id.into()); + let (captures, _) = infer.closure_info(&id.0.into()); let fields = captures .iter() .map(|it| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index fa80567b1ecc0..3f966694d504f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -161,10 +161,7 @@ impl TyFingerprint { rustc_ast_ir::Mutability::Mut => TyFingerprint::RawPtr(Mutability::Mut), rustc_ast_ir::Mutability::Not => TyFingerprint::RawPtr(Mutability::Not), }, - TyKind::Foreign(def) => { - let SolverDefId::TypeAliasId(def) = def else { unreachable!() }; - TyFingerprint::ForeignType(crate::to_foreign_def_id(def)) - } + TyKind::Foreign(def) => TyFingerprint::ForeignType(crate::to_foreign_def_id(def.0)), TyKind::Dynamic(bounds, _, _) => { let trait_ref = bounds .as_slice() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index c60ace85be124..ca7467d3855fa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -42,7 +42,7 @@ use crate::{ layout::{Layout, LayoutError, RustcEnumVariantIdx}, method_resolution::{is_dyn_method, lookup_impl_const}, next_solver::{ - Ctor, DbInterner, SolverDefId, + DbInterner, mapping::{ChalkToNextSolver, convert_args_for_result, convert_ty_for_result}, }, static_lifetime, @@ -2366,8 +2366,8 @@ impl<'db> Evaluator<'db> { let new_id = self.vtable_map.id(ty); self.write_memory(addr, &new_id.to_le_bytes())?; } - TyKind::Adt(id, args) => match id.def_id() { - SolverDefId::AdtId(AdtId::StructId(s)) => { + TyKind::Adt(id, args) => match id.def_id().0 { + AdtId::StructId(s) => { for (i, (_, ty)) in self.db.field_types_ns(s.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let ty = ty.instantiate(interner, args); @@ -2380,8 +2380,8 @@ impl<'db> Evaluator<'db> { )?; } } - SolverDefId::AdtId(AdtId::UnionId(_)) => (), - SolverDefId::AdtId(AdtId::EnumId(e)) => { + AdtId::UnionId(_) => (), + AdtId::EnumId(e) => { if let Some((ev, layout)) = detect_variant_from_bytes( &layout, self.db, @@ -2402,7 +2402,6 @@ impl<'db> Evaluator<'db> { } } } - _ => unreachable!(), }, TyKind::Tuple(tys) => { for (id, ty) in tys.iter().enumerate() { @@ -2472,38 +2471,24 @@ impl<'db> Evaluator<'db> { let interner = DbInterner::new_with(self.db, None, None); use rustc_type_ir::TyKind; match next_ty.kind() { - TyKind::FnDef(def, generic_args) => { - let def = match def { - SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), - SolverDefId::Ctor(Ctor::Struct(s)) => CallableDefId::StructId(s), - SolverDefId::Ctor(Ctor::Enum(e)) => CallableDefId::EnumVariantId(e), - _ => unreachable!(), - }; - self.exec_fn_def( - def, - &convert_args_for_result(interner, generic_args.as_slice()), - destination, - args, - locals, - target_bb, - span, - ) - } - TyKind::Closure(id, generic_args) => { - let id = match id { - SolverDefId::InternedClosureId(id) => id, - _ => unreachable!(), - }; - self.exec_closure( - id.into(), - bytes.slice(0..0), - &convert_args_for_result(interner, generic_args.as_slice()), - destination, - args, - locals, - span, - ) - } + TyKind::FnDef(def, generic_args) => self.exec_fn_def( + def.0, + &convert_args_for_result(interner, generic_args.as_slice()), + destination, + args, + locals, + target_bb, + span, + ), + TyKind::Closure(id, generic_args) => self.exec_closure( + id.0.into(), + bytes.slice(0..0), + &convert_args_for_result(interner, generic_args.as_slice()), + destination, + args, + locals, + span, + ), _ => Err(MirEvalError::InternalError("function pointer to non function".into())), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index 8bbc6e3370399..a9c572d3f34ee 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -1,8 +1,8 @@ //! Definition of `SolverDefId` use hir_def::{ - AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, StaticId, StructId, - TraitId, TypeAliasId, UnionId, + AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, + StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -42,7 +42,8 @@ impl_from!( TypeAliasId, InternedClosureId, InternedCoroutineId, - InternedOpaqueTyId + InternedOpaqueTyId, + Ctor for SolverDefId ); @@ -145,3 +146,59 @@ macro_rules! declare_id_wrapper { } declare_id_wrapper!(TraitIdWrapper, TraitId); +declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId); +declare_id_wrapper!(ClosureIdWrapper, InternedClosureId); +declare_id_wrapper!(CoroutineIdWrapper, InternedCoroutineId); +declare_id_wrapper!(AdtIdWrapper, AdtId); +declare_id_wrapper!(ImplIdWrapper, ImplId); + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct CallableIdWrapper(pub CallableDefId); + +impl std::fmt::Debug for CallableIdWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&self.0, f) + } +} +impl From for CallableDefId { + #[inline] + fn from(value: CallableIdWrapper) -> CallableDefId { + value.0 + } +} +impl From for CallableIdWrapper { + #[inline] + fn from(value: CallableDefId) -> CallableIdWrapper { + Self(value) + } +} +impl From for SolverDefId { + #[inline] + fn from(value: CallableIdWrapper) -> SolverDefId { + match value.0 { + CallableDefId::FunctionId(it) => it.into(), + CallableDefId::StructId(it) => Ctor::Struct(it).into(), + CallableDefId::EnumVariantId(it) => Ctor::Enum(it).into(), + } + } +} +impl TryFrom for CallableIdWrapper { + type Error = (); + #[inline] + fn try_from(value: SolverDefId) -> Result { + match value { + SolverDefId::FunctionId(it) => Ok(Self(it.into())), + SolverDefId::Ctor(Ctor::Struct(it)) => Ok(Self(it.into())), + SolverDefId::Ctor(Ctor::Enum(it)) => Ok(Self(it.into())), + _ => Err(()), + } + } +} +impl<'db> inherent::DefId> for CallableIdWrapper { + fn as_local(self) -> Option { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index ffb9c076fa061..beaac11a2de41 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -400,7 +400,7 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { TyKind::Infer(IntVar(vid)) => { let nt = self.infcx.opportunistic_resolve_int_var(vid); if nt != t { - return self.fold_ty(nt); + self.fold_ty(nt) } else { self.canonicalize_ty_var(CanonicalVarKind::Int, t) } @@ -408,7 +408,7 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { TyKind::Infer(FloatVar(vid)) => { let nt = self.infcx.opportunistic_resolve_float_var(vid); if nt != t { - return self.fold_ty(nt); + self.fold_ty(nt) } else { self.canonicalize_ty_var(CanonicalVarKind::Float, t) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs index 8db4320acc9c0..d0669f5c3bcc5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -82,9 +82,7 @@ impl<'db> InferCtxt<'db> { let var_values = CanonicalVarValues::instantiate( self.interner, canonical.variables, - |var_values, info| { - self.instantiate_canonical_var(info, &var_values, |ui| universes[ui]) - }, + |var_values, info| self.instantiate_canonical_var(info, var_values, |ui| universes[ui]), ); let result = canonical.instantiate(self.interner, &var_values); (result, var_values) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 5709beaefc292..0f512fdaf8687 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -19,7 +19,7 @@ use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::{ AdtDef as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike as _, Span as _, }; -use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, @@ -47,8 +47,9 @@ use crate::method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}; use crate::next_solver::infer::InferCtxt; use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; use crate::next_solver::{ - BoundConst, CanonicalVarKind, FxIndexMap, InternedWrapperNoDebug, RegionAssumptions, - SolverContext, SolverDefIds, TraitIdWrapper, + AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, + CoroutineIdWrapper, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, RegionAssumptions, + SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, }; use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase}; @@ -609,8 +610,8 @@ impl AdtDef { } impl<'db> inherent::AdtDef> for AdtDef { - fn def_id(self) -> as rustc_type_ir::Interner>::DefId { - SolverDefId::AdtId(self.inner().id) + fn def_id(self) -> AdtIdWrapper { + self.inner().id.into() } fn is_struct(self) -> bool { @@ -889,6 +890,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { type LocalDefId = SolverDefId; type LocalDefIds = SolverDefIds; type TraitId = TraitIdWrapper; + type ForeignId = TypeAliasIdWrapper; + type FunctionId = CallableIdWrapper; + type ClosureId = ClosureIdWrapper; + type CoroutineClosureId = CoroutineIdWrapper; + type CoroutineId = CoroutineIdWrapper; + type AdtId = AdtIdWrapper; + type ImplId = ImplIdWrapper; type Span = Span; type GenericArgs = GenericArgs<'db>; @@ -1103,12 +1111,8 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self.db().ty_ns(def_id) } - fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef { - let def_id = match adt_def_id { - SolverDefId::AdtId(adt_id) => adt_id, - _ => panic!("Invalid DefId passed to adt_def"), - }; - AdtDef::new(def_id, self) + fn adt_def(self, def_id: Self::AdtId) -> Self::AdtDef { + AdtDef::new(def_id.0, self) } fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> AliasTyKind { @@ -1219,24 +1223,16 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn fn_sig( self, - def_id: Self::DefId, + def_id: Self::FunctionId, ) -> EarlyBinder>> { - let id = match def_id { - SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), - SolverDefId::Ctor(ctor) => match ctor { - super::Ctor::Struct(struct_id) => CallableDefId::StructId(struct_id), - super::Ctor::Enum(enum_variant_id) => CallableDefId::EnumVariantId(enum_variant_id), - }, - def => unreachable!("{:?}", def), - }; - self.db().callable_item_signature_ns(id) + self.db().callable_item_signature_ns(def_id.0) } - fn coroutine_movability(self, def_id: Self::DefId) -> rustc_ast_ir::Movability { + fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability { unimplemented!() } - fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId { + fn coroutine_for_closure(self, def_id: Self::CoroutineId) -> Self::CoroutineId { unimplemented!() } @@ -1361,13 +1357,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn impl_super_outlives( self, - impl_def_id: Self::DefId, + impl_id: Self::ImplId, ) -> EarlyBinder> { - let impl_id = match impl_def_id { - SolverDefId::ImplId(id) => id, - _ => unreachable!(), - }; - let trait_ref = self.db().impl_trait_ns(impl_id).expect("expected an impl of trait"); + let trait_ref = self.db().impl_trait_ns(impl_id.0).expect("expected an impl of trait"); trait_ref.map_bound(|trait_ref| { let clause: Clause<'_> = trait_ref.upcast(self); Clauses::new_from_iter( @@ -1392,7 +1384,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { EarlyBinder::bind([unimplemented!()]) } - fn has_target_features(self, def_id: Self::DefId) -> bool { + fn has_target_features(self, def_id: Self::FunctionId) -> bool { false } @@ -1407,8 +1399,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { SolverLangItem::DynMetadata => LangItem::DynMetadata, SolverLangItem::FutureOutput => LangItem::FutureOutput, SolverLangItem::Metadata => LangItem::Metadata, - SolverLangItem::Option => LangItem::Option, - SolverLangItem::Poll => LangItem::Poll, }; let target = hir_def::lang_item::lang_item( self.db(), @@ -1468,21 +1458,30 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .into() } - #[allow(clippy::match_like_matches_macro)] - fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool { - use SolverLangItem::*; + fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> AdtIdWrapper { + let lang_item = match lang_item { + SolverAdtLangItem::Option => LangItem::Option, + SolverAdtLangItem::Poll => LangItem::Poll, + }; + lang_item + .resolve_adt(self.db(), self.krate.expect("Must have self.krate")) + .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")) + .into() + } - // FIXME: derive PartialEq on SolverLangItem + fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool { self.as_lang_item(def_id) .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) } - #[allow(clippy::match_like_matches_macro)] fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool { - use SolverTraitLangItem::*; + self.as_trait_lang_item(def_id) + .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) + } + fn is_adt_lang_item(self, def_id: Self::AdtId, lang_item: SolverAdtLangItem) -> bool { // FIXME: derive PartialEq on SolverTraitLangItem - self.as_trait_lang_item(def_id) + self.as_adt_lang_item(def_id) .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) } @@ -1505,9 +1504,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { DynMetadata, CoroutineReturn, CoroutineYield, - Poll, FutureOutput, - Option, AsyncFnOnceOutput, CallRefFuture, CallOnceFuture, @@ -1556,6 +1553,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ) } + fn as_adt_lang_item(self, def_id: Self::AdtId) -> Option { + let def_id: AttrDefId = def_id.0.into(); + let lang_item = self.db().lang_attr(def_id)?; + as_lang_item!( + SolverAdtLangItem, lang_item; + + ignore = {} + + Option, + Poll, + ) + } + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator { let trait_ = match def_id { SolverDefId::TraitId(id) => id, @@ -1568,7 +1578,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, trait_: Self::TraitId, self_ty: Self::Ty, - mut f: impl FnMut(Self::DefId), + mut f: impl FnMut(Self::ImplId), ) { let trait_ = trait_.0; let self_ty_fp = TyFingerprint::for_trait_impl_ns(&self_ty); @@ -1595,7 +1605,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { continue; } - f(SolverDefId::ImplId(i)); + f(i.into()); } ControlFlow::Continue(()) }, @@ -1618,7 +1628,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { continue; } - f(SolverDefId::ImplId(i)); + f(i.into()); } } ControlFlow::Continue(()) @@ -1632,7 +1642,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { true } - fn impl_is_default(self, impl_def_id: Self::DefId) -> bool { + fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { // FIXME false } @@ -1640,26 +1650,16 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { #[tracing::instrument(skip(self), ret)] fn impl_trait_ref( self, - impl_def_id: Self::DefId, + impl_id: Self::ImplId, ) -> EarlyBinder> { - let impl_id = match impl_def_id { - SolverDefId::ImplId(id) => id, - _ => panic!("Unexpected SolverDefId in impl_trait_ref"), - }; - let db = self.db(); - - db.impl_trait_ns(impl_id) + db.impl_trait_ns(impl_id.0) // ImplIds for impls where the trait ref can't be resolved should never reach trait solving .expect("invalid impl passed to trait solver") } - fn impl_polarity(self, impl_def_id: Self::DefId) -> rustc_type_ir::ImplPolarity { - let impl_id = match impl_def_id { - SolverDefId::ImplId(id) => id, - _ => unreachable!(), - }; - let impl_data = self.db().impl_signature(impl_id); + fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { + let impl_data = self.db().impl_signature(impl_id.0); if impl_data.flags.contains(ImplFlags::NEGATIVE) { ImplPolarity::Negative } else { @@ -1701,33 +1701,29 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { panic!("Bug encountered in next-trait-solver.") } - fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool { + fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool { // FIXME(next-solver) true } - fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool { + fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool { // FIXME(next-solver) true } - fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool { + fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { // FIXME(next-solver) false } - fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool { + fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { // FIXME(next-solver) false } - fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams { - let id = match adt_def_id { - SolverDefId::AdtId(id) => id, - _ => unreachable!(), - }; - let def = AdtDef::new(id, self); - let num_params = self.generics_of(adt_def_id).count(); + fn unsizing_params_for_adt(self, id: Self::AdtId) -> Self::UnsizingParams { + let def = AdtDef::new(id.0, self); + let num_params = self.generics_of(id.into()).count(); let maybe_unsizing_param_idx = |arg: GenericArg<'db>| match arg.kind() { GenericArgKind::Type(ty) => match ty.kind() { @@ -1835,15 +1831,15 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { EarlyBinder::bind([]) } - fn fn_is_const(self, def_id: Self::DefId) -> bool { - let id = match def_id { - SolverDefId::FunctionId(id) => id, - _ => unreachable!(), + fn fn_is_const(self, id: Self::FunctionId) -> bool { + let id = match id.0 { + CallableDefId::FunctionId(id) => id, + _ => return false, }; self.db().function_signature(id).flags.contains(FnFlags::CONST) } - fn impl_is_const(self, def_id: Self::DefId) -> bool { + fn impl_is_const(self, def_id: Self::ImplId) -> bool { false } @@ -1877,7 +1873,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn coroutine_hidden_types( self, - def_id: Self::DefId, + def_id: Self::CoroutineId, ) -> EarlyBinder>> { // FIXME(next-solver) @@ -1896,11 +1892,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) } - fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool { + fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool { false } - fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool { + fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool { false } @@ -2020,6 +2016,12 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { SolverDefId, TraitIdWrapper, + TypeAliasIdWrapper, + CallableIdWrapper, + ClosureIdWrapper, + CoroutineIdWrapper, + AdtIdWrapper, + ImplIdWrapper, Pattern<'db>, Safety, FnAbi, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 11bc6e6abe94b..ce56282a00b24 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -243,12 +243,10 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { } chalk_ir::TyKind::FnDef(fn_def_id, substitution) => { let def_id = CallableDefId::from_chalk(interner.db(), *fn_def_id); - let id: SolverDefId = match def_id { - CallableDefId::FunctionId(id) => id.into(), - CallableDefId::StructId(id) => SolverDefId::Ctor(Ctor::Struct(id)), - CallableDefId::EnumVariantId(id) => SolverDefId::Ctor(Ctor::Enum(id)), - }; - rustc_type_ir::TyKind::FnDef(id, substitution.to_nextsolver(interner)) + rustc_type_ir::TyKind::FnDef( + def_id.into(), + substitution.to_nextsolver(interner), + ) } chalk_ir::TyKind::Str => rustc_type_ir::TyKind::Str, chalk_ir::TyKind::Never => rustc_type_ir::TyKind::Never, @@ -271,7 +269,7 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { ) } chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign( - SolverDefId::TypeAliasId(crate::from_foreign_def_id(*foreign_def_id)), + crate::from_foreign_def_id(*foreign_def_id).into(), ), chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed), chalk_ir::TyKind::Dyn(dyn_ty) => { @@ -1511,13 +1509,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) TyKind::Slice(ty) } - rustc_type_ir::TyKind::Foreign(foreign) => { - let def_id = match foreign { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - TyKind::Foreign(to_foreign_def_id(def_id)) - } + rustc_type_ir::TyKind::Foreign(foreign) => TyKind::Foreign(to_foreign_def_id(foreign.0)), rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(), rustc_type_ir::TyKind::RawPtr(ty, mutability) => { let mutability = match mutability { @@ -1528,40 +1520,22 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) TyKind::Raw(mutability, ty) } rustc_type_ir::TyKind::FnDef(def_id, args) => { - let id = match def_id { - SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), - SolverDefId::Ctor(Ctor::Struct(id)) => CallableDefId::StructId(id), - SolverDefId::Ctor(Ctor::Enum(id)) => CallableDefId::EnumVariantId(id), - _ => unreachable!(), - }; let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::FnDef(id.to_chalk(interner.db()), subst) + TyKind::FnDef(def_id.0.to_chalk(interner.db()), subst) } rustc_type_ir::TyKind::Closure(def_id, args) => { - let id = match def_id { - SolverDefId::InternedClosureId(id) => id, - _ => unreachable!(), - }; let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::Closure(id.into(), subst) + TyKind::Closure(def_id.0.into(), subst) } rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(), rustc_type_ir::TyKind::Coroutine(def_id, args) => { - let id = match def_id { - SolverDefId::InternedCoroutineId(id) => id, - _ => unreachable!(), - }; let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::Coroutine(id.into(), subst) + TyKind::Coroutine(def_id.0.into(), subst) } rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { - let id = match def_id { - SolverDefId::InternedCoroutineId(id) => id, - _ => unreachable!(), - }; let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::CoroutineWitness(id.into(), subst) + TyKind::CoroutineWitness(def_id.0.into(), subst) } rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index dc5073305c8ca..c7591c0c77966 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -9,8 +9,8 @@ use rustc_type_ir::{ solve::{Certainty, NoSolution}, }; -use crate::next_solver::CanonicalVarKind; use crate::next_solver::mapping::NextSolverToChalk; +use crate::next_solver::{CanonicalVarKind, ImplIdWrapper}; use crate::{ TraitRefExt, db::HirDatabase, @@ -148,12 +148,8 @@ impl<'db> SolverDelegate for SolverContext<'db> { &self, goal_trait_ref: rustc_type_ir::TraitRef, trait_assoc_def_id: ::DefId, - impl_def_id: ::DefId, + impl_id: ImplIdWrapper, ) -> Result::DefId>, ErrorGuaranteed> { - let impl_id = match impl_def_id { - SolverDefId::ImplId(id) => id, - _ => panic!("Unexpected SolverDefId"), - }; let trait_assoc_id = match trait_assoc_def_id { SolverDefId::TypeAliasId(id) => id, _ => panic!("Unexpected SolverDefId"), @@ -162,7 +158,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { .0 .interner .db() - .impl_trait(impl_id) + .impl_trait(impl_id.0) // ImplIds for impls where the trait ref can't be resolved should never reach solver .expect("invalid impl passed to next-solver") .into_value_and_skipped_binders() @@ -170,7 +166,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { let trait_ = trait_ref.hir_trait_id(); let trait_data = trait_.trait_items(self.0.interner.db()); let id = - impl_id.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> { + impl_id.0.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> { match item { (_, AssocItemId::TypeAliasId(type_alias)) => { let name = &self.0.interner.db().type_alias_signature(*type_alias).name; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 4794e2d604509..e1c29160ad1ae 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -20,7 +20,9 @@ use rustc_type_ir::{ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; -use crate::next_solver::GenericArg; +use crate::next_solver::{ + CallableIdWrapper, ClosureIdWrapper, CoroutineIdWrapper, GenericArg, TypeAliasIdWrapper, +}; use crate::{ db::HirDatabase, interner::InternedWrapperNoDebug, @@ -599,10 +601,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { Ty::new(interner, TyKind::Adt(adt_def, args)) } - fn new_foreign( - interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, - ) -> Self { + fn new_foreign(interner: DbInterner<'db>, def_id: TypeAliasIdWrapper) -> Self { Ty::new(interner, TyKind::Foreign(def_id)) } @@ -617,7 +616,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: CoroutineIdWrapper, args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Coroutine(def_id, args)) @@ -625,7 +624,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_closure( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: CoroutineIdWrapper, args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineClosure(def_id, args)) @@ -633,7 +632,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_closure( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: ClosureIdWrapper, args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Closure(def_id, args)) @@ -641,7 +640,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: CoroutineIdWrapper, args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) @@ -649,7 +648,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness_for_coroutine( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: CoroutineIdWrapper, coroutine_args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { // HACK: Coroutine witness types are lifetime erased, so they @@ -714,7 +713,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_fn_def( interner: DbInterner<'db>, - def_id: as rustc_type_ir::Interner>::DefId, + def_id: CallableIdWrapper, args: as rustc_type_ir::Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::FnDef(def_id, args)) From 1acb4c2c1621578ea787afb698ed8718cbdf3d4f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Aug 2025 03:35:22 +0300 Subject: [PATCH 180/251] An associated type is not a projection! More correctly, a `TyKind::AssociatedType` is not the same as `TyKind::Projection`. We used to map next-solver `TyKind::Alias` to Chalk's `TyKind::AssociatedType`. This is very incorrect, as `AssociatedType` is assumed to be fully normalized, and caused a lot of type mismatches. Unfortunately fixing this causes a lot of stack overflows, because the next solver doesn't have something akin to `AssociatedType` so we normalize again and again. The reason is that is the lazy-normalization nature of the next solver, which means we need to stop normalizing everything. This will be fixed in the next commit. --- .../crates/hir-ty/src/next_solver/mapping.rs | 5 +++- .../hir-ty/src/tests/regression/new_solver.rs | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index f66b8dace30a6..57a56b3f0c662 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1358,7 +1358,10 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) }; let associated_ty_id = to_assoc_type_id(assoc_ty_id); let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); - TyKind::AssociatedType(associated_ty_id, substitution) + TyKind::Alias(crate::AliasTy::Projection(crate::ProjectionTy { + associated_ty_id, + substitution, + })) } rustc_type_ir::AliasTyKind::Opaque => { let opaque_ty_id = match alias_ty.def_id { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 97473bbabba04..471108d964f6e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -71,3 +71,30 @@ fn main() { }"#, ); } + +#[test] +fn projection_is_not_associated_type() { + check_no_mismatches( + r#" +//- minicore: fn +trait Iterator { + type Item; + + fn partition(self, f: F) + where + F: FnMut(&Self::Item) -> bool, + { + } +} + +struct Iter; +impl Iterator for Iter { + type Item = i32; +} + +fn main() { + Iter.partition(|n| true); +} + "#, + ); +} From 4a4b77f1c75e48944507fd69e75db36a1658f800 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 10 Sep 2025 03:32:06 +0300 Subject: [PATCH 181/251] Properly handle normalization Previously normalization was broken, which caused a lot of fake errors. This fix most type mismatches of the new solver, and it also reverts many test regressions. The downside is that now `chalk_ir::TyKind::AssociatedType`/`chalk_ir::TyKind::Alias` cannot be trusted anymore with their roles, namely: `AssociatedType` is always fully normalized and `Alias` only if it can possibly be normalized further. That seems okay as the new solver does not have this distinction at all (due to it being a lazy normalizer), so this will only hold for the migration time. This does mean we have to change some APIs, notably `hir::Type::walk()` and `TyFingerprint`, to treat `Alias` the same as `AssociatedType`. Another small thing this commit does is to isolate processing of user-written types (currently involving replacing error types and normalizing, but in the future validation will also be needed) to separate functions. --- .../rust-analyzer/crates/hir-ty/src/infer.rs | 50 +++- .../crates/hir-ty/src/infer/closure.rs | 10 +- .../crates/hir-ty/src/infer/expr.rs | 8 +- .../crates/hir-ty/src/infer/pat.rs | 4 +- .../crates/hir-ty/src/infer/path.rs | 17 +- .../crates/hir-ty/src/infer/unify.rs | 244 +++++++++--------- .../crates/hir-ty/src/method_resolution.rs | 21 +- .../crates/hir-ty/src/tests/macros.rs | 4 +- .../crates/hir-ty/src/tests/never_type.rs | 24 +- .../crates/hir-ty/src/tests/patterns.rs | 8 +- .../crates/hir-ty/src/tests/regression.rs | 12 +- .../hir-ty/src/tests/regression/new_solver.rs | 2 +- .../crates/hir-ty/src/tests/simple.rs | 2 +- .../crates/hir-ty/src/tests/traits.rs | 18 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 9 +- 15 files changed, 235 insertions(+), 198 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 265d1f8541cc8..3d91a2558f0b1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -54,6 +54,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, @@ -922,13 +924,15 @@ impl<'db> InferenceContext<'db> { }); diagnostics.shrink_to_fit(); for (_, subst) in method_resolutions.values_mut() { - *subst = table.resolve_completely(subst.clone()); + *subst = + table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); *has_errors = *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); } method_resolutions.shrink_to_fit(); for (_, subst) in assoc_resolutions.values_mut() { - *subst = table.resolve_completely(subst.clone()); + *subst = + table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); *has_errors = *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); } @@ -946,7 +950,12 @@ impl<'db> InferenceContext<'db> { result.tuple_field_access_types = tuple_field_accesses_rev .into_iter() .enumerate() - .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst))) + .map(|(idx, subst)| { + ( + TupleId(idx as u32), + table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst), + ) + }) .inspect(|(_, subst)| { *has_errors = *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); @@ -1015,14 +1024,12 @@ impl<'db> InferenceContext<'db> { if let Some(self_param) = self.body.self_param && let Some(ty) = param_tys.next() { - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_user_written_ty(ty); self.write_binding_ty(self_param, ty); } let mut tait_candidates = FxHashSet::default(); for (ty, pat) in param_tys.zip(&*self.body.params) { - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_user_written_ty(ty); self.infer_top_pat(*pat, &ty, None); if ty @@ -1073,7 +1080,7 @@ impl<'db> InferenceContext<'db> { None => self.result.standard_types.unit.clone(), }; - self.return_ty = self.normalize_associated_types_in(return_ty); + self.return_ty = self.process_user_written_ty(return_ty); self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); // Functions might be defining usage sites of TAITs. @@ -1415,8 +1422,7 @@ impl<'db> InferenceContext<'db> { ) -> Ty { let ty = self .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); - let ty = self.insert_type_vars(ty); - self.normalize_associated_types_in(ty) + self.process_user_written_ty(ty) } fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { @@ -1562,15 +1568,35 @@ impl<'db> InferenceContext<'db> { ty } + /// Whenever you lower a user-written type, you should call this. + fn process_user_written_ty(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, + { + self.table.process_user_written_ty(ty) + } + + /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation, + /// while `process_user_written_ty()` should (but doesn't currently). + fn process_remote_user_written_ty(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, + { + self.table.process_remote_user_written_ty(ty) + } + /// Recurses through the given type, normalizing associated types mentioned /// in it by replacing them by type variables and registering obligations to /// resolve later. This should be done once for every type we get from some /// type annotation (e.g. from a let type annotation, field type or function /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. - fn normalize_associated_types_in(&mut self, ty: T) -> T + fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { self.table.normalize_associated_types_in(ty) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 5a69ad68b58e4..fd7e5a6a0e121 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -53,7 +53,7 @@ pub(super) struct ClosureSignature { pub(super) expected_sig: FnPointer, } -impl InferenceContext<'_> { +impl<'db> InferenceContext<'db> { pub(super) fn infer_closure( &mut self, body: &ExprId, @@ -71,9 +71,13 @@ impl InferenceContext<'_> { None => (None, None), }; - let ClosureSignature { expected_sig: bound_sig, ret_ty: body_ret_ty } = + let ClosureSignature { expected_sig: mut bound_sig, ret_ty: body_ret_ty } = self.sig_of_closure(body, ret_type, arg_types, closure_kind, expected_sig); - let bound_sig = self.normalize_associated_types_in(bound_sig); + bound_sig.substitution.0 = self + .normalize_associated_types_in::<_, crate::next_solver::GenericArgs<'db>>( + bound_sig.substitution.0, + ); + let bound_sig = bound_sig; let sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner); let (id, ty, resume_yield_tys) = match closure_kind { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index bfeb5bae851a5..0a58ea11bb871 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1419,7 +1419,7 @@ impl InferenceContext<'_> { None => self.err_ty(), }; - let ret_ty = self.normalize_associated_types_in(ret_ty); + let ret_ty = self.process_remote_user_written_ty(ret_ty); if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) { // use knowledge of built-in binary ops, which can sometimes help inference @@ -1630,8 +1630,7 @@ impl InferenceContext<'_> { Some(match res { Some((field_id, ty)) => { let adjustments = auto_deref_adjust_steps(&autoderef); - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_remote_user_written_ty(ty); (ty, field_id, adjustments, true) } @@ -1641,8 +1640,7 @@ impl InferenceContext<'_> { let ty = self.db.field_types(field_id.parent)[field_id.local_id] .clone() .substitute(Interner, &subst); - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_remote_user_written_ty(ty); (ty, Either::Left(field_id), adjustments, false) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 16489e3068f35..6781bc84d1c11 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -88,7 +88,7 @@ impl InferenceContext<'_> { Some(substs) => f.substitute(Interner, substs), None => f.substitute(Interner, &Substitution::empty(Interner)), }; - self.normalize_associated_types_in(expected_ty) + self.process_remote_user_written_ty(expected_ty) } None => self.err_ty(), } @@ -152,7 +152,7 @@ impl InferenceContext<'_> { Some(substs) => f.substitute(Interner, substs), None => f.substitute(Interner, &Substitution::empty(Interner)), }; - self.normalize_associated_types_in(expected_ty) + self.process_remote_user_written_ty(expected_ty) } None => { self.push_diagnostic(InferenceDiagnostic::NoSuchField { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 1f62f9c4aa113..80f7324e58b2b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -23,7 +23,7 @@ use crate::{ use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; -impl InferenceContext<'_> { +impl<'db> InferenceContext<'db> { pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? { ValuePathResolution::GenericDef(value_def, generic_def, substs) => { @@ -31,13 +31,13 @@ impl InferenceContext<'_> { } ValuePathResolution::NonGeneric(ty) => return Some(ty), }; - let substs = self.insert_type_vars(substs); - let substs = self.normalize_associated_types_in(substs); + let substs = + self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs); self.add_required_obligations_for_value_path(generic_def, &substs); let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_remote_user_written_ty(ty); Some(ty) } @@ -173,14 +173,12 @@ impl InferenceContext<'_> { let last = path.segments().last()?; let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref); - let ty = self.table.insert_type_vars(ty); - let ty = self.table.normalize_associated_types_in(ty); + let ty = self.table.process_user_written_ty(ty); path_ctx.ignore_last_segment(); let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true); drop_ctx(ctx, no_diagnostics); - let ty = self.table.insert_type_vars(ty); - let ty = self.table.normalize_associated_types_in(ty); + let ty = self.table.process_user_written_ty(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { let hygiene = self.body.expr_or_pat_path_hygiene(id); @@ -223,8 +221,7 @@ impl InferenceContext<'_> { return None; } - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); + let ty = self.process_user_written_ty(ty); self.resolve_ty_assoc_item(ty, last_segment.name, id) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index ec4b7ee85dc67..19b83d3c212df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -12,12 +12,14 @@ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_next_trait_solver::solve::HasChanged; +use rustc_type_ir::inherent::IntoKind; use rustc_type_ir::{ AliasRelationDirection, FloatVid, IntVid, TyVid, inherent::{Span, Term as _}, relate::{Relate, solver_relating::RelateExt}, solve::{Certainty, NoSolution}, }; +use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt}; use smallvec::SmallVec; use triomphe::Arc; @@ -31,11 +33,8 @@ use crate::{ db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{ - self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term, - infer::{ - DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues, - snapshot::CombinedSnapshot, - }, + self, Binder, DbInterner, Predicate, PredicateKind, SolverDefIds, Term, + infer::{DbInternerInferExt, InferCtxt, snapshot::CombinedSnapshot}, mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk}, }, to_chalk_trait_id, @@ -305,116 +304,21 @@ impl<'a> InferenceTable<'a> { /// type annotation (e.g. from a let type annotation, field type or function /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. - #[tracing::instrument(skip(self), ret)] - pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T + pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, { - fold_tys_and_consts( - ty, - |e, _| match e { - Either::Left(ty) => { - let ty = self.resolve_ty_shallow(&ty); - tracing::debug!(?ty); - Either::Left(match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - let ty = self.normalize_projection_ty(proj_ty.clone()); - self.resolve_ty_shallow(&ty) - } - TyKind::AssociatedType(id, subst) => { - // return Either::Left(self.resolve_ty_shallow(&ty)); - if ty.data(Interner).flags.intersects( - chalk_ir::TypeFlags::HAS_TY_INFER - | chalk_ir::TypeFlags::HAS_CT_INFER, - ) { - return Either::Left(ty); - } - let var = self.new_type_var(); - let proj_ty = chalk_ir::ProjectionTy { - associated_ty_id: *id, - substitution: subst.clone(), - }; - let normalize = chalk_ir::Normalize { - alias: AliasTy::Projection(proj_ty), - ty: var.clone(), - }; - let goal = chalk_ir::Goal::new( - Interner, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Normalize( - normalize, - )), - ); - let in_env = InEnvironment::new(&self.trait_env.env, goal); - let goal = in_env.to_nextsolver(self.interner); - let goal = - ParamEnvAnd { param_env: goal.param_env, value: goal.predicate }; - - let (canonical_goal, orig_values) = { - let mut orig_values = OriginalQueryValues::default(); - let result = - self.infer_ctxt.canonicalize_query(goal, &mut orig_values); - (result.canonical, orig_values) - }; - let canonical_goal = rustc_type_ir::Canonical { - max_universe: canonical_goal.max_universe, - variables: canonical_goal.variables, - value: crate::next_solver::Goal { - param_env: canonical_goal.value.param_env, - predicate: canonical_goal.value.value, - }, - }; - let solution = next_trait_solve_canonical_in_ctxt( - &self.infer_ctxt, - canonical_goal, - ); - if let NextTraitSolveResult::Certain(canonical_subst) = solution { - let subst = self.instantiate_canonical(canonical_subst).subst; - if subst.len(Interner) != orig_values.var_values.len() { - ty - } else { - let target_ty = var.to_nextsolver(self.interner); - subst - .iter(Interner) - .zip(orig_values.var_values.iter()) - .find_map(|(new, orig)| { - if orig.ty() == Some(target_ty) { - Some(new.assert_ty_ref(Interner).clone()) - } else { - None - } - }) - .unwrap_or(ty) - } - } else { - ty - } - } - _ => ty, - }) - } - Either::Right(c) => Either::Right(match &c.data(Interner).value { - chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { - crate::ConstScalar::UnevaluatedConst(c_id, subst) => { - // FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable - // and registering an obligation. But it needs chalk support, so we handle the most basic - // case (a non associated const without generic parameters) manually. - if subst.len(Interner) == 0 { - if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) { - eval - } else { - unknown_const(c.data(Interner).ty.clone()) - } - } else { - unknown_const(c.data(Interner).ty.clone()) - } - } - _ => c, - }, - _ => c, - }), - }, - DebruijnIndex::INNERMOST, - ) + self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } + + pub(crate) fn normalize_associated_types_in_ns(&mut self, ty: T) -> T + where + T: rustc_type_ir::TypeFoldable>, + { + let ty = self.resolve_vars_with_obligations(ty); + ty.fold_with(&mut Normalizer { table: self }) } /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow @@ -476,11 +380,27 @@ impl<'a> InferenceTable<'a> { } pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { - let var = self.new_type_var(); - let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; - let obligation: Goal = alias_eq.cast(Interner); - self.register_obligation(obligation.to_nextsolver(self.interner)); - var + let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(proj_ty)) + .intern(Interner) + .to_nextsolver(self.interner); + self.normalize_alias_ty(ty).to_chalk(self.interner) + } + + pub(crate) fn normalize_alias_ty( + &mut self, + alias: crate::next_solver::Ty<'a>, + ) -> crate::next_solver::Ty<'a> { + let infer_term = self.infer_ctxt.next_ty_var(); + let obligation = crate::next_solver::Predicate::new( + self.interner, + crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate( + alias.into(), + infer_term.into(), + rustc_type_ir::AliasRelationDirection::Equate, + )), + ); + self.register_obligation(obligation); + self.resolve_vars_with_obligations(infer_term) } fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { @@ -591,9 +511,10 @@ impl<'a> InferenceTable<'a> { ) } - pub(crate) fn resolve_completely(&mut self, t: T) -> T + pub(crate) fn resolve_completely(&mut self, t: T) -> T where - T: HasInterner + TypeFoldable, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, { let t = self.resolve_with_fallback(t, &|_, _, d, _| d); let t = self.normalize_associated_types_in(t); @@ -1045,6 +966,30 @@ impl<'a> InferenceTable<'a> { } } + /// Whenever you lower a user-written type, you should call this. + pub(crate) fn process_user_written_ty(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + { + self.process_remote_user_written_ty(ty) + // FIXME: Register a well-formed obligation. + } + + /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation, + /// while `process_user_written_ty()` should (but doesn't currently). + pub(crate) fn process_remote_user_written_ty(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + { + let ty = self.insert_type_vars(ty); + // See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495: + // Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs + // to normalize before inspecting the `TyKind`. + self.normalize_associated_types_in(ty) + } + /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it. pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const { let data = c.data(Interner); @@ -1319,3 +1264,62 @@ mod resolve { } } } + +/// This expects its input to be resolved. +struct Normalizer<'a, 'b> { + table: &'a mut InferenceTable<'b>, +} + +impl<'db> Normalizer<'_, 'db> { + fn normalize_alias_term( + &mut self, + alias_term: crate::next_solver::Term<'db>, + ) -> crate::next_solver::Term<'db> { + let infer_term = self.table.infer_ctxt.next_term_var_of_kind(alias_term); + let obligation = crate::next_solver::Predicate::new( + self.table.interner, + crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate( + alias_term, + infer_term, + rustc_type_ir::AliasRelationDirection::Equate, + )), + ); + self.table.register_obligation(obligation); + let term = self.table.resolve_vars_with_obligations(infer_term); + // Now normalize the result, because maybe it contains more aliases. + match term { + Term::Ty(term) => term.super_fold_with(self).into(), + Term::Const(term) => term.super_fold_with(self).into(), + } + } +} + +impl<'db> rustc_type_ir::TypeFolder> for Normalizer<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.table.interner + } + + fn fold_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> { + if !ty.has_aliases() { + return ty; + } + + let crate::next_solver::TyKind::Alias(..) = ty.kind() else { + return ty.super_fold_with(self); + }; + // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only). + self.normalize_alias_term(ty.into()).expect_type() + } + + fn fold_const(&mut self, ct: crate::next_solver::Const<'db>) -> crate::next_solver::Const<'db> { + if !ct.has_aliases() { + return ct; + } + + let crate::next_solver::ConstKind::Unevaluated(..) = ct.kind() else { + return ct.super_fold_with(self); + }; + // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only). + self.normalize_alias_term(ct.into()).expect_const() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index fa80567b1ecc0..a234312173a23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -22,10 +22,9 @@ use stdx::never; use triomphe::Arc; use crate::{ - AdtId, AliasTy, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, - GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, - TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, - VariableKind, WhereClause, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, + Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause, autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, @@ -106,8 +105,12 @@ impl TyFingerprint { } } TyKind::AssociatedType(_, _) + // FIXME(next-solver): Putting `Alias` here is *probably* incorrect, AFAIK it should return `None`. But this breaks + // flyimport, which uses an incorrect but fast method resolution algorithm. Therefore we put it here, + // because this function is only called by flyimport, and anyway we should get rid of `TyFingerprint` + // and switch to `rustc_type_ir`'s `SimplifiedType`. + | TyKind::Alias(_) | TyKind::OpaqueType(_, _) - | TyKind::Alias(AliasTy::Opaque(_)) | TyKind::FnDef(_, _) | TyKind::Closure(_, _) | TyKind::Coroutine(..) @@ -115,8 +118,7 @@ impl TyFingerprint { TyKind::Function(fn_ptr) => { TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32) } - TyKind::Alias(_) - | TyKind::Placeholder(_) + TyKind::Placeholder(_) | TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) | TyKind::Error => return None, @@ -908,7 +910,10 @@ fn find_matching_impl( } table.register_obligation(goal.to_nextsolver(table.interner)); } - Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) + Some(( + impl_.impl_items(db), + table.resolve_completely::<_, crate::next_solver::GenericArgs<'_>>(impl_substs), + )) }) }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 6490554b22b7d..5d088e40cdeda 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -202,7 +202,7 @@ fn expr_macro_def_expanded_in_various_places() { 100..119 'for _ ...!() {}': {unknown} 100..119 'for _ ...!() {}': &'? mut {unknown} 100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 100..119 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> + 100..119 'for _ ...!() {}': Option<{unknown}> 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () @@ -296,7 +296,7 @@ fn expr_macro_rules_expanded_in_various_places() { 114..133 'for _ ...!() {}': {unknown} 114..133 'for _ ...!() {}': &'? mut {unknown} 114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 114..133 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> + 114..133 'for _ ...!() {}': Option<{unknown}> 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index baca7f2318e22..6a9135622deb6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -362,12 +362,12 @@ fn diverging_expression_3_break() { 140..141 'x': u32 149..175 '{ for ...; }; }': u32 151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter + 151..172 'for a ...eak; }': {unknown} 151..172 'for a ...eak; }': ! - 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter - 151..172 'for a ...eak; }': &'? mut <{unknown} as IntoIterator>::IntoIter + 151..172 'for a ...eak; }': {unknown} + 151..172 'for a ...eak; }': &'? mut {unknown} 151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item> + 151..172 'for a ...eak; }': Option<{unknown}> 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () @@ -379,12 +379,12 @@ fn diverging_expression_3_break() { 226..227 'x': u32 235..253 '{ for ... {}; }': u32 237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter + 237..250 'for a in b {}': {unknown} 237..250 'for a in b {}': ! - 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter - 237..250 'for a in b {}': &'? mut <{unknown} as IntoIterator>::IntoIter + 237..250 'for a in b {}': {unknown} + 237..250 'for a in b {}': &'? mut {unknown} 237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item> + 237..250 'for a in b {}': Option<{unknown}> 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () @@ -395,12 +395,12 @@ fn diverging_expression_3_break() { 304..305 'x': u32 313..340 '{ for ...; }; }': u32 315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter + 315..337 'for a ...urn; }': {unknown} 315..337 'for a ...urn; }': ! - 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter - 315..337 'for a ...urn; }': &'? mut <{unknown} as IntoIterator>::IntoIter + 315..337 'for a ...urn; }': {unknown} + 315..337 'for a ...urn; }': &'? mut {unknown} 315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item> + 315..337 'for a ...urn; }': Option<{unknown}> 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 60a2641e1a20e..02cb03706919b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -48,12 +48,12 @@ fn infer_pattern() { 83..84 '1': i32 86..93 '"hello"': &'static str 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter + 101..151 'for (e... }': {unknown} 101..151 'for (e... }': ! - 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter - 101..151 'for (e... }': &'? mut <{unknown} as IntoIterator>::IntoIter + 101..151 'for (e... }': {unknown} + 101..151 'for (e... }': &'? mut {unknown} 101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 101..151 'for (e... }': Option<<{unknown} as Iterator>::Item> + 101..151 'for (e... }': Option<({unknown}, {unknown})> 101..151 'for (e... }': () 101..151 'for (e... }': () 101..151 'for (e... }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index eacc4603ea1af..6a3f2286215f4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -268,12 +268,12 @@ fn infer_std_crash_5() { expect![[r#" 26..322 '{ ... } }': () 32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter + 32..320 'for co... }': {unknown} 32..320 'for co... }': ! - 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter - 32..320 'for co... }': &'? mut <{unknown} as IntoIterator>::IntoIter + 32..320 'for co... }': {unknown} + 32..320 'for co... }': &'? mut {unknown} 32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 32..320 'for co... }': Option<<{unknown} as Iterator>::Item> + 32..320 'for co... }': Option<{unknown}> 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () @@ -628,7 +628,7 @@ fn issue_4053_diesel_where_clauses() { 65..69 'self': Self 267..271 'self': Self 466..470 'self': SelectStatement - 488..522 '{ ... }': as BoxedDsl>::Output + 488..522 '{ ... }': () 498..502 'self': SelectStatement 498..508 'self.order': O 498..515 'self.o...into()': dyn QueryFragment + '? @@ -1248,7 +1248,7 @@ fn test() { 16..66 'for _ ... }': {unknown} 16..66 'for _ ... }': &'? mut {unknown} 16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 16..66 'for _ ... }': Option<<{unknown} as Iterator>::Item> + 16..66 'for _ ... }': Option<{unknown}> 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 471108d964f6e..6d6c56696a30d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -20,7 +20,7 @@ impl<'a> IntoIterator for &'a Grid { "#, expect![[r#" 150..154 'self': &'a Grid - 174..181 '{ }': impl Iterator + 174..181 '{ }': impl Iterator "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index e7357ed5aa78b..60ad0f49c6ab0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2000,7 +2000,7 @@ fn test() { 225..360 'match ... }': () 231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str> 231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str> - 231..262 'Pin::n...usize)': CoroutineState + 231..262 'Pin::n...usize)': CoroutineState 240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str 245..246 'g': |usize| yields i64 -> &'static str 255..261 '0usize': usize diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 7a946f7ec7ced..22332fdc2b8aa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4190,8 +4190,6 @@ fn g(p:

( &self, tcx: DbInterner<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs index b640039af625b..29e7b883c93bf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs @@ -15,7 +15,7 @@ use tracing::debug; use crate::next_solver::SolverDefId; use crate::next_solver::Ty; -use crate::next_solver::infer::InferCtxtUndoLogs; +use crate::next_solver::infer::{InferCtxtUndoLogs, iter_idx_range}; /// Represents a single undo-able action that affects a type inference variable. #[derive(Clone)] @@ -59,7 +59,7 @@ impl<'tcx> Rollback> for TypeVariableStorage<'tcx> { } } -#[derive(Clone, Default)] +#[derive(Debug, Clone, Default)] pub(crate) struct TypeVariableStorage<'db> { /// The origins of each type variable. values: IndexVec, @@ -102,7 +102,7 @@ pub struct TypeVariableOrigin { pub param_def_id: Option, } -#[derive(Clone)] +#[derive(Debug, Clone)] pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, } @@ -267,6 +267,15 @@ impl<'db> TypeVariableTable<'_, 'db> { self.storage.sub_unification_table.with_log(self.undo_log) } + /// Returns a range of the type variables created during the snapshot. + pub(crate) fn vars_since_snapshot( + &mut self, + value_count: usize, + ) -> (Range, Vec) { + let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars()); + (range.clone(), iter_idx_range(range).map(|index| self.var_origin(index)).collect()) + } + /// Returns indices of all variables that are not yet /// instantiated. pub(crate) fn unresolved_variables(&mut self) -> Vec { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs new file mode 100644 index 0000000000000..cab3c69118f64 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs @@ -0,0 +1,501 @@ +pub use ra_ap_rustc_next_trait_solver::solve::inspect::*; + +use rustc_ast_ir::try_visit; +use rustc_next_trait_solver::{ + resolve::eager_resolve_vars, + solve::{ + SolverDelegateEvalExt, + inspect::{self, instantiate_canonical_state}, + }, +}; +use rustc_type_ir::{ + VisitorResult, + inherent::{IntoKind, Span as _}, + solve::{Certainty, GoalSource, MaybeCause, NoSolution}, +}; + +use crate::next_solver::{ + DbInterner, GenericArg, GenericArgs, Goal, NormalizesTo, ParamEnv, Predicate, PredicateKind, + QueryResult, SolverContext, Span, Term, + fulfill::NextSolverError, + infer::{ + InferCtxt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, +}; + +pub struct InspectConfig { + pub max_depth: usize, +} + +pub struct InspectGoal<'a, 'db> { + infcx: &'a SolverContext<'db>, + depth: usize, + orig_values: Vec>, + goal: Goal<'db, Predicate<'db>>, + result: Result, + final_revision: inspect::Probe>, + normalizes_to_term_hack: Option>, + source: GoalSource, +} + +impl<'a, 'db> std::fmt::Debug for InspectGoal<'a, 'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InspectGoal") + .field("depth", &self.depth) + .field("orig_values", &self.orig_values) + .field("goal", &self.goal) + .field("result", &self.result) + .field("final_revision", &self.final_revision) + .field("normalizes_to_term_hack", &self.normalizes_to_term_hack) + .field("source", &self.source) + .finish() + } +} + +impl<'a, 'db> std::fmt::Debug for InspectCandidate<'a, 'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InspectCandidate") + .field("kind", &self.kind) + .field("steps", &self.steps) + .field("final_state", &self.final_state) + .field("result", &self.result) + .field("shallow_certainty", &self.shallow_certainty) + .finish() + } +} + +/// The expected term of a `NormalizesTo` goal gets replaced +/// with an unconstrained inference variable when computing +/// `NormalizesTo` goals and we return the nested goals to the +/// caller, who also equates the actual term with the expected. +/// +/// This is an implementation detail of the trait solver and +/// not something we want to leak to users. We therefore +/// treat `NormalizesTo` goals as if they apply the expected +/// type at the end of each candidate. +#[derive(Debug, Copy, Clone)] +struct NormalizesToTermHack<'db> { + term: Term<'db>, + unconstrained_term: Term<'db>, +} + +impl<'db> NormalizesToTermHack<'db> { + /// Relate the `term` with the new `unconstrained_term` created + /// when computing the proof tree for this `NormalizesTo` goals. + /// This handles nested obligations. + fn constrain_and( + &self, + infcx: &InferCtxt<'db>, + param_env: ParamEnv<'db>, + f: impl FnOnce(&mut ObligationCtxt<'_, 'db>), + ) -> Result { + let mut ocx = ObligationCtxt::new(infcx); + ocx.eq(&ObligationCause::dummy(), param_env, self.term, self.unconstrained_term)?; + f(&mut ocx); + let errors = ocx.select_all_or_error(); + if errors.is_empty() { + Ok(Certainty::Yes) + } else if errors.iter().all(|e| !matches!(e, NextSolverError::TrueError(_))) { + Ok(Certainty::AMBIGUOUS) + } else { + Err(NoSolution) + } + } +} + +pub struct InspectCandidate<'a, 'db> { + goal: &'a InspectGoal<'a, 'db>, + kind: inspect::ProbeKind>, + steps: Vec<&'a inspect::ProbeStep>>, + final_state: inspect::CanonicalState, ()>, + result: QueryResult<'db>, + shallow_certainty: Certainty, +} + +impl<'a, 'db> InspectCandidate<'a, 'db> { + pub fn kind(&self) -> inspect::ProbeKind> { + self.kind + } + + pub fn result(&self) -> Result { + self.result.map(|c| c.value.certainty) + } + + pub fn goal(&self) -> &'a InspectGoal<'a, 'db> { + self.goal + } + + /// Certainty passed into `evaluate_added_goals_and_make_canonical_response`. + /// + /// If this certainty is `Yes`, then we must be confident that the candidate + /// must hold iff it's nested goals hold. This is not true if the certainty is + /// `Maybe(..)`, which suggests we forced ambiguity instead. + /// + /// This is *not* the certainty of the candidate's full nested evaluation, which + /// can be accessed with [`Self::result`] instead. + pub fn shallow_certainty(&self) -> Certainty { + self.shallow_certainty + } + + /// Visit all nested goals of this candidate without rolling + /// back their inference constraints. This function modifies + /// the state of the `infcx`. + pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result { + for goal in self.instantiate_nested_goals() { + try_visit!(goal.visit_with(visitor)); + } + + V::Result::output() + } + + /// Instantiate the nested goals for the candidate without rolling back their + /// inference constraints. This function modifies the state of the `infcx`. + /// + /// See [`Self::instantiate_impl_args`] if you need the impl args too. + pub fn instantiate_nested_goals(&self) -> Vec> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.to_vec(); + + let mut instantiated_goals = vec![]; + for step in &self.steps { + match **step { + inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( + source, + instantiate_canonical_state( + infcx, + Span::dummy(), + param_env, + &mut orig_values, + goal, + ), + )), + inspect::ProbeStep::RecordImplArgs { .. } => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } + + let () = instantiate_canonical_state( + infcx, + Span::dummy(), + param_env, + &mut orig_values, + self.final_state, + ); + + if let Some(term_hack) = &self.goal.normalizes_to_term_hack { + // FIXME: We ignore the expected term of `NormalizesTo` goals + // when computing the result of its candidates. This is + // scuffed. + let _ = term_hack.constrain_and(infcx, param_env, |_| {}); + } + + instantiated_goals + .into_iter() + .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal)) + .collect() + } + + /// Instantiate the args of an impl if this candidate came from a + /// `CandidateSource::Impl`. This function modifies the state of the + /// `infcx`. + pub fn instantiate_impl_args(&self) -> GenericArgs<'db> { + let infcx = self.goal.infcx; + let param_env = self.goal.goal.param_env; + let mut orig_values = self.goal.orig_values.to_vec(); + + for step in &self.steps { + match **step { + inspect::ProbeStep::RecordImplArgs { impl_args } => { + let impl_args = instantiate_canonical_state( + infcx, + Span::dummy(), + param_env, + &mut orig_values, + impl_args, + ); + + let () = instantiate_canonical_state( + infcx, + Span::dummy(), + param_env, + &mut orig_values, + self.final_state, + ); + + // No reason we couldn't support this, but we don't need to for select. + assert!( + self.goal.normalizes_to_term_hack.is_none(), + "cannot use `instantiate_impl_args` with a `NormalizesTo` goal" + ); + + return eager_resolve_vars(infcx, impl_args); + } + inspect::ProbeStep::AddGoal(..) => {} + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } + + panic!("expected impl args probe step for `instantiate_impl_args`"); + } + + pub fn instantiate_proof_tree_for_nested_goal( + &self, + source: GoalSource, + goal: Goal<'db, Predicate<'db>>, + ) -> InspectGoal<'a, 'db> { + let infcx = self.goal.infcx; + match goal.predicate.kind().no_bound_vars() { + Some(PredicateKind::NormalizesTo(NormalizesTo { alias, term })) => { + let unconstrained_term = infcx.next_term_var_of_kind(term); + let goal = + goal.with(infcx.interner, NormalizesTo { alias, term: unconstrained_term }); + // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the + // expected term. This means that candidates which only fail due to nested goals + // and which normalize to a different term then the final result could ICE: when + // building their proof tree, the expected term was unconstrained, but when + // instantiating the candidate it is already constrained to the result of another + // candidate. + let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term }; + let (proof_tree, nested_goals_result) = infcx.probe(|_| { + // Here, if we have any nested goals, then we make sure to apply them + // considering the constrained RHS, and pass the resulting certainty to + // `InspectGoal::new` so that the goal has the right result (and maintains + // the impression that we don't do this normalizes-to infer hack at all). + let (nested, proof_tree) = + infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy()); + let nested_goals_result = nested.and_then(|nested| { + normalizes_to_term_hack.constrain_and( + infcx, + proof_tree.uncanonicalized_goal.param_env, + |ocx| { + ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| { + Obligation::new( + infcx.interner, + ObligationCause::dummy(), + goal.param_env, + goal.predicate, + ) + })); + }, + ) + }); + (proof_tree, nested_goals_result) + }); + InspectGoal::new( + infcx, + self.goal.depth + 1, + proof_tree, + Some((normalizes_to_term_hack, nested_goals_result)), + source, + ) + } + _ => { + // We're using a probe here as evaluating a goal could constrain + // inference variables by choosing one candidate. If we then recurse + // into another candidate who ends up with different inference + // constraints, we get an ICE if we already applied the constraints + // from the chosen candidate. + let proof_tree = + infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1); + InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) + } + } + } + + /// Visit all nested goals of this candidate, rolling back + /// all inference constraints. + pub fn visit_nested_in_probe>(&self, visitor: &mut V) -> V::Result { + self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor)) + } +} + +impl<'a, 'db> InspectGoal<'a, 'db> { + pub fn infcx(&self) -> &'a InferCtxt<'db> { + self.infcx + } + + pub fn goal(&self) -> Goal<'db, Predicate<'db>> { + self.goal + } + + pub fn result(&self) -> Result { + self.result + } + + pub fn source(&self) -> GoalSource { + self.source + } + + pub fn depth(&self) -> usize { + self.depth + } + + fn candidates_recur( + &'a self, + candidates: &mut Vec>, + steps: &mut Vec<&'a inspect::ProbeStep>>, + probe: &'a inspect::Probe>, + ) { + let mut shallow_certainty = None; + for step in &probe.steps { + match *step { + inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => { + steps.push(step) + } + inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { + assert!(matches!( + shallow_certainty.replace(c), + None | Some(Certainty::Maybe(MaybeCause::Ambiguity)) + )); + } + inspect::ProbeStep::NestedProbe(ref probe) => { + match probe.kind { + // These never assemble candidates for the goal we're trying to solve. + inspect::ProbeKind::ProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => continue, + + inspect::ProbeKind::NormalizedSelfTyAssembly + | inspect::ProbeKind::UnsizeAssembly + | inspect::ProbeKind::Root { .. } + | inspect::ProbeKind::TraitCandidate { .. } + | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } + | inspect::ProbeKind::RigidAlias { .. } => { + // Nested probes have to prove goals added in their parent + // but do not leak them, so we truncate the added goals + // afterwards. + let num_steps = steps.len(); + self.candidates_recur(candidates, steps, probe); + steps.truncate(num_steps); + } + } + } + } + } + + match probe.kind { + inspect::ProbeKind::ProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => { + panic!() + } + + inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {} + + // We add a candidate even for the root evaluation if there + // is only one way to prove a given goal, e.g. for `WellFormed`. + inspect::ProbeKind::Root { result } + | inspect::ProbeKind::TraitCandidate { source: _, result } + | inspect::ProbeKind::OpaqueTypeStorageLookup { result } + | inspect::ProbeKind::RigidAlias { result } => { + // We only add a candidate if `shallow_certainty` was set, which means + // that we ended up calling `evaluate_added_goals_and_make_canonical_response`. + if let Some(shallow_certainty) = shallow_certainty { + candidates.push(InspectCandidate { + goal: self, + kind: probe.kind, + steps: steps.clone(), + final_state: probe.final_state, + shallow_certainty, + result, + }); + } + } + } + } + + pub fn candidates(&'a self) -> Vec> { + let mut candidates = vec![]; + let mut nested_goals = vec![]; + self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision); + candidates + } + + /// Returns the single candidate applicable for the current goal, if it exists. + /// + /// Returns `None` if there are either no or multiple applicable candidates. + pub fn unique_applicable_candidate(&'a self) -> Option> { + // FIXME(-Znext-solver): This does not handle impl candidates + // hidden by env candidates. + let mut candidates = self.candidates(); + candidates.retain(|c| c.result().is_ok()); + candidates.pop().filter(|_| candidates.is_empty()) + } + + fn new( + infcx: &'a InferCtxt<'db>, + depth: usize, + root: inspect::GoalEvaluation>, + term_hack_and_nested_certainty: Option<( + NormalizesToTermHack<'db>, + Result, + )>, + source: GoalSource, + ) -> Self { + let infcx = <&SolverContext<'db>>::from(infcx); + + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } = + root; + // If there's a normalizes-to goal, AND the evaluation result with the result of + // constraining the normalizes-to RHS and computing the nested goals. + let result = result.and_then(|ok| { + let nested_goals_certainty = + term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?; + Ok(ok.value.certainty.and(nested_goals_certainty)) + }); + + InspectGoal { + infcx, + depth, + orig_values, + goal: eager_resolve_vars(infcx, uncanonicalized_goal), + result, + final_revision, + normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), + source, + } + } + + pub(crate) fn visit_with>(&self, visitor: &mut V) -> V::Result { + if self.depth < visitor.config().max_depth { + try_visit!(visitor.visit_goal(self)); + } + + V::Result::output() + } +} + +/// The public API to interact with proof trees. +pub trait ProofTreeVisitor<'db> { + type Result: VisitorResult; + + fn config(&self) -> InspectConfig { + InspectConfig { max_depth: 10 } + } + + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result; +} + +impl<'db> InferCtxt<'db> { + pub(crate) fn visit_proof_tree>( + &self, + goal: Goal<'db, Predicate<'db>>, + visitor: &mut V, + ) -> V::Result { + self.visit_proof_tree_at_depth(goal, 0, visitor) + } + + pub(crate) fn visit_proof_tree_at_depth>( + &self, + goal: Goal<'db, Predicate<'db>>, + depth: usize, + visitor: &mut V, + ) -> V::Result { + let (_, proof_tree) = <&SolverContext<'db>>::from(self) + .evaluate_root_goal_for_proof_tree(goal, Span::dummy()); + visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 7b6e8a1073d78..8f731b06fa197 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -48,8 +48,8 @@ use crate::next_solver::infer::InferCtxt; use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; use crate::next_solver::{ AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, - CoroutineIdWrapper, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, RegionAssumptions, - SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, + CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, + RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, }; use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase}; @@ -1055,60 +1055,62 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { - match def_id { - SolverDefId::FunctionId(def_id) => VariancesOf::new_from_iter( - self, - self.db() - .variances_of(hir_def::GenericDefId::FunctionId(def_id)) - .as_deref() - .unwrap_or_default() - .iter() - .map(|v| v.to_nextsolver(self)), - ), - SolverDefId::AdtId(def_id) => VariancesOf::new_from_iter( - self, - self.db() - .variances_of(hir_def::GenericDefId::AdtId(def_id)) - .as_deref() - .unwrap_or_default() - .iter() - .map(|v| v.to_nextsolver(self)), - ), + let generic_def = match def_id { + SolverDefId::FunctionId(def_id) => def_id.into(), + SolverDefId::AdtId(def_id) => def_id.into(), + SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(), + SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(), SolverDefId::InternedOpaqueTyId(_def_id) => { // FIXME(next-solver): track variances // // We compute them based on the only `Ty` level info in rustc, // move `variances_of_opaque` into `rustc_next_trait_solver` for reuse. - VariancesOf::new_from_iter( + return VariancesOf::new_from_iter( self, (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant), - ) + ); } - _ => VariancesOf::new_from_iter(self, []), - } + _ => return VariancesOf::new_from_iter(self, []), + }; + VariancesOf::new_from_iter( + self, + self.db() + .variances_of(generic_def) + .as_deref() + .unwrap_or_default() + .iter() + .map(|v| v.to_nextsolver(self)), + ) } fn type_of(self, def_id: Self::DefId) -> EarlyBinder { - let def_id = match def_id { + match def_id { SolverDefId::TypeAliasId(id) => { use hir_def::Lookup; match id.lookup(self.db()).container { ItemContainerId::ImplId(it) => it, _ => panic!("assoc ty value should be in impl"), }; - crate::TyDefId::TypeAliasId(id) + self.db().ty_ns(id.into()) } - SolverDefId::AdtId(id) => crate::TyDefId::AdtId(id), + SolverDefId::AdtId(id) => self.db().ty_ns(id.into()), // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. // // We currently always use the type from HIR typeck which ignores regions. This // should be fine. - SolverDefId::InternedOpaqueTyId(_) => { - return self.type_of_opaque_hir_typeck(def_id); + SolverDefId::InternedOpaqueTyId(_) => self.type_of_opaque_hir_typeck(def_id), + SolverDefId::FunctionId(id) => self.db.value_ty_ns(id.into()).unwrap(), + SolverDefId::Ctor(id) => { + let id = match id { + Ctor::Struct(id) => id.into(), + Ctor::Enum(id) => id.into(), + }; + self.db + .value_ty_ns(id) + .expect("`SolverDefId::Ctor` should have a function-like ctor") } _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), - }; - self.db().ty_ns(def_id) + } } fn adt_def(self, def_id: Self::AdtId) -> Self::AdtDef { @@ -1998,6 +2000,28 @@ impl<'db> DbInterner<'db> { ) -> T { self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate) } + + pub fn mk_fn_sig( + self, + inputs: I, + output: Ty<'db>, + c_variadic: bool, + safety: Safety, + abi: FnAbi, + ) -> FnSig<'db> + where + I: IntoIterator>, + { + FnSig { + inputs_and_output: Tys::new_from_iter( + self, + inputs.into_iter().chain(std::iter::once(output)), + ), + c_variadic, + safety, + abi, + } + } } macro_rules! TrivialTypeTraversalImpls { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index eb2cc69167d0d..d8a86ea083e08 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -147,6 +147,24 @@ pub trait NextSolverToChalk<'db, Out> { fn to_chalk(self, interner: DbInterner<'db>) -> Out; } +impl NextSolverToChalk<'_, chalk_ir::Mutability> for rustc_ast_ir::Mutability { + fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Mutability { + match self { + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + } + } +} + +impl NextSolverToChalk<'_, chalk_ir::Safety> for crate::next_solver::abi::Safety { + fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Safety { + match self { + crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, + crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, + } + } +} + impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { fn to_nextsolver(&self, interner: DbInterner<'db>) -> Ty<'db> { Ty::new( @@ -617,6 +635,15 @@ impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution } } +impl<'db> NextSolverToChalk<'db, crate::Substitution> for Tys<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> crate::Substitution { + Substitution::from_iter( + Interner, + self.inner().iter().map(|ty| ty.to_chalk(interner).cast(Interner)), + ) + } +} + impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex { fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { rustc_type_ir::DebruijnIndex::from_u32(self.depth()) @@ -859,6 +886,16 @@ impl<'db> NextSolverToChalk<'db, chalk_ir::Goal> for Predicate<'db> { } } +impl<'db> NextSolverToChalk<'db, crate::ProjectionTy> for crate::next_solver::AliasTy<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> crate::ProjectionTy { + let SolverDefId::TypeAliasId(assoc_id) = self.def_id else { unreachable!() }; + crate::ProjectionTy { + associated_ty_id: to_assoc_type_id(assoc_id), + substitution: self.args.to_chalk(interner), + } + } +} + impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment { fn to_nextsolver(&self, interner: DbInterner<'db>) -> ParamEnv<'db> { let clauses = Clauses::new_from_iter( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs similarity index 87% rename from src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs rename to src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs index 42c238febf6f6..41cb4884404f1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs @@ -1,35 +1,23 @@ -//! Normalization within a next-solver infer context. - -use std::fmt::Debug; - use rustc_next_trait_solver::placeholder::BoundVarReplacer; use rustc_type_ir::{ AliasRelationDirection, FallibleTypeFolder, Flags, Interner, TermKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, - inherent::{IntoKind, Span as _, Term as _}, + inherent::{IntoKind, Term as _}, }; +use crate::next_solver::SolverDefId; use crate::next_solver::{ - Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Span, Term, Ty, - TyKind, TypingMode, + Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Term, Ty, + TyKind, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ - DbInternerInferExt, InferCtxt, + InferCtxt, at::At, traits::{Obligation, ObligationCause}, }, util::PlaceholderReplacer, }; -pub fn normalize<'db, T>(interner: DbInterner<'db>, param_env: ParamEnv<'db>, value: T) -> T -where - T: TypeFoldable>, -{ - let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); - let cause = ObligationCause::dummy(); - deeply_normalize(infer_ctxt.at(&cause, param_env), value.clone()).unwrap_or(value) -} - /// Deeply normalize all aliases in `value`. This does not handle inference and expects /// its input to be already fully resolved. pub fn deeply_normalize<'db, T>(at: At<'_, 'db>, value: T) -> Result>> @@ -81,10 +69,16 @@ where T: TypeFoldable>, { let fulfill_cx = FulfillmentCtxt::new(at.infcx); - let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes }; + let mut folder = NormalizationFolder { + at, + fulfill_cx, + depth: 0, + universes, + stalled_coroutine_goals: vec![], + }; let value = value.try_fold_with(&mut folder)?; let errors = folder.fulfill_cx.select_all_or_error(at.infcx); - if errors.is_empty() { Ok((value, vec![])) } else { Err(errors) } + if errors.is_empty() { Ok((value, folder.stalled_coroutine_goals)) } else { Err(errors) } } struct NormalizationFolder<'me, 'db> { @@ -92,6 +86,7 @@ struct NormalizationFolder<'me, 'db> { fulfill_cx: FulfillmentCtxt<'db>, depth: usize, universes: Vec>, + stalled_coroutine_goals: Vec>>, } impl<'db> NormalizationFolder<'_, 'db> { @@ -100,22 +95,30 @@ impl<'db> NormalizationFolder<'_, 'db> { alias_term: Term<'db>, ) -> Result, Vec>> { let infcx = self.at.infcx; - let tcx = infcx.interner; - let recursion_limit = tcx.recursion_limit(); - if self.depth > recursion_limit { - return Err(vec![]); - } + let interner = infcx.interner; + let recursion_limit = interner.recursion_limit(); self.depth += 1; let infer_term = infcx.next_term_var_of_kind(alias_term); let obligation = Obligation::new( - tcx, + interner, self.at.cause.clone(), self.at.param_env, PredicateKind::AliasRelate(alias_term, infer_term, AliasRelationDirection::Equate), ); + if self.depth > recursion_limit { + // let term = alias_term.to_alias_term().unwrap(); + // self.at.infcx.err_ctxt().report_overflow_error( + // OverflowCause::DeeplyNormalize(term), + // self.at.cause.span, + // true, + // |_| {}, + // ); + return Err(vec![NextSolverError::Overflow(obligation)]); + } + self.fulfill_cx.register_predicate_obligation(infcx, obligation); self.select_all_and_stall_coroutine_predicates()?; @@ -140,6 +143,13 @@ impl<'db> NormalizationFolder<'_, 'db> { return Err(errors); } + self.stalled_coroutine_goals.extend( + self.fulfill_cx + .drain_stalled_obligations_for_coroutines(self.at.infcx) + .into_iter() + .map(|obl| obl.as_goal()), + ); + let errors = self.fulfill_cx.collect_remaining_errors(self.at.infcx); if !errors.is_empty() { return Err(errors); @@ -166,7 +176,6 @@ impl<'db> FallibleTypeFolder> for NormalizationFolder<'_, 'db> { Ok(t) } - #[tracing::instrument(level = "trace", skip(self), ret)] fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ty, infcx.shallow_resolve(ty)); @@ -193,7 +202,6 @@ impl<'db> FallibleTypeFolder> for NormalizationFolder<'_, 'db> { } } - #[tracing::instrument(level = "trace", skip(self), ret)] fn try_fold_const(&mut self, ct: Const<'db>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ct, infcx.shallow_resolve_const(ct)); @@ -232,8 +240,8 @@ pub(crate) fn deeply_normalize_for_diagnostics<'db, T: TypeFoldable { - at: At<'a, 'db>, +struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { + at: At<'a, 'tcx>, } impl<'db> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, 'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs new file mode 100644 index 0000000000000..8e2dc0dec4ed3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs @@ -0,0 +1,203 @@ +use hir_def::TraitId; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::{TypeFoldable, Upcast, Variance}; + +use crate::next_solver::fulfill::{FulfillmentCtxt, NextSolverError}; +use crate::next_solver::infer::at::ToTrace; +use crate::next_solver::infer::traits::{ + Obligation, ObligationCause, PredicateObligation, PredicateObligations, +}; +use crate::next_solver::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace}; +use crate::next_solver::{Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError}; + +/// Used if you want to have pleasant experience when dealing +/// with obligations outside of hir or mir typeck. +pub struct ObligationCtxt<'a, 'db> { + pub infcx: &'a InferCtxt<'db>, + engine: FulfillmentCtxt<'db>, +} + +impl<'a, 'db> ObligationCtxt<'a, 'db> { + pub fn new(infcx: &'a InferCtxt<'db>) -> Self { + Self { infcx, engine: FulfillmentCtxt::new(infcx) } + } +} + +impl<'a, 'db> ObligationCtxt<'a, 'db> { + pub fn register_obligation(&mut self, obligation: PredicateObligation<'db>) { + self.engine.register_predicate_obligation(self.infcx, obligation); + } + + pub fn register_obligations( + &mut self, + obligations: impl IntoIterator>, + ) { + self.engine.register_predicate_obligations(self.infcx, obligations); + } + + pub fn register_infer_ok_obligations(&mut self, infer_ok: InferOk<'db, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.register_obligations(obligations); + value + } + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + pub fn register_bound( + &mut self, + cause: ObligationCause, + param_env: ParamEnv<'db>, + ty: Ty<'db>, + def_id: TraitId, + ) { + let trait_ref = TraitRef::new(self.infcx.interner, def_id.into(), [ty]); + self.register_obligation(Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: trait_ref.upcast(self.infcx.interner), + }); + } + + pub fn eq>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .eq(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + pub fn eq_trace>>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + trace: TypeTrace<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. + pub fn sub>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .sub(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + pub fn relate>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + variance: Variance, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .relate(DefineOpaqueTypes::Yes, expected, variance, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`. + pub fn sup>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'db>> { + self.infcx + .at(cause, param_env) + .sup(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Computes the least-upper-bound, or mutual supertype, of two values. + pub fn lub>( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + expected: T, + actual: T, + ) -> Result> { + self.infcx + .at(cause, param_env) + .lub(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + #[must_use] + pub fn select_where_possible(&mut self) -> Vec> { + self.engine.select_where_possible(self.infcx) + } + + #[must_use] + pub fn select_all_or_error(&mut self) -> Vec> { + self.engine.select_all_or_error(self.infcx) + } + + /// Returns the not-yet-processed and stalled obligations from the + /// `ObligationCtxt`. + /// + /// Takes ownership of the context as doing operations such as + /// [`ObligationCtxt::eq`] afterwards will result in other obligations + /// getting ignored. You can make a new `ObligationCtxt` if this + /// needs to be done in a loop, for example. + #[must_use] + pub fn into_pending_obligations(self) -> PredicateObligations<'db> { + self.engine.pending_obligations() + } + + pub fn deeply_normalize>>( + &self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: T, + ) -> Result>> { + self.infcx.at(cause, param_env).deeply_normalize(value) + } + + pub fn structurally_normalize_ty( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Ty<'db>, + ) -> Result, Vec>> { + self.infcx.at(cause, param_env).structurally_normalize_ty(value, &mut self.engine) + } + + pub fn structurally_normalize_const( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Const<'db>, + ) -> Result, Vec>> { + self.infcx.at(cause, param_env).structurally_normalize_const(value, &mut self.engine) + } + + pub fn structurally_normalize_term( + &mut self, + cause: &ObligationCause, + param_env: ParamEnv<'db>, + value: Term<'db>, + ) -> Result, Vec>> { + self.infcx.at(cause, param_env).structurally_normalize_term(value, &mut self.engine) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index c86d3a4aadb22..99b1354b6335f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -262,28 +262,6 @@ impl<'db> Predicate<'db> { Some(Predicate::new(DbInterner::conjure(), kind)) } - - pub fn as_trait_clause(self) -> Option> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(ClauseKind::Projection(..)) - | PredicateKind::Clause(ClauseKind::HostEffect(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) - | PredicateKind::NormalizesTo(..) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::DynCompatible(..) - | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, - } - } } // FIXME: should make a "header" in interned_vec @@ -693,6 +671,12 @@ impl<'db> UpcastFrom, ty::OutlivesPredicate, Reg } } +impl<'db> UpcastFrom, PolyRegionOutlivesPredicate<'db>> for Predicate<'db> { + fn upcast_from(from: PolyRegionOutlivesPredicate<'db>, tcx: DbInterner<'db>) -> Self { + from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx) + } +} + impl<'db> rustc_type_ir::inherent::Predicate> for Predicate<'db> { fn as_clause(self) -> Option< as rustc_type_ir::Interner>::Clause> { match self.kind().skip_binder() { @@ -730,6 +714,30 @@ impl<'db> rustc_type_ir::inherent::Predicate> for Predicate<'db> } impl<'db> Predicate<'db> { + pub fn as_trait_clause(self) -> Option> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + _ => None, + } + } + + pub fn as_projection_clause(self) -> Option> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), + _ => None, + } + } + + /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. + pub fn as_clause(self) -> Option> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + /// Assert that the predicate is a clause. pub fn expect_clause(self) -> Clause<'db> { match self.kind().skip_binder() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs deleted file mode 100644 index e57808728ae96..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Projection code for next-solver. - -pub(crate) mod solve_normalize; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index c7591c0c77966..946e57e6cb741 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -2,6 +2,7 @@ use hir_def::{AssocItemId, GeneralConstId, TypeAliasId}; use rustc_next_trait_solver::delegate::SolverDelegate; +use rustc_type_ir::GenericArgKind; use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::{ InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex, @@ -65,12 +66,12 @@ impl<'db> SolverDelegate for SolverContext<'db> { (SolverContext(infcx), value, vars) } - fn fresh_var_for_kind_with_span( - &self, - arg: ::GenericArg, - span: ::Span, - ) -> ::GenericArg { - unimplemented!() + fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> { + match arg.kind() { + GenericArgKind::Lifetime(_) => self.next_region_var().into(), + GenericArgKind::Type(_) => self.next_ty_var().into(), + GenericArgKind::Const(_) => self.next_const_var().into(), + } } fn leak_check( @@ -92,7 +93,8 @@ impl<'db> SolverDelegate for SolverContext<'db> { >, >, > { - unimplemented!() + // FIXME(next-solver): + None } fn make_deduplicated_outlives_constraints( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/structural_normalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/structural_normalize.rs new file mode 100644 index 0000000000000..18859d8b79707 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/structural_normalize.rs @@ -0,0 +1,57 @@ +use rustc_type_ir::{AliasRelationDirection, inherent::Term as _}; + +use crate::next_solver::{ + Const, PredicateKind, Term, Ty, + fulfill::{FulfillmentCtxt, NextSolverError}, + infer::{at::At, traits::Obligation}, +}; + +impl<'db> At<'_, 'db> { + pub(crate) fn structurally_normalize_ty( + &self, + ty: Ty<'db>, + fulfill_cx: &mut FulfillmentCtxt<'db>, + ) -> Result, Vec>> { + self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type()) + } + + pub(crate) fn structurally_normalize_const( + &self, + ct: Const<'db>, + fulfill_cx: &mut FulfillmentCtxt<'db>, + ) -> Result, Vec>> { + self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const()) + } + + pub(crate) fn structurally_normalize_term( + &self, + term: Term<'db>, + fulfill_cx: &mut FulfillmentCtxt<'db>, + ) -> Result, Vec>> { + assert!(!term.is_infer(), "should have resolved vars before calling"); + + if term.to_alias_term().is_none() { + return Ok(term); + } + + let new_infer = self.infcx.next_term_var_of_kind(term); + + // We simply emit an `alias-eq` goal here, since that will take care of + // normalizing the LHS of the projection until it is a rigid projection + // (or a not-yet-defined opaque in scope). + let obligation = Obligation::new( + self.infcx.interner, + self.cause.clone(), + self.param_env, + PredicateKind::AliasRelate(term, new_infer, AliasRelationDirection::Equate), + ); + + fulfill_cx.register_predicate_obligation(self.infcx, obligation); + let errors = fulfill_cx.select_where_possible(self.infcx); + if !errors.is_empty() { + return Err(errors); + } + + Ok(self.infcx.resolve_vars_if_possible(new_infer)) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index e1c29160ad1ae..e6c444d0d6bed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -1,17 +1,19 @@ //! Things related to tys in the next-trait-solver. +use std::iter; +use std::ops::ControlFlow; + use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId}; use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; -use rustc_type_ir::Interner; use rustc_type_ir::{ - BoundVar, ClosureKind, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, - TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, UintTy, - WithCachedTypeInfo, + BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy, + IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo, inherent::{ - AdtDef, BoundVarLike, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, SliceLike, - Ty as _, + Abi, AdtDef, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, + PlaceholderLike, Safety as _, SliceLike, Ty as _, }, relate::Relate, solve::SizedTraitKind, @@ -20,13 +22,16 @@ use rustc_type_ir::{ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; -use crate::next_solver::{ - CallableIdWrapper, ClosureIdWrapper, CoroutineIdWrapper, GenericArg, TypeAliasIdWrapper, -}; use crate::{ + FnAbi, db::HirDatabase, interner::InternedWrapperNoDebug, - next_solver::util::{CoroutineArgsExt, IntegerTypeExt}, + next_solver::{ + CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg, + PolyFnSig, TypeAliasIdWrapper, + abi::Safety, + util::{CoroutineArgsExt, IntegerTypeExt}, + }, }; use super::{ @@ -310,6 +315,68 @@ impl<'db> Ty<'db> { | TyKind::Error(_) => false, } } + + #[inline] + pub fn is_never(self) -> bool { + matches!(self.kind(), TyKind::Never) + } + + #[inline] + pub fn is_infer(self) -> bool { + matches!(self.kind(), TyKind::Infer(..)) + } + + #[inline] + pub fn is_str(self) -> bool { + matches!(self.kind(), TyKind::Str) + } + + #[inline] + pub fn is_unit(self) -> bool { + matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty()) + } + + /// Given a `fn` type, returns an equivalent `unsafe fn` type; + /// that is, a `fn` type that is equivalent in every way for being + /// unsafe. + pub fn safe_to_unsafe_fn_ty(interner: DbInterner<'db>, sig: PolyFnSig<'db>) -> Ty<'db> { + assert!(sig.safety().is_safe()); + Ty::new_fn_ptr(interner, sig.map_bound(|sig| FnSig { safety: Safety::Unsafe, ..sig })) + } + + /// Returns the type of `*ty`. + /// + /// The parameter `explicit` indicates if this is an *explicit* dereference. + /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. + pub fn builtin_deref(self, db: &dyn HirDatabase, explicit: bool) -> Option> { + match self.kind() { + TyKind::Adt(adt, substs) if crate::lang_items::is_box(db, adt.def_id().0) => { + Some(substs.as_slice()[0].expect_ty()) + } + TyKind::Ref(_, ty, _) => Some(ty), + TyKind::RawPtr(ty, _) if explicit => Some(ty), + _ => None, + } + } + + /// Whether the type contains some non-lifetime, aka. type or const, error type. + pub fn references_non_lt_error(self) -> bool { + self.references_error() && self.visit_with(&mut ReferencesNonLifetimeError).is_break() + } +} + +struct ReferencesNonLifetimeError; + +impl<'db> TypeVisitor> for ReferencesNonLifetimeError { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if ty.is_ty_error() { ControlFlow::Break(()) } else { ty.super_visit_with(self) } + } + + fn visit_const(&mut self, c: Const<'db>) -> Self::Result { + if c.is_ct_error() { ControlFlow::Break(()) } else { c.super_visit_with(self) } + } } impl<'db> std::fmt::Debug for Ty<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index 97d3ea72c93cb..a50f20a565ee2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -409,8 +409,7 @@ pub(crate) fn for_trait_impls( // Note: Since we're using `impls_for_trait` and `impl_provided_for`, // only impls where the trait can be resolved should ever reach Chalk. // `impl_datum` relies on that and will panic if the trait can't be resolved. - let in_deps = db.trait_impls_in_deps(krate); - let in_self = db.trait_impls_in_crate(krate); + let in_self_and_deps = db.trait_impls_in_deps(krate); let trait_module = trait_id.module(db); let type_module = match self_ty_fp { Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(db)), @@ -435,8 +434,7 @@ pub(crate) fn for_trait_impls( }); }) .filter_map(|block_id| db.trait_impls_in_block(block_id)); - f(&in_self)?; - for it in in_deps.iter().map(ops::Deref::deref) { + for it in in_self_and_deps.iter().map(ops::Deref::deref) { f(it)?; } for it in block_impls { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs index 9d1238701bcfa..0a8ed2cf0cabd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs @@ -7,7 +7,7 @@ use hir_def::tt; use intern::{Symbol, sym}; use rustc_hash::{FxHashMap, FxHashSet}; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct TargetFeatures { pub(crate) enabled: FxHashSet, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 7ec5231a7341a..1735f550b8ad7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -177,21 +177,23 @@ fn test(i: i32) { #[test] fn coerce_merge_one_by_one1() { - cov_mark::check!(coerce_merge_fail_fallback); - check( r" fn test() { let t = &mut 1; let x = match 1 { 1 => t as *mut i32, - //^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer) + //^ adjustments: Deref(None), Borrow(RawPtr(Mut)) + _ => t as *const i32, + }; + x; + // ^ type: *const i32 + let x = match 1 { + 1 => t as *mut i32, 2 => t as &i32, //^^^^^^^^^ expected *mut i32, got &'? i32 _ => t as *const i32, }; - x; - //^ type: *const i32 } ", @@ -276,17 +278,19 @@ fn test() { fn coerce_autoderef_implication_1() { check_no_mismatches( r" -//- minicore: deref -struct Foo; +//- minicore: deref, phantom_data +use core::marker::PhantomData; + +struct Foo(PhantomData); impl core::ops::Deref for Foo { type Target = (); } fn takes_ref_foo(x: &Foo) {} fn test() { - let foo = Foo; + let foo = Foo(PhantomData); //^^^ type: Foo<{unknown}> takes_ref_foo(&foo); - let foo = Foo; + let foo = Foo(PhantomData); //^^^ type: Foo let _: &() = &foo; }", @@ -297,16 +301,18 @@ fn test() { fn coerce_autoderef_implication_2() { check( r" -//- minicore: deref -struct Foo; +//- minicore: deref, phantom_data +use core::marker::PhantomData; + +struct Foo(PhantomData); impl core::ops::Deref for Foo { type Target = (); } fn takes_ref_foo(x: &Foo) {} fn test() { - let foo = Foo; + let foo = Foo(PhantomData); //^^^ type: Foo<{unknown}> - let _: &u32 = &Foo; - //^^^^ expected &'? u32, got &'? Foo<{unknown}> + let _: &u32 = &Foo(PhantomData); + //^^^^^^^^^^^^^^^^^ expected &'? u32, got &'? Foo<{unknown}> }", ); } @@ -409,8 +415,6 @@ fn test() { #[test] fn coerce_fn_items_in_match_arms() { - cov_mark::check!(coerce_fn_reification); - check_no_mismatches( r" fn foo1(x: u32) -> isize { 1 } @@ -683,9 +687,9 @@ fn coerce_unsize_expected_type_2() { check_no_mismatches( r#" //- minicore: coerce_unsized -struct InFile; +struct InFile(T); impl InFile { - fn with_value(self, value: U) -> InFile { InFile } + fn with_value(self, value: U) -> InFile { InFile(loop {}) } } struct RecordField; trait AstNode {} @@ -694,7 +698,7 @@ impl AstNode for RecordField {} fn takes_dyn(it: InFile<&dyn AstNode>) {} fn test() { - let x: InFile<()> = InFile; + let x: InFile<()> = InFile(()); let n = &RecordField; takes_dyn(x.with_value(n)); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs index 855034117c0d7..f257aa1b6e602 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs @@ -89,7 +89,6 @@ fn test(x: bool) { //^^^^ expected (), got &'static str } match x { true => true, false => 0 } - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), got bool //^ expected bool, got i32 () } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index d79639b93727b..c0b930e5e1231 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -48,7 +48,6 @@ fn foo() -> i32 { "expr_scopes_shim", "lang_item", "crate_lang_items", - "lang_item", ] "#]], ); @@ -138,7 +137,6 @@ fn baz() -> i32 { "crate_lang_items", "attrs_shim", "attrs_shim", - "lang_item", "infer_shim", "function_signature_shim", "function_signature_with_source_map_shim", @@ -588,8 +586,8 @@ fn main() { "crate_lang_items", "attrs_shim", "attrs_shim", - "return_type_impl_traits_shim", "generic_predicates_ns_shim", + "return_type_impl_traits_shim", "infer_shim", "function_signature_shim", "function_signature_with_source_map_shim", @@ -602,6 +600,7 @@ fn main() { "VariantFields::firewall_", "VariantFields::query_", "lang_item", + "lang_item", "inherent_impls_in_crate_shim", "impl_signature_shim", "impl_signature_with_source_map_shim", @@ -616,7 +615,6 @@ fn main() { "generic_predicates_ns_shim", "value_ty_shim", "generic_predicates_shim", - "lang_item", ] "#]], ); @@ -688,8 +686,8 @@ fn main() { "attrs_shim", "attrs_shim", "attrs_shim", - "return_type_impl_traits_shim", "generic_predicates_ns_shim", + "return_type_impl_traits_shim", "infer_shim", "function_signature_with_source_map_shim", "expr_scopes_shim", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 5d088e40cdeda..25b938c7078aa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -194,15 +194,15 @@ fn expr_macro_def_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - 39..442 '{ ...!(); }': () + 39..442 '{ ...!(); }': {unknown} 73..94 'spam!(...am!())': {unknown} 100..119 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter - 100..119 'for _ ...!() {}': {unknown} + 100..119 'for _ ...!() {}': ::IntoIter 100..119 'for _ ...!() {}': ! - 100..119 'for _ ...!() {}': {unknown} - 100..119 'for _ ...!() {}': &'? mut {unknown} + 100..119 'for _ ...!() {}': ::IntoIter + 100..119 'for _ ...!() {}': &'? mut ::IntoIter 100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 100..119 'for _ ...!() {}': Option<{unknown}> + 100..119 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () @@ -288,15 +288,15 @@ fn expr_macro_rules_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - 53..456 '{ ...!(); }': () + 53..456 '{ ...!(); }': {unknown} 87..108 'spam!(...am!())': {unknown} 114..133 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter - 114..133 'for _ ...!() {}': {unknown} + 114..133 'for _ ...!() {}': ::IntoIter 114..133 'for _ ...!() {}': ! - 114..133 'for _ ...!() {}': {unknown} - 114..133 'for _ ...!() {}': &'? mut {unknown} + 114..133 'for _ ...!() {}': ::IntoIter + 114..133 'for _ ...!() {}': &'? mut ::IntoIter 114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 114..133 'for _ ...!() {}': Option<{unknown}> + 114..133 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item> 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () @@ -707,7 +707,7 @@ fn infer_builtin_macros_file() { expect![[r#" !0..6 '"file"': &'static str 63..87 '{ ...!(); }': () - 73..74 'x': &'static str + 73..74 'x': &'? str "#]], ); } @@ -745,7 +745,7 @@ fn infer_builtin_macros_concat() { expect![[r#" !0..13 '"helloworld!"': &'static str 65..121 '{ ...")); }': () - 75..76 'x': &'static str + 75..76 'x': &'? str "#]], ); } @@ -822,7 +822,7 @@ macro_rules! include_str {() => {}} fn main() { let a = include_str!("foo.rs"); a; -} //^ &'static str +} //^ &'? str //- /foo.rs hello @@ -849,7 +849,7 @@ macro_rules! m { fn main() { let a = include_str!(m!(".rs")); a; -} //^ &'static str +} //^ &'? str //- /foo.rs hello @@ -964,7 +964,7 @@ fn infer_builtin_macros_concat_with_lazy() { expect![[r#" !0..13 '"helloworld!"': &'static str 103..160 '{ ...")); }': () - 113..114 'x': &'static str + 113..114 'x': &'? str "#]], ); } @@ -979,7 +979,7 @@ fn infer_builtin_macros_env() { fn main() { let x = env!("foo"); - //^ &'static str + //^ &'? str } "#, ); @@ -993,7 +993,7 @@ fn infer_builtin_macros_option_env() { //- /main.rs env:foo=bar fn main() { let x = option_env!("foo"); - //^ Option<&'static str> + //^ Option<&'? str> } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index d50daf0f0d5be..b14ce35aa99c8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -578,17 +578,17 @@ fn infer_trait_assoc_method_generics_3() { trait Trait { fn make() -> (Self, T); } - struct S; + struct S(T); impl Trait for S {} fn test() { let a = S::make(); } "#, expect![[r#" - 100..126 '{ ...e(); }': () - 110..111 'a': (S, i64) - 114..121 'S::make': fn make, i64>() -> (S, i64) - 114..123 'S::make()': (S, i64) + 103..129 '{ ...e(); }': () + 113..114 'a': (S, i64) + 117..124 'S::make': fn make, i64>() -> (S, i64) + 117..126 'S::make()': (S, i64) "#]], ); } @@ -600,7 +600,7 @@ fn infer_trait_assoc_method_generics_4() { trait Trait { fn make() -> (Self, T); } - struct S; + struct S(T); impl Trait for S {} impl Trait for S {} fn test() { @@ -609,13 +609,13 @@ fn infer_trait_assoc_method_generics_4() { } "#, expect![[r#" - 130..202 '{ ...e(); }': () - 140..141 'a': (S, i64) - 157..164 'S::make': fn make, i64>() -> (S, i64) - 157..166 'S::make()': (S, i64) - 176..177 'b': (S, i32) - 190..197 'S::make': fn make, i32>() -> (S, i32) - 190..199 'S::make()': (S, i32) + 133..205 '{ ...e(); }': () + 143..144 'a': (S, i64) + 160..167 'S::make': fn make, i64>() -> (S, i64) + 160..169 'S::make()': (S, i64) + 179..180 'b': (S, i32) + 193..200 'S::make': fn make, i32>() -> (S, i32) + 193..202 'S::make()': (S, i32) "#]], ); } @@ -627,7 +627,7 @@ fn infer_trait_assoc_method_generics_5() { trait Trait { fn make() -> (Self, T, U); } - struct S; + struct S(T); impl Trait for S {} fn test() { let a = >::make::(); @@ -635,13 +635,13 @@ fn infer_trait_assoc_method_generics_5() { } "#, expect![[r#" - 106..210 '{ ...>(); }': () - 116..117 'a': (S, i64, u8) - 120..149 '': fn make, i64, u8>() -> (S, i64, u8) - 120..151 '()': (S, i64, u8) - 161..162 'b': (S, i64, u8) - 181..205 'Trait:...::': fn make, i64, u8>() -> (S, i64, u8) - 181..207 'Trait:...()': (S, i64, u8) + 109..213 '{ ...>(); }': () + 119..120 'a': (S, i64, u8) + 123..152 '': fn make, i64, u8>() -> (S, i64, u8) + 123..154 '()': (S, i64, u8) + 164..165 'b': (S, i64, u8) + 184..208 'Trait:...::': fn make, i64, u8>() -> (S, i64, u8) + 184..210 'Trait:...()': (S, i64, u8) "#]], ); } @@ -1107,6 +1107,9 @@ fn method_resolution_slow() { // this can get quite slow if we set the solver size limit too high check_types( r#" +//- minicore: phantom_data +use core::marker::PhantomData; + trait SendX {} struct S1; impl SendX for S1 {} @@ -1115,17 +1118,17 @@ struct U1; trait Trait { fn method(self); } -struct X1 {} +struct X1(PhantomData<(A, B)>); impl SendX for X1 where A: SendX, B: SendX {} -struct S {} +struct S(PhantomData<(B, C)>); trait FnX {} impl Trait for S where C: FnX, B: SendX {} -fn test() { (S {}).method(); } - //^^^^^^^^^^^^^^^ () +fn test() { (S(PhantomData)).method(); } + //^^^^^^^^^^^^^^^^^^^^^^^^^ () "#, ); } @@ -1187,11 +1190,11 @@ fn test() { 89..109 '{ ... }': bool 99..103 'true': bool 123..167 '{ ...o(); }': () - 133..134 's': &'static S - 137..151 'unsafe { f() }': &'static S + 133..134 's': &'? S + 137..151 'unsafe { f() }': &'? S 146..147 'f': fn f() -> &'static S 146..149 'f()': &'static S - 157..158 's': &'static S + 157..158 's': &'? S 157..164 's.foo()': bool "#]], ); @@ -2191,9 +2194,9 @@ impl Receiver for Bar { fn main() { let bar = Bar; let _v1 = bar.foo1(); - //^^^ type: {unknown} + //^^^ type: i32 let _v2 = bar.foo2(); - //^^^ type: {unknown} + //^^^ type: bool } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index 6a9135622deb6..af5290d720356 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -14,6 +14,8 @@ fn test() { ); } +// FIXME(next-solver): The never type fallback implemented in r-a no longer works properly because of +// `Coerce` predicates. We should reimplement fallback like rustc. #[test] fn infer_never2() { check_types( @@ -24,7 +26,7 @@ fn test() { let a = gen(); if false { a } else { loop {} }; a; -} //^ ! +} //^ {unknown} "#, ); } @@ -39,7 +41,7 @@ fn test() { let a = gen(); if false { loop {} } else { a }; a; - //^ ! + //^ {unknown} } "#, ); @@ -54,7 +56,7 @@ enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; -} //^ Option +} //^ Option<{unknown}> "#, ); } @@ -104,7 +106,7 @@ enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; - //^ Option<&'static str> + //^ Option<&'? str> match 42 { 42 => a, _ => Option::Some("str"), @@ -218,7 +220,7 @@ fn test(a: i32) { _ => loop {}, }; i; -} //^ ! +} //^ {unknown} "#, ); } @@ -362,12 +364,12 @@ fn diverging_expression_3_break() { 140..141 'x': u32 149..175 '{ for ...; }; }': u32 151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 151..172 'for a ...eak; }': {unknown} + 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': ! 151..172 'for a ...eak; }': {unknown} 151..172 'for a ...eak; }': &'? mut {unknown} 151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 151..172 'for a ...eak; }': Option<{unknown}> + 151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item> 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () @@ -379,12 +381,12 @@ fn diverging_expression_3_break() { 226..227 'x': u32 235..253 '{ for ... {}; }': u32 237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 237..250 'for a in b {}': {unknown} + 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': ! 237..250 'for a in b {}': {unknown} 237..250 'for a in b {}': &'? mut {unknown} 237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 237..250 'for a in b {}': Option<{unknown}> + 237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item> 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () @@ -395,12 +397,12 @@ fn diverging_expression_3_break() { 304..305 'x': u32 313..340 '{ for ...; }; }': u32 315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 315..337 'for a ...urn; }': {unknown} + 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': ! 315..337 'for a ...urn; }': {unknown} 315..337 'for a ...urn; }': &'? mut {unknown} 315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 315..337 'for a ...urn; }': Option<{unknown}> + 315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item> 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs index 256ca7defb78a..40e4c28fcc0b9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs @@ -158,6 +158,7 @@ static ALIAS: i32 = { 191..193 '_a': impl Trait + ?Sized 205..211 'Struct': Struct 217..218 '5': i32 + 205..211: expected impl Trait + ?Sized, got Struct "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 02cb03706919b..607daada42eb1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -41,19 +41,19 @@ fn infer_pattern() { 47..48 'x': &'? i32 58..59 'a': i32 62..63 'z': i32 - 73..79 '(c, d)': (i32, &'static str) + 73..79 '(c, d)': (i32, &'? str) 74..75 'c': i32 - 77..78 'd': &'static str - 82..94 '(1, "hello")': (i32, &'static str) + 77..78 'd': &'? str + 82..94 '(1, "hello")': (i32, &'? str) 83..84 '1': i32 86..93 '"hello"': &'static str 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 101..151 'for (e... }': {unknown} + 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': ! 101..151 'for (e... }': {unknown} 101..151 'for (e... }': &'? mut {unknown} 101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 101..151 'for (e... }': Option<({unknown}, {unknown})> + 101..151 'for (e... }': Option<<{unknown} as Iterator>::Item> 101..151 'for (e... }': () 101..151 'for (e... }': () 101..151 'for (e... }': () @@ -653,7 +653,7 @@ fn infer_generics_in_patterns() { fn infer_const_pattern() { check( r#" -enum Option { None } +enum Option { None, Some(T) } use Option::None; struct Foo; const Bar: usize = 1; @@ -719,28 +719,28 @@ fn test() { 51..58 'loop {}': ! 56..58 '{}': () 72..171 '{ ... x); }': () - 78..81 'foo': fn foo<&'? (i32, &'static str), i32, impl FnOnce(&'? (i32, &'static str)) -> i32>(&'? (i32, &'static str), impl FnOnce(&'? (i32, &'static str)) -> i32) -> i32 + 78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32 78..105 'foo(&(...y)| x)': i32 - 82..91 '&(1, "a")': &'? (i32, &'static str) - 83..91 '(1, "a")': (i32, &'static str) + 82..91 '&(1, "a")': &'? (i32, &'? str) + 83..91 '(1, "a")': (i32, &'? str) 84..85 '1': i32 87..90 '"a"': &'static str - 93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'static str)) -> i32 - 94..101 '&(x, y)': &'? (i32, &'static str) - 95..101 '(x, y)': (i32, &'static str) + 93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32 + 94..101 '&(x, y)': &'? (i32, &'? str) + 95..101 '(x, y)': (i32, &'? str) 96..97 'x': i32 - 99..100 'y': &'static str + 99..100 'y': &'? str 103..104 'x': i32 - 142..145 'foo': fn foo<&'? (i32, &'static str), &'? i32, impl FnOnce(&'? (i32, &'static str)) -> &'? i32>(&'? (i32, &'static str), impl FnOnce(&'? (i32, &'static str)) -> &'? i32) -> &'? i32 + 142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32 142..168 'foo(&(...y)| x)': &'? i32 - 146..155 '&(1, "a")': &'? (i32, &'static str) - 147..155 '(1, "a")': (i32, &'static str) + 146..155 '&(1, "a")': &'? (i32, &'? str) + 147..155 '(1, "a")': (i32, &'? str) 148..149 '1': i32 151..154 '"a"': &'static str - 157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'static str)) -> &'? i32 - 158..164 '(x, y)': (i32, &'static str) + 157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32 + 158..164 '(x, y)': (i32, &'? str) 159..160 'x': &'? i32 - 162..163 'y': &'? &'static str + 162..163 'y': &'? &'? str 166..167 'x': &'? i32 "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 6a3f2286215f4..2ba1e2341b297 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -88,6 +88,7 @@ fn bug_651() { #[test] fn recursive_vars() { + // FIXME: This isn't nice, but I guess as long as we don't hang/crash that's fine? check_infer( r#" fn test() { @@ -97,12 +98,12 @@ fn recursive_vars() { "#, expect![[r#" 10..47 '{ ...&y]; }': () - 20..21 'y': {unknown} - 24..31 'unknown': {unknown} - 37..44 '[y, &y]': [{unknown}; 2] - 38..39 'y': {unknown} - 41..43 '&y': &'? {unknown} - 42..43 'y': {unknown} + 20..21 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 24..31 'unknown': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 37..44 '[y, &y]': [&'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}; 2] + 38..39 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 41..43 '&y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 42..43 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} "#]], ); } @@ -119,19 +120,19 @@ fn recursive_vars_2() { "#, expect![[r#" 10..79 '{ ...x)]; }': () - 20..21 'x': &'? {unknown} - 24..31 'unknown': &'? {unknown} - 41..42 'y': {unknown} - 45..52 'unknown': {unknown} - 58..76 '[(x, y..., &x)]': [(&'? {unknown}, {unknown}); 2] - 59..65 '(x, y)': (&'? {unknown}, {unknown}) - 60..61 'x': &'? {unknown} - 63..64 'y': {unknown} - 67..75 '(&y, &x)': (&'? {unknown}, {unknown}) - 68..70 '&y': &'? {unknown} - 69..70 'y': {unknown} - 72..74 '&x': &'? &'? {unknown} - 73..74 'x': &'? {unknown} + 20..21 'x': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 24..31 'unknown': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 41..42 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 45..52 'unknown': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 58..76 '[(x, y..., &x)]': [(&'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}, &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}); 2] + 59..65 '(x, y)': (&'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}, &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}) + 60..61 'x': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 63..64 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 67..75 '(&y, &x)': (&'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}, &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown}) + 68..70 '&y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 69..70 'y': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 72..74 '&x': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 73..74 'x': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} "#]], ); } @@ -268,37 +269,37 @@ fn infer_std_crash_5() { expect![[r#" 26..322 '{ ... } }': () 32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter - 32..320 'for co... }': {unknown} + 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter 32..320 'for co... }': ! 32..320 'for co... }': {unknown} 32..320 'for co... }': &'? mut {unknown} 32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 32..320 'for co... }': Option<{unknown}> + 32..320 'for co... }': Option<<{unknown} as Iterator>::Item> 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () - 36..43 'content': {unknown} + 36..43 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 47..60 'doesnt_matter': {unknown} 61..320 '{ ... }': () - 75..79 'name': &'? {unknown} - 82..166 'if doe... }': &'? {unknown} + 75..79 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 82..166 'if doe... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 85..98 'doesnt_matter': bool - 99..128 '{ ... }': &'? {unknown} - 113..118 'first': &'? {unknown} - 134..166 '{ ... }': &'? {unknown} - 148..156 '&content': &'? {unknown} - 149..156 'content': {unknown} - 181..188 'content': &'? {unknown} - 191..313 'if ICE... }': &'? {unknown} - 194..231 'ICE_RE..._VALUE': {unknown} + 99..128 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 113..118 'first': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 134..166 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 148..156 '&content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 149..156 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 181..188 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 191..313 'if ICE... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 194..231 'ICE_RE..._VALUE': bool 194..247 'ICE_RE...&name)': bool - 241..246 '&name': &'? &'? {unknown} - 242..246 'name': &'? {unknown} - 248..276 '{ ... }': &'? {unknown} - 262..266 'name': &'? {unknown} - 282..313 '{ ... }': {unknown} - 296..303 'content': {unknown} + 241..246 '&name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 242..246 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 248..276 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 262..266 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 282..313 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 296..303 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} "#]], ); } @@ -394,7 +395,7 @@ fn issue_2669() { r#" trait A {} trait Write {} - struct Response {} + struct Response(T); trait D { fn foo(); @@ -410,13 +411,13 @@ fn issue_2669() { } "#, expect![[r#" - 119..214 '{ ... }': () - 129..132 'end': fn end<{unknown}>() - 129..134 'end()': () - 163..208 '{ ... }': () - 181..183 '_x': ! - 190..197 'loop {}': ! - 195..197 '{}': () + 120..215 '{ ... }': () + 130..133 'end': fn end<{unknown}>() + 130..135 'end()': () + 164..209 '{ ... }': () + 182..184 '_x': ! + 191..198 'loop {}': ! + 196..198 '{}': () "#]], ) } @@ -628,7 +629,7 @@ fn issue_4053_diesel_where_clauses() { 65..69 'self': Self 267..271 'self': Self 466..470 'self': SelectStatement - 488..522 '{ ... }': () + 488..522 '{ ... }': as BoxedDsl>::Output 498..502 'self': SelectStatement 498..508 'self.order': O 498..515 'self.o...into()': dyn QueryFragment + '? @@ -799,7 +800,7 @@ fn issue_4966() { struct Map { f: F } - struct Vec {} + struct Vec { p: *mut T } impl core::ops::Deref for Vec { type Target = [T]; @@ -818,23 +819,23 @@ fn issue_4966() { } "#, expect![[r#" - 225..229 'iter': T - 244..246 '{}': Vec - 258..402 '{ ...r(); }': () - 268..273 'inner': Map f64> - 276..300 'Map { ... 0.0 }': Map f64> - 285..298 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64 - 286..287 '_': &'? f64 - 295..298 '0.0': f64 - 311..317 'repeat': Repeat f64>> - 320..345 'Repeat...nner }': Repeat f64>> - 338..343 'inner': Map f64> - 356..359 'vec': Vec<{unknown}> - 362..371 'from_iter': fn from_iter<{unknown}, Repeat f64>>>(Repeat f64>>) -> Vec<{unknown}> - 362..379 'from_i...epeat)': Vec<{unknown}> - 372..378 'repeat': Repeat f64>> - 386..389 'vec': Vec<{unknown}> - 386..399 'vec.foo_bar()': {unknown} + 236..240 'iter': T + 255..257 '{}': Vec + 269..413 '{ ...r(); }': () + 279..284 'inner': Map f64> + 287..311 'Map { ... 0.0 }': Map f64> + 296..309 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64 + 297..298 '_': &'? f64 + 306..309 '0.0': f64 + 322..328 'repeat': Repeat f64>> + 331..356 'Repeat...nner }': Repeat f64>> + 349..354 'inner': Map f64> + 367..370 'vec': Vec<{unknown}> + 373..382 'from_iter': fn from_iter<{unknown}, Repeat f64>>>(Repeat f64>>) -> Vec<{unknown}> + 373..390 'from_i...epeat)': Vec<{unknown}> + 383..389 'repeat': Repeat f64>> + 397..400 'vec': Vec<{unknown}> + 397..410 'vec.foo_bar()': {unknown} "#]], ); } @@ -843,37 +844,40 @@ fn issue_4966() { fn issue_6628() { check_infer( r#" -//- minicore: fn -struct S(); +//- minicore: fn, phantom_data +use core::marker::PhantomData; + +struct S(PhantomData); impl S { fn f(&self, _t: T) {} fn g(&self, _f: F) {} } fn main() { - let s = S(); + let s = S(PhantomData); s.g(|_x| {}); s.f(10); } "#, expect![[r#" - 40..44 'self': &'? S - 46..48 '_t': T - 53..55 '{}': () - 81..85 'self': &'? S - 87..89 '_f': F - 94..96 '{}': () - 109..160 '{ ...10); }': () - 119..120 's': S - 123..124 'S': fn S() -> S - 123..126 'S()': S - 132..133 's': S - 132..144 's.g(|_x| {})': () - 136..143 '|_x| {}': impl FnOnce(&'? i32) - 137..139 '_x': &'? i32 - 141..143 '{}': () - 150..151 's': S - 150..157 's.f(10)': () - 154..156 '10': i32 + 86..90 'self': &'? S + 92..94 '_t': T + 99..101 '{}': () + 127..131 'self': &'? S + 133..135 '_f': F + 140..142 '{}': () + 155..217 '{ ...10); }': () + 165..166 's': S + 169..170 'S': fn S(PhantomData) -> S + 169..183 'S(PhantomData)': S + 171..182 'PhantomData': PhantomData + 189..190 's': S + 189..201 's.g(|_x| {})': () + 193..200 '|_x| {}': impl FnOnce(&'? i32) + 194..196 '_x': &'? i32 + 198..200 '{}': () + 207..208 's': S + 207..214 's.f(10)': () + 211..213 '10': i32 "#]], ); } @@ -931,7 +935,7 @@ fn lifetime_from_chalk_during_deref() { check_types( r#" //- minicore: deref -struct Box {} +struct Box(T); impl core::ops::Deref for Box { type Target = T; @@ -964,6 +968,9 @@ fn clone_iter(s: Iter) { fn issue_8686() { check_infer( r#" +//- minicore: phantom_data +use core::marker::PhantomData; + pub trait Try: FromResidual { type Output; type Residual; @@ -972,28 +979,32 @@ pub trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; } -struct ControlFlow; +struct ControlFlow(PhantomData<(B, C)>); impl Try for ControlFlow { type Output = C; type Residual = ControlFlow; } impl FromResidual for ControlFlow { - fn from_residual(r: ControlFlow) -> Self { ControlFlow } + fn from_residual(r: ControlFlow) -> Self { ControlFlow(PhantomData) } } fn test() { - ControlFlow::from_residual(ControlFlow::); + ControlFlow::from_residual(ControlFlow::(PhantomData)); } "#, expect![[r#" - 144..152 'residual': R - 365..366 'r': ControlFlow - 395..410 '{ ControlFlow }': ControlFlow - 397..408 'ControlFlow': ControlFlow - 424..482 '{ ...!>); }': () - 430..456 'Contro...sidual': fn from_residual, ControlFlow>(ControlFlow) -> ControlFlow - 430..479 'Contro...2, !>)': ControlFlow - 457..478 'Contro...32, !>': ControlFlow + 176..184 'residual': R + 418..419 'r': ControlFlow + 448..476 '{ Cont...ata) }': ControlFlow + 450..461 'ControlFlow': fn ControlFlow(PhantomData<(B, C)>) -> ControlFlow + 450..474 'Contro...mData)': ControlFlow + 462..473 'PhantomData': PhantomData<(B, C)> + 490..561 '{ ...a)); }': () + 496..522 'Contro...sidual': fn from_residual, ControlFlow>(ControlFlow) -> ControlFlow + 496..558 'Contro...Data))': ControlFlow + 523..544 'Contro...32, !>': fn ControlFlow(PhantomData<(u32, !)>) -> ControlFlow + 523..557 'Contro...mData)': ControlFlow + 545..556 'PhantomData': PhantomData<(u32, !)> "#]], ); } @@ -1052,12 +1063,13 @@ fn impl_trait_in_option_9530() { check_types( r#" //- minicore: sized -struct Option; +struct Option(T); impl Option { fn unwrap(self) -> T { loop {} } } -fn make() -> Option { Option } +fn make() -> Option { Option(()) } trait Copy {} +impl Copy for () {} fn test() { let o = make(); o.unwrap(); @@ -1163,9 +1175,9 @@ pub trait BitView { pub struct Lsb0; -pub struct BitArray { } +pub struct BitArray(V); -pub struct BitSlice { } +pub struct BitSlice(T); impl core::ops::Deref for BitArray { type Target = BitSlice; @@ -1243,12 +1255,12 @@ fn test() { expect![[r#" 10..68 '{ ... } }': () 16..66 'for _ ... }': fn into_iter<()>(()) -> <() as IntoIterator>::IntoIter - 16..66 'for _ ... }': {unknown} + 16..66 'for _ ... }': <() as IntoIterator>::IntoIter 16..66 'for _ ... }': ! - 16..66 'for _ ... }': {unknown} - 16..66 'for _ ... }': &'? mut {unknown} + 16..66 'for _ ... }': <() as IntoIterator>::IntoIter + 16..66 'for _ ... }': &'? mut <() as IntoIterator>::IntoIter 16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> - 16..66 'for _ ... }': Option<{unknown}> + 16..66 'for _ ... }': Option<<{unknown} as Iterator>::Item> 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () @@ -1779,7 +1791,7 @@ fn regression_14844() { r#" pub type Ty = Unknown; -pub struct Inner(); +pub struct Inner(T); pub struct Outer { pub inner: Inner, @@ -1787,7 +1799,7 @@ pub struct Outer { fn main() { _ = Outer { - inner: Inner::(), + inner: Inner::(0), }; } "#, @@ -1939,7 +1951,7 @@ fn main() { Alias::Braced; //^^^^^^^^^^^^^ {unknown} let Alias::Braced = loop {}; - //^^^^^^^^^^^^^ ! + //^^^^^^^^^^^^^ {unknown} let Alias::Braced(..) = loop {}; //^^^^^^^^^^^^^^^^^ Enum @@ -2017,12 +2029,12 @@ fn tait_async_stack_overflow_17199() { fn lifetime_params_move_param_defaults() { check_types( r#" -pub struct Thing<'s, T = u32>; +pub struct Thing<'s, T = u32>(&'s T); impl <'s> Thing<'s> { pub fn new() -> Thing<'s> { - Thing - //^^^^^ Thing<'?, u32> + Thing(&0) + //^^^^^^^^^ Thing<'?, u32> } } @@ -2042,11 +2054,11 @@ fn issue_17734() { r#" fn test() { let x = S::foo::<'static, &()>(&S); - // ^ Wrap<'static, ()> + // ^ Wrap<'?, ()> let x = S::foo::<&()>(&S); // ^ Wrap<'?, ()> let x = S.foo::<'static, &()>(); - // ^ Wrap<'static, ()> + // ^ Wrap<'?, ()> let x = S.foo::<&()>(); // ^ Wrap<'?, ()> } @@ -2059,7 +2071,7 @@ impl S { } } -struct Wrap<'a, T>(T); +struct Wrap<'a, T>(&'a T); trait Trait<'a> { type Proj; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 82d670cef2b0e..ead79a8f5b90b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -307,3 +307,114 @@ where "#]], ) } + +#[test] +fn fn_coercion() { + check_no_mismatches( + r#" +fn foo() { + let _is_suffix_start: fn(&(usize, char)) -> bool = match true { + true => |(_, c)| *c == ' ', + _ => |(_, c)| *c == 'v', + }; +} + "#, + ); +} + +#[test] +fn coercion_with_errors() { + check_no_mismatches( + r#" +//- minicore: unsize, coerce_unsized +fn foo(_v: i32) -> [u8; _] { loop {} } +fn bar(_v: &[u8]) {} + +fn main() { + bar(&foo()); +} + "#, + ); +} + +#[test] +fn another_20654_case() { + check_no_mismatches( + r#" +//- minicore: sized, unsize, coerce_unsized, dispatch_from_dyn, fn +struct Region<'db>(&'db ()); + +trait TypeFoldable {} + +trait Interner { + type Region; + type GenericArg; +} + +struct DbInterner<'db>(&'db ()); +impl<'db> Interner for DbInterner<'db> { + type Region = Region<'db>; + type GenericArg = GenericArg<'db>; +} + +trait GenericArgExt> { + fn expect_region(&self) -> I::Region { + loop {} + } +} +impl<'db> GenericArgExt> for GenericArg<'db> {} + +enum GenericArg<'db> { + Region(Region<'db>), +} + +fn foo<'db, T: TypeFoldable>>(arg: GenericArg<'db>) { + let regions = &mut || arg.expect_region(); + let f: &'_ mut (dyn FnMut() -> Region<'db> + '_) = regions; +} + "#, + ); +} + +#[test] +fn trait_solving_with_error() { + check_infer( + r#" +//- minicore: size_of +struct Vec(T); + +trait Foo { + type Item; + fn to_vec(self) -> Vec { + loop {} + } +} + +impl<'a, T, const N: usize> Foo for &'a [T; N] { + type Item = T; +} + +fn to_bytes() -> [u8; _] { + loop {} +} + +fn foo() { + let _x = to_bytes().to_vec(); +} + "#, + expect![[r#" + 60..64 'self': Self + 85..108 '{ ... }': Vec<::Item> + 95..102 'loop {}': ! + 100..102 '{}': () + 208..223 '{ loop {} }': [u8; _] + 214..221 'loop {}': ! + 219..221 '{}': () + 234..271 '{ ...c(); }': () + 244..246 '_x': {unknown} + 249..257 'to_bytes': fn to_bytes() -> [u8; _] + 249..259 'to_bytes()': [u8; _] + 249..268 'to_byt..._vec()': Vec<<[u8; _] as Foo>::Item> + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 60ad0f49c6ab0..9d02a44c37c97 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -439,11 +439,11 @@ h"; 256..260 'true': bool 274..370 'r#" ... "#': &'static str 384..394 'br#"yolo"#': &'static [u8; 4] - 412..413 'a': &'static [u8; 4] + 412..413 'a': &'? [u8; 4] 416..440 'b"a\x2... c"': &'static [u8; 4] - 458..459 'b': &'static [u8; 4] + 458..459 'b': &'? [u8; 4] 462..470 'br"g\ h"': &'static [u8; 4] - 488..489 'c': &'static [u8; 6] + 488..489 'c': &'? [u8; 6] 492..504 'br#"x"\"yb"#': &'static [u8; 6] "##]], ); @@ -1124,13 +1124,13 @@ fn infer_tuple() { 116..122 '(c, x)': ((isize, &'? str), &'? str) 117..118 'c': (isize, &'? str) 120..121 'x': &'? str - 132..133 'e': (i32, &'static str) - 136..144 '(1, "e")': (i32, &'static str) + 132..133 'e': (i32, &'? str) + 136..144 '(1, "e")': (i32, &'? str) 137..138 '1': i32 140..143 '"e"': &'static str - 154..155 'f': ((i32, &'static str), &'static str) - 158..166 '(e, "d")': ((i32, &'static str), &'static str) - 159..160 'e': (i32, &'static str) + 154..155 'f': ((i32, &'? str), &'? str) + 158..166 '(e, "d")': ((i32, &'? str), &'? str) + 159..160 'e': (i32, &'? str) 162..165 '"d"': &'static str "#]], ); @@ -1201,8 +1201,8 @@ fn infer_array() { 209..215 '[1, 2]': [i32; 2] 210..211 '1': i32 213..214 '2': i32 - 225..226 'i': [&'static str; 2] - 229..239 '["a", "b"]': [&'static str; 2] + 225..226 'i': [&'? str; 2] + 229..239 '["a", "b"]': [&'? str; 2] 230..233 '"a"': &'static str 235..238 '"b"': &'static str 250..251 'b': [[&'? str; 1]; 2] @@ -1283,11 +1283,11 @@ fn infer_tuple_struct_generics() { 92..93 'A': fn A(u128) -> A 92..101 'A(42u128)': A 94..100 '42u128': u128 - 107..111 'Some': fn Some<&'static str>(&'static str) -> Option<&'static str> - 107..116 'Some("x")': Option<&'static str> + 107..111 'Some': fn Some<&'? str>(&'? str) -> Option<&'? str> + 107..116 'Some("x")': Option<&'? str> 112..115 '"x"': &'static str - 122..134 'Option::Some': fn Some<&'static str>(&'static str) -> Option<&'static str> - 122..139 'Option...e("x")': Option<&'static str> + 122..134 'Option::Some': fn Some<&'? str>(&'? str) -> Option<&'? str> + 122..139 'Option...e("x")': Option<&'? str> 135..138 '"x"': &'static str 145..149 'None': Option<{unknown}> 159..160 'x': Option @@ -1946,9 +1946,9 @@ fn closure_return_inferred() { "#, expect![[r#" 16..46 '{ ..." }; }': u32 - 26..27 'x': impl Fn() -> &'static str - 30..43 '|| { "test" }': impl Fn() -> &'static str - 33..43 '{ "test" }': &'static str + 26..27 'x': impl Fn() -> &'? str + 30..43 '|| { "test" }': impl Fn() -> &'? str + 33..43 '{ "test" }': &'? str 35..41 '"test"': &'static str "#]], ); @@ -1983,10 +1983,10 @@ fn test() { 70..71 'v': i64 78..80 '{}': () 91..362 '{ ... } }': () - 101..106 'mut g': |usize| yields i64 -> &'static str - 109..218 '|r| { ... }': |usize| yields i64 -> &'static str + 101..106 'mut g': |usize| yields i64 -> &'? str + 109..218 '|r| { ... }': |usize| yields i64 -> &'? str 110..111 'r': usize - 113..218 '{ ... }': &'static str + 113..218 '{ ... }': &'? str 127..128 'a': usize 131..138 'yield 0': usize 137..138 '0': i64 @@ -1998,20 +1998,20 @@ fn test() { 187..188 '2': i64 198..212 '"return value"': &'static str 225..360 'match ... }': () - 231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str> - 231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str> - 231..262 'Pin::n...usize)': CoroutineState - 240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str - 245..246 'g': |usize| yields i64 -> &'static str + 231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'? str>(&'? mut |usize| yields i64 -> &'? str) -> Pin<&'? mut |usize| yields i64 -> &'? str> + 231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'? str> + 231..262 'Pin::n...usize)': CoroutineState + 240..246 '&mut g': &'? mut |usize| yields i64 -> &'? str + 245..246 'g': |usize| yields i64 -> &'? str 255..261 '0usize': usize - 273..299 'Corout...ded(y)': CoroutineState + 273..299 'Corout...ded(y)': CoroutineState 297..298 'y': i64 303..312 '{ f(y); }': () 305..306 'f': fn f(i64) 305..309 'f(y)': () 307..308 'y': i64 - 321..348 'Corout...ete(r)': CoroutineState - 346..347 'r': &'static str + 321..348 'Corout...ete(r)': CoroutineState + 346..347 'r': &'? str 352..354 '{}': () "#]], ); @@ -2707,11 +2707,11 @@ unsafe impl Allocator for Global {} #[lang = "owned_box"] #[fundamental] -pub struct Box; +pub struct Box(T, A); impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} -pub struct Vec {} +pub struct Vec(T, A); #[lang = "slice"] impl [T] {} @@ -2734,22 +2734,22 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 604..608 'self': Box<[T], A> - 637..669 '{ ... }': Vec - 683..853 '{ ...])); }': () - 693..696 'vec': Vec - 699..714 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 699..745 '<[_]>:...i32]))': Vec - 715..744 '#[rust...1i32])': Box<[i32; 1], Global> - 737..743 '[1i32]': [i32; 1] - 738..742 '1i32': i32 - 755..756 'v': Vec, Global> - 776..793 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 776..850 '<[_]> ...ct)]))': Vec, Global> - 794..849 '#[rust...uct)])': Box<[Box; 1], Global> - 816..848 '[#[rus...ruct)]': [Box; 1] - 817..847 '#[rust...truct)': Box - 839..846 'Astruct': Astruct + 614..618 'self': Box<[T], A> + 647..679 '{ ... }': Vec + 693..863 '{ ...])); }': () + 703..706 'vec': Vec + 709..724 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec + 709..755 '<[_]>:...i32]))': Vec + 725..754 '#[rust...1i32])': Box<[i32; 1], Global> + 747..753 '[1i32]': [i32; 1] + 748..752 '1i32': i32 + 765..766 'v': Vec, Global> + 786..803 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 786..860 '<[_]> ...ct)]))': Vec, Global> + 804..859 '#[rust...uct)])': Box<[Box; 1], Global> + 826..858 '[#[rus...ruct)]': [Box; 1] + 827..857 '#[rust...truct)': Box + 849..856 'Astruct': Astruct "#]], ) } @@ -3889,9 +3889,9 @@ fn main() { 74..75 'f': F 80..82 '{}': () 94..191 '{ ... }); }': () - 100..113 'async_closure': fn async_closure impl Future>(impl AsyncFnOnce(i32) -> impl Future) + 100..113 'async_closure': fn async_closure(impl FnOnce(i32)) 100..147 'async_... })': () - 114..146 'async ... }': impl AsyncFnOnce(i32) -> impl Future + 114..146 'async ... }': impl FnOnce(i32) 121..124 'arg': i32 126..146 '{ ... }': () 136..139 'arg': i32 @@ -3924,7 +3924,7 @@ fn foo() { expect![[r#" 110..127 '{ ...z(); }': () 116..122 'T::baz': fn baz() -> <{unknown} as Foo>::Gat<'?> - 116..124 'T::baz()': {unknown} + 116..124 'T::baz()': <{unknown} as Foo>::Gat<'?> "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 22332fdc2b8aa..41f8d4ed555f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -85,6 +85,7 @@ async fn test() { } #[test] +#[ignore = "FIXME(next-solver): fix async closures"] fn infer_async_closure() { check_types( r#" @@ -164,16 +165,16 @@ unsafe impl Allocator for Global {} #[lang = "owned_box"] #[fundamental] -pub struct Box(T); +pub struct Box(T, A); impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} fn send() -> Box + Send + 'static>{ - Box(async move {}) + Box(async move {}, Global) } fn not_send() -> Box + 'static> { - Box(async move {}) + Box(async move {}, Global) } "#, ); @@ -248,15 +249,15 @@ fn test() { v.push("foo"); for x in v { x; - } //^ &'static str + } //^ &'? str } //- /alloc.rs crate:alloc #![no_std] pub mod collections { - pub struct Vec {} + pub struct Vec { p: *const T } impl Vec { - pub fn new() -> Self { Vec {} } + pub fn new() -> Self { Vec { p: 0 as _ } } pub fn push(&mut self, t: T) { } } @@ -722,8 +723,8 @@ fn deref_trait_with_inference_var() { check_types( r#" //- minicore: deref -struct Arc; -fn new_arc() -> Arc { Arc } +struct Arc(T); +fn new_arc() -> Arc { loop {} } impl core::ops::Deref for Arc { type Target = T; } @@ -785,13 +786,15 @@ fn test(s: Arc) { fn deref_trait_with_implicit_sized_requirement_on_inference_var() { check_types( r#" -//- minicore: deref -struct Foo; +//- minicore: deref, phantom_data +use core::marker::PhantomData; + +struct Foo(PhantomData); impl core::ops::Deref for Foo { type Target = (); } fn test() { - let foo = Foo; + let foo = Foo(PhantomData); *foo; //^^^^ () let _: Foo = foo; @@ -1456,7 +1459,7 @@ trait Trait { fn foo2(&self) -> i64; } -struct Box {} +struct Box(*const T); impl core::ops::Deref for Box { type Target = T; } @@ -1477,27 +1480,27 @@ fn test(x: Box>, y: &dyn Trait) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 198..200 '{}': Box + '?> - 210..211 'x': Box + '?> - 234..235 'y': &'? (dyn Trait + '?) - 254..371 '{ ...2(); }': () - 260..261 'x': Box + '?> - 267..268 'y': &'? (dyn Trait + '?) - 278..279 'z': Box + '?> - 282..285 'bar': fn bar() -> Box + '?> - 282..287 'bar()': Box + '?> - 293..294 'x': Box + '?> - 293..300 'x.foo()': u64 - 306..307 'y': &'? (dyn Trait + '?) - 306..313 'y.foo()': u64 - 319..320 'z': Box + '?> - 319..326 'z.foo()': u64 - 332..333 'x': Box + '?> - 332..340 'x.foo2()': i64 - 346..347 'y': &'? (dyn Trait + '?) - 346..354 'y.foo2()': i64 - 360..361 'z': Box + '?> - 360..368 'z.foo2()': i64 + 206..208 '{}': Box + '?> + 218..219 'x': Box + '?> + 242..243 'y': &'? (dyn Trait + '?) + 262..379 '{ ...2(); }': () + 268..269 'x': Box + '?> + 275..276 'y': &'? (dyn Trait + '?) + 286..287 'z': Box + '?> + 290..293 'bar': fn bar() -> Box + '?> + 290..295 'bar()': Box + '?> + 301..302 'x': Box + '?> + 301..308 'x.foo()': u64 + 314..315 'y': &'? (dyn Trait + '?) + 314..321 'y.foo()': u64 + 327..328 'z': Box + '?> + 327..334 'z.foo()': u64 + 340..341 'x': Box + '?> + 340..348 'x.foo2()': i64 + 354..355 'y': &'? (dyn Trait + '?) + 354..362 'y.foo2()': i64 + 368..369 'z': Box + '?> + 368..376 'z.foo2()': i64 "#]], ); } @@ -1674,7 +1677,9 @@ fn test(x: (impl Trait + UnknownTrait)) { fn assoc_type_bindings() { check_infer( r#" -//- minicore: sized +//- minicore: sized, phantom_data +use core::marker::PhantomData; + trait Trait { type Type; } @@ -1683,7 +1688,7 @@ fn get(t: T) -> ::Type {} fn get2>(t: T) -> U {} fn set>(t: T) -> T {t} -struct S; +struct S(PhantomData); impl Trait for S { type Type = T; } fn test>(x: T, y: impl Trait) { @@ -1691,46 +1696,52 @@ fn test>(x: T, y: impl Trait) { get2(x); get(y); get2(y); - get(set(S)); - get2(set(S)); - get2(S::); + get(set(S(PhantomData))); + get2(set(S(PhantomData))); + get2(S::(PhantomData)); }"#, expect![[r#" - 49..50 't': T - 77..79 '{}': ::Type - 111..112 't': T - 122..124 '{}': U - 154..155 't': T - 165..168 '{t}': T - 166..167 't': T - 256..257 'x': T - 262..263 'y': impl Trait - 289..399 '{ ...e>); }': () - 295..298 'get': fn get(T) -> ::Type - 295..301 'get(x)': u32 - 299..300 'x': T - 307..311 'get2': fn get2(T) -> u32 - 307..314 'get2(x)': u32 - 312..313 'x': T - 320..323 'get': fn get>(impl Trait) -> as Trait>::Type - 320..326 'get(y)': i64 - 324..325 'y': impl Trait - 332..336 'get2': fn get2>(impl Trait) -> i64 - 332..339 'get2(y)': i64 - 337..338 'y': impl Trait - 345..348 'get': fn get>(S) -> as Trait>::Type - 345..356 'get(set(S))': u64 - 349..352 'set': fn set>(S) -> S - 349..355 'set(S)': S - 353..354 'S': S - 362..366 'get2': fn get2>(S) -> u64 - 362..374 'get2(set(S))': u64 - 367..370 'set': fn set>(S) -> S - 367..373 'set(S)': S - 371..372 'S': S - 380..384 'get2': fn get2>(S) -> usize - 380..396 'get2(S...size>)': usize - 385..395 'S::': S + 81..82 't': T + 109..111 '{}': ::Type + 143..144 't': T + 154..156 '{}': U + 186..187 't': T + 197..200 '{t}': T + 198..199 't': T + 304..305 'x': T + 310..311 'y': impl Trait + 337..486 '{ ...a)); }': () + 343..346 'get': fn get(T) -> ::Type + 343..349 'get(x)': u32 + 347..348 'x': T + 355..359 'get2': fn get2(T) -> u32 + 355..362 'get2(x)': u32 + 360..361 'x': T + 368..371 'get': fn get>(impl Trait) -> as Trait>::Type + 368..374 'get(y)': i64 + 372..373 'y': impl Trait + 380..384 'get2': fn get2>(impl Trait) -> i64 + 380..387 'get2(y)': i64 + 385..386 'y': impl Trait + 393..396 'get': fn get>(S) -> as Trait>::Type + 393..417 'get(se...ata)))': u64 + 397..400 'set': fn set>(S) -> S + 397..416 'set(S(...Data))': S + 401..402 'S': fn S(PhantomData) -> S + 401..415 'S(PhantomData)': S + 403..414 'PhantomData': PhantomData + 423..427 'get2': fn get2>(S) -> u64 + 423..448 'get2(s...ata)))': u64 + 428..431 'set': fn set>(S) -> S + 428..447 'set(S(...Data))': S + 432..433 'S': fn S(PhantomData) -> S + 432..446 'S(PhantomData)': S + 434..445 'PhantomData': PhantomData + 454..458 'get2': fn get2>(S) -> usize + 454..483 'get2(S...Data))': usize + 459..469 'S::': fn S(PhantomData) -> S + 459..482 'S:: + 470..481 'PhantomData': PhantomData "#]], ); } @@ -1747,7 +1758,7 @@ pub enum RustLanguage {} impl Language for RustLanguage { type Kind = SyntaxKind; } -struct SyntaxNode {} +struct SyntaxNode(L); fn foo() -> impl Iterator> {} trait Clone { @@ -1886,31 +1897,36 @@ fn super_trait_cycle() { fn super_trait_assoc_type_bounds() { check_infer( r#" +//- minicore: phantom_data +use core::marker::PhantomData; + trait SuperTrait { type Type; } trait Trait where Self: SuperTrait {} fn get2>(t: T) -> U {} fn set>(t: T) -> T {t} -struct S; +struct S(PhantomData); impl SuperTrait for S { type Type = T; } impl Trait for S {} fn test() { - get2(set(S)); + get2(set(S(PhantomData))); }"#, expect![[r#" - 102..103 't': T - 113..115 '{}': U - 145..146 't': T - 156..159 '{t}': T - 157..158 't': T - 258..279 '{ ...S)); }': () - 264..268 'get2': fn get2>(S) -> u64 - 264..276 'get2(set(S))': u64 - 269..272 'set': fn set>(S) -> S - 269..275 'set(S)': S - 273..274 'S': S + 134..135 't': T + 145..147 '{}': U + 177..178 't': T + 188..191 '{t}': T + 189..190 't': T + 306..340 '{ ...))); }': () + 312..316 'get2': fn get2>(S) -> u64 + 312..337 'get2(s...ata)))': u64 + 317..320 'set': fn set>(S) -> S + 317..336 'set(S(...Data))': S + 321..322 'S': fn S(PhantomData) -> S + 321..335 'S(PhantomData)': S + 323..334 'PhantomData': PhantomData "#]], ); } @@ -2000,7 +2016,7 @@ impl Foo { fn foo(&self) -> usize {} } -struct Lazy T>(F); +struct Lazy T>(T, F); impl Lazy { pub fn new(f: F) -> Lazy {} @@ -2014,7 +2030,7 @@ fn test() { let lazy1: Lazy = Lazy::new(|| Foo); let r1 = lazy1.foo(); - fn make_foo_fn() -> Foo {} +fn make_foo_fn() -> Foo {} let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; let lazy2: Lazy = Lazy::new(make_foo_fn_ptr); let r2 = lazy2.foo(); @@ -2022,27 +2038,27 @@ fn test() { expect![[r#" 36..40 'self': &'? Foo 51..53 '{}': usize - 131..132 'f': F - 151..153 '{}': Lazy - 251..497 '{ ...o(); }': () - 261..266 'lazy1': Lazy Foo> - 283..292 'Lazy::new': fn new Foo>(impl Fn() -> Foo) -> Lazy Foo> - 283..300 'Lazy::...| Foo)': Lazy Foo> - 293..299 '|| Foo': impl Fn() -> Foo - 296..299 'Foo': Foo - 310..312 'r1': usize - 315..320 'lazy1': Lazy Foo> - 315..326 'lazy1.foo()': usize - 368..383 'make_foo_fn_ptr': fn() -> Foo - 399..410 'make_foo_fn': fn make_foo_fn() -> Foo - 420..425 'lazy2': Lazy Foo> - 442..451 'Lazy::new': fn new Foo>(fn() -> Foo) -> Lazy Foo> - 442..468 'Lazy::...n_ptr)': Lazy Foo> - 452..467 'make_foo_fn_ptr': fn() -> Foo - 478..480 'r2': usize - 483..488 'lazy2': Lazy Foo> - 483..494 'lazy2.foo()': usize - 357..359 '{}': Foo + 134..135 'f': F + 154..156 '{}': Lazy + 254..496 '{ ...o(); }': () + 264..269 'lazy1': Lazy Foo> + 286..295 'Lazy::new': fn new Foo>(impl Fn() -> Foo) -> Lazy Foo> + 286..303 'Lazy::...| Foo)': Lazy Foo> + 296..302 '|| Foo': impl Fn() -> Foo + 299..302 'Foo': Foo + 313..315 'r1': usize + 318..323 'lazy1': Lazy Foo> + 318..329 'lazy1.foo()': usize + 367..382 'make_foo_fn_ptr': fn() -> Foo + 398..409 'make_foo_fn': fn make_foo_fn() -> Foo + 419..424 'lazy2': Lazy Foo> + 441..450 'Lazy::new': fn new Foo>(fn() -> Foo) -> Lazy Foo> + 441..467 'Lazy::...n_ptr)': Lazy Foo> + 451..466 'make_foo_fn_ptr': fn() -> Foo + 477..479 'r2': usize + 482..487 'lazy2': Lazy Foo> + 482..493 'lazy2.foo()': usize + 356..358 '{}': Foo "#]], ); } @@ -2341,7 +2357,7 @@ trait Fold { type Result; } -struct Ty {} +struct Ty(I); impl Fold for Ty { type Result = Ty; } @@ -2383,17 +2399,20 @@ fn test() { fn trait_impl_self_ty_cycle() { check_types( r#" +//- minicore: phantom_data +use core::marker::PhantomData; + trait Trait { fn foo(&self); } -struct S; +struct S(T); impl Trait for S {} fn test() { - S.foo(); -} //^^^^^^^ {unknown} + S(PhantomData).foo(); +} //^^^^^^^^^^^^^^^^^^^^ {unknown} "#, ); } @@ -2743,7 +2762,7 @@ fn dyn_trait_through_chalk() { check_types( r#" //- minicore: deref, unsize, dispatch_from_dyn -struct Box {} +struct Box(*const T); impl core::ops::Deref for Box { type Target = T; } @@ -2802,7 +2821,7 @@ pub trait IntoIterator { fn into_iter(self) -> Self::IntoIter; } -pub struct FilterMap { } +pub struct FilterMap(I, F); impl Iterator for FilterMap where F: FnMut(I::Item) -> Option, @@ -2820,7 +2839,7 @@ impl IntoIterator for I { } } -struct Vec {} +struct Vec(T); impl Vec { fn new() -> Self { loop {} } } @@ -2830,7 +2849,7 @@ impl IntoIterator for Vec { type IntoIter = IntoIter; } -pub struct IntoIter { } +pub struct IntoIter(T); impl Iterator for IntoIter { type Item = T; } @@ -2852,35 +2871,35 @@ fn main() { 242..249 'loop {}': ! 247..249 '{}': () 360..364 'self': Self - 689..693 'self': I - 700..720 '{ ... }': I - 710..714 'self': I - 779..790 '{ loop {} }': Vec - 781..788 'loop {}': ! - 786..788 '{}': () - 977..1104 '{ ... }); }': () - 983..998 'Vec::::new': fn new() -> Vec - 983..1000 'Vec::<...:new()': Vec - 983..1012 'Vec::<...iter()': IntoIter - 983..1075 'Vec::<...one })': FilterMap, impl FnMut(i32) -> Option> - 983..1101 'Vec::<... y; })': () - 1029..1074 '|x| if...None }': impl FnMut(i32) -> Option - 1030..1031 'x': i32 - 1033..1074 'if x >...None }': Option - 1036..1037 'x': i32 - 1036..1041 'x > 0': bool - 1040..1041 '0': i32 - 1042..1060 '{ Some...u32) }': Option - 1044..1048 'Some': fn Some(u32) -> Option - 1044..1058 'Some(x as u32)': Option - 1049..1050 'x': i32 - 1049..1057 'x as u32': u32 - 1066..1074 '{ None }': Option - 1068..1072 'None': Option - 1090..1100 '|y| { y; }': impl FnMut(u32) - 1091..1092 'y': u32 - 1094..1100 '{ y; }': () - 1096..1097 'y': u32 + 692..696 'self': I + 703..723 '{ ... }': I + 713..717 'self': I + 783..794 '{ loop {} }': Vec + 785..792 'loop {}': ! + 790..792 '{}': () + 981..1108 '{ ... }); }': () + 987..1002 'Vec::::new': fn new() -> Vec + 987..1004 'Vec::<...:new()': Vec + 987..1016 'Vec::<...iter()': IntoIter + 987..1079 'Vec::<...one })': FilterMap, impl FnMut(i32) -> Option> + 987..1105 'Vec::<... y; })': () + 1033..1078 '|x| if...None }': impl FnMut(i32) -> Option + 1034..1035 'x': i32 + 1037..1078 'if x >...None }': Option + 1040..1041 'x': i32 + 1040..1045 'x > 0': bool + 1044..1045 '0': i32 + 1046..1064 '{ Some...u32) }': Option + 1048..1052 'Some': fn Some(u32) -> Option + 1048..1062 'Some(x as u32)': Option + 1053..1054 'x': i32 + 1053..1061 'x as u32': u32 + 1070..1078 '{ None }': Option + 1072..1076 'None': Option + 1094..1104 '|y| { y; }': impl FnMut(u32) + 1095..1096 'y': u32 + 1098..1104 '{ y; }': () + 1100..1101 'y': u32 "#]], ); } @@ -3134,7 +3153,6 @@ fn foo() { #[test] fn dyn_fn_param_informs_call_site_closure_signature() { - cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature); check_types( r#" //- minicore: fn, coerce_unsized, dispatch_from_dyn @@ -3617,7 +3635,7 @@ impl Add<&i32> for i32 { type Output = i32 } impl Add for u32 { type Output = u32 } impl Add<&u32> for u32 { type Output = u32 } -struct V; +struct V(T); impl V { fn default() -> Self { loop {} } fn get(&self, _: &T) -> &T { loop {} } @@ -3646,7 +3664,7 @@ impl Add<&i32> for i32 { type Output = i32; } // fallback to integer type variable for `42`. impl Add<&()> for i32 { type Output = (); } -struct V; +struct V(T); impl V { fn default() -> Self { loop {} } fn get(&self) -> &T { loop {} } @@ -4213,21 +4231,21 @@ fn f(v: impl Trait) { } fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); - //^ &'a T + //^ &'? T let a = v.get::<()>(); //^ = &'a T> as Trait>::Assoc<()> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); - //^ &'a i32 + //^ &'? i32 let a = v.get::(); - //^ &'a i64 + //^ &'? i64 } fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { let a = v.get::(); - //^ &'a i32 + //^ &'? i32 let a = v.get::(); - //^ &'a i64 + //^ &'? i64 } "#, ); @@ -4257,8 +4275,8 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { 127..128 'v': &'? (dyn Trait = &'a i32> + '?) 164..195 '{ ...f(); }': () 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': {unknown} - 170..192 'v.get:...eref()': &'? {unknown} + 170..184 'v.get::()': = &'a i32> + '? as Trait>::Assoc + 170..192 'v.get:...eref()': {unknown} "#]], ); } @@ -4485,7 +4503,9 @@ impl Trait for () { fn derive_macro_bounds() { check_types( r#" - //- minicore: clone, derive + //- minicore: clone, derive, phantom_data + use core::marker::PhantomData; + #[derive(Clone)] struct Copy; struct NotCopy; @@ -4508,7 +4528,7 @@ fn derive_macro_bounds() { struct AssocGeneric3(Generic); #[derive(Clone)] - struct Vec(); + struct Vec(PhantomData); #[derive(Clone)] struct R1(Vec); @@ -4532,9 +4552,9 @@ fn derive_macro_bounds() { let x: &AssocGeneric3 = &AssocGeneric3(Generic(NotCopy)); let x = x.clone(); //^ &'? AssocGeneric3 - let x = (&R1(Vec())).clone(); + let x = (&R1(Vec(PhantomData))).clone(); //^ R1 - let x = (&R2(R1(Vec()))).clone(); + let x = (&R2(R1(Vec(PhantomData)))).clone(); //^ R2 } "#, @@ -4624,8 +4644,10 @@ fn ttt() { fn infer_borrow() { check_types( r#" -//- minicore: index -pub struct SomeMap; +//- minicore: index, phantom_data +use core::marker::PhantomData; + +pub struct SomeMap(PhantomData); pub trait Borrow { fn borrow(&self) -> &Borrowed; @@ -4658,7 +4680,7 @@ impl core::ops::IndexMut for SomeMap { } fn foo() { - let mut map = SomeMap; + let mut map = SomeMap(PhantomData); map["a"] = (); map; //^^^ SomeMap<&'static str> @@ -4908,6 +4930,7 @@ fn main() { #[test] fn async_fn_return_type() { + // FIXME(next-solver): Async closures are lowered as closures currently. We should fix that. check_infer( r#" //- minicore: async_fn @@ -4925,9 +4948,9 @@ fn main() { 46..53 'loop {}': ! 51..53 '{}': () 67..97 '{ ...()); }': () - 73..76 'foo': fn foo impl Future, ()>(impl AsyncFn() -> impl Future) + 73..76 'foo': fn foo(impl Fn()) 73..94 'foo(as...|| ())': () - 77..93 'async ... || ()': impl AsyncFn() -> impl Future + 77..93 'async ... || ()': impl Fn() 91..93 '()': () "#]], ); @@ -5020,7 +5043,7 @@ fn main() { 223..227 'iter': Box + 'static> 273..280 'loop {}': ! 278..280 '{}': () - 290..291 '_': Box + 'static> + 290..291 '_': Box + '?> 294..298 'iter': Box + 'static> 294..310 'iter.i...iter()': Box + 'static> 152..156 'self': &'? mut Box diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index a6377243ed984..d73d7da4b9b98 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -428,9 +428,4 @@ impl FnTrait { pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { self.lang_item().resolve_trait(db, krate) } - - #[inline] - pub(crate) fn is_async(self) -> bool { - matches!(self, FnTrait::AsyncFn | FnTrait::AsyncFnMut | FnTrait::AsyncFnOnce) - } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 07679d2a119d3..427c4bb68423d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -20,14 +20,14 @@ use hir_expand::name::Name; use intern::sym; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; -use rustc_type_ir::inherent::{IntoKind, SliceLike}; +use rustc_type_ir::inherent::{GenericArgs, IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use span::Edition; -use stdx::never; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ - ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TargetFeatures, TraitRef, - TraitRefExt, Ty, WhereClause, + ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef, + TraitRefExt, Ty, consteval::unknown_const, db::HirDatabase, layout::{Layout, TagEncoding}, @@ -120,52 +120,6 @@ impl Iterator for SuperTraits<'_> { } } -pub(super) fn elaborate_clause_supertraits( - db: &dyn HirDatabase, - clauses: impl Iterator, -) -> ClauseElaborator<'_> { - let mut elaborator = ClauseElaborator { db, stack: Vec::new(), seen: FxHashSet::default() }; - elaborator.extend_deduped(clauses); - - elaborator -} - -pub(super) struct ClauseElaborator<'a> { - db: &'a dyn HirDatabase, - stack: Vec, - seen: FxHashSet, -} - -impl ClauseElaborator<'_> { - fn extend_deduped(&mut self, clauses: impl IntoIterator) { - self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone()))) - } - - fn elaborate_supertrait(&mut self, clause: &WhereClause) { - if let WhereClause::Implemented(trait_ref) = clause { - direct_super_trait_refs(self.db, trait_ref, |t| { - let clause = WhereClause::Implemented(t); - if self.seen.insert(clause.clone()) { - self.stack.push(clause); - } - }); - } - } -} - -impl Iterator for ClauseElaborator<'_> { - type Item = WhereClause; - - fn next(&mut self) -> Option { - if let Some(next) = self.stack.pop() { - self.elaborate_supertrait(&next); - Some(next) - } else { - None - } - } -} - fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = LazyCell::new(|| trait_.resolver(db)); let (generic_params, store) = db.generic_params_and_store(trait_.into()); @@ -239,34 +193,25 @@ pub(super) fn associated_type_by_name_including_super_traits( }) } -/// It is a bit different from the rustc equivalent. Currently it stores: -/// - 0..n-1: generics of the parent -/// - n: the function signature, encoded as a function pointer type -/// -/// and it doesn't store the closure types and fields. -/// -/// Codes should not assume this ordering, and should always use methods available -/// on this struct for retrieving, and `TyBuilder::substs_for_closure` for creating. pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution); impl<'a> ClosureSubst<'a> { - pub(crate) fn parent_subst(&self) -> &'a [GenericArg] { - match self.0.as_slice(Interner) { - [x @ .., _] => x, - _ => { - never!("Closure missing parameter"); - &[] - } - } + pub(crate) fn parent_subst(&self, db: &dyn HirDatabase) -> Substitution { + let interner = DbInterner::new_with(db, None, None); + let subst = + >>::to_nextsolver( + self.0, interner, + ); + subst.split_closure_args().parent_args.to_chalk(interner) } - pub(crate) fn sig_ty(&self) -> &'a Ty { - match self.0.as_slice(Interner) { - [.., x] => x.assert_ty_ref(Interner), - _ => { - unreachable!("Closure missing sig_ty parameter"); - } - } + pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty { + let interner = DbInterner::new_with(db, None, None); + let subst = + >>::to_nextsolver( + self.0, interner, + ); + subst.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.to_chalk(interner) } } @@ -278,8 +223,17 @@ pub enum Unsafety { DeprecatedSafe2024, } -pub fn target_feature_is_safe_in_target(target: &TargetData) -> bool { - matches!(target.arch, target::Arch::Wasm32 | target::Arch::Wasm64) +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TargetFeatureIsSafeInTarget { + No, + Yes, +} + +pub fn target_feature_is_safe_in_target(target: &TargetData) -> TargetFeatureIsSafeInTarget { + match target.arch { + target::Arch::Wasm32 | target::Arch::Wasm64 => TargetFeatureIsSafeInTarget::Yes, + _ => TargetFeatureIsSafeInTarget::No, + } } pub fn is_fn_unsafe_to_call( @@ -287,14 +241,14 @@ pub fn is_fn_unsafe_to_call( func: FunctionId, caller_target_features: &TargetFeatures, call_edition: Edition, - target_feature_is_safe: bool, + target_feature_is_safe: TargetFeatureIsSafeInTarget, ) -> Unsafety { let data = db.function_signature(func); if data.is_unsafe() { return Unsafety::Unsafe; } - if data.has_target_feature() && !target_feature_is_safe { + if data.has_target_feature() && target_feature_is_safe == TargetFeatureIsSafeInTarget::No { // RFC 2396 . let callee_target_features = TargetFeatures::from_attrs_no_implications(&db.attrs(func.into())); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index a1ebff04bbd47..8593dba301b85 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -49,7 +49,23 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option { } "#, expect![[r#" - Hello['a: bivariant] - Other['a: bivariant] + Hello['a: invariant] + Other['a: invariant] "#]], ); } @@ -601,7 +618,7 @@ struct Foo { //~ ERROR [T: o] } "#, expect![[r#" - Foo[T: bivariant] + Foo[T: invariant] "#]], ); } @@ -683,9 +700,9 @@ struct TestBox+Setter> { //~ ERROR [U: *, T: +] get[Self: contravariant, T: covariant] get[Self: contravariant, T: contravariant] TestStruct[U: covariant, T: covariant] - TestEnum[U: bivariant, T: covariant] - TestContraStruct[U: bivariant, T: covariant] - TestBox[U: bivariant, T: covariant] + TestEnum[U: invariant, T: covariant] + TestContraStruct[U: invariant, T: covariant] + TestBox[U: invariant, T: covariant] "#]], ); } @@ -805,8 +822,8 @@ enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used trait SomeTrait<'a> { fn foo(&self); } // OK on traits. "#, expect![[r#" - SomeStruct['a: bivariant] - SomeEnum['a: bivariant] + SomeStruct['a: invariant] + SomeEnum['a: invariant] foo[Self: contravariant, 'a: invariant] "#]], ); @@ -834,14 +851,14 @@ struct DoubleNothing { "#, expect![[r#" - SomeStruct[A: bivariant] - SomeEnum[A: bivariant] - ListCell[T: bivariant] - SelfTyAlias[T: bivariant] - WithBounds[T: bivariant] - WithWhereBounds[T: bivariant] - WithOutlivesBounds[T: bivariant] - DoubleNothing[T: bivariant] + SomeStruct[A: invariant] + SomeEnum[A: invariant] + ListCell[T: invariant] + SelfTyAlias[T: invariant] + WithBounds[T: invariant] + WithWhereBounds[T: invariant] + WithOutlivesBounds[T: invariant] + DoubleNothing[T: invariant] "#]], ); } @@ -952,7 +969,7 @@ struct S3(S); "#, expect![[r#" S[T: covariant] - S2[T: bivariant] + S2[T: invariant] S3[T: covariant] "#]], ); @@ -965,7 +982,7 @@ struct S3(S); struct FixedPoint(&'static FixedPoint<(), T, U>, V); "#, expect![[r#" - FixedPoint[T: bivariant, U: bivariant, V: bivariant] + FixedPoint[T: invariant, U: invariant, V: invariant] "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index bd9360f30f165..3083b56515628 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2549,11 +2549,13 @@ impl Function { let target_feature_is_safe_in_target = match &caller.krate(db).id.workspace_data(db).target { Ok(target) => hir_ty::target_feature_is_safe_in_target(target), - Err(_) => false, + Err(_) => hir_ty::TargetFeatureIsSafeInTarget::No, }; (target_features, target_feature_is_safe_in_target) }) - .unwrap_or_else(|| (hir_ty::TargetFeatures::default(), false)); + .unwrap_or_else(|| { + (hir_ty::TargetFeatures::default(), hir_ty::TargetFeatureIsSafeInTarget::No) + }); matches!( hir_ty::is_fn_unsafe_to_call( db, @@ -4660,7 +4662,7 @@ impl Closure { .iter() .map(|capture| Type { env: db.trait_environment_for_body(owner), - ty: capture.ty(&self.subst), + ty: capture.ty(db, &self.subst), _pd: PhantomCovariantLifetime::new(), }) .collect() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 5f526ec899404..3dd435d9423b2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -805,6 +805,7 @@ impl A { ); } + #[ignore = "FIXME(next-solver): Fix async closures"] #[test] fn replaces_async_closure_with_async_fn() { check_assist( @@ -1066,7 +1067,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { *a = 1.2; let c = *b; } @@ -1098,7 +1099,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { let _: &mut bool = p2; *a = 1.2; let c = *b; @@ -1136,7 +1137,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { let _: &mut bool = p2; *a = 1.2; let c = *b; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index d88e3311bd7bf..3685cc904e947 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -5043,7 +5043,7 @@ fn main() { fun_name(bar); } -fn $0fun_name(bar: &'static str) { +fn $0fun_name(bar: &str) { m!(bar); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index b9ef68cc2d2a3..8b4f315ac5733 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1501,7 +1501,9 @@ fn main() { bar.$0 } "#, - expect![[r#""#]], + expect![[r#" + me foo() fn(self: Bar) + "#]], ); } 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 79137104b568d..5cc72ef845bf5 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 @@ -2011,7 +2011,7 @@ fn main() { en Enum Enum fn function() fn() fn main() fn() - lc variable &'static str + lc variable &str ma helper!(…) macro_rules! helper ma m!(…) macro_rules! m ma makro!(…) macro_rules! makro @@ -2486,6 +2486,7 @@ fn bar() { md rust_2024 (use core::prelude::rust_2024) tt Clone tt Copy + tt FromIterator tt IntoIterator tt Iterator ta Result (use core::fmt::Result) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 8d42770269057..542ac215f1cc6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -152,7 +152,7 @@ fn main() { fn main() { let mut x = t(); x = _; - //^ 💡 error: invalid `_` expression, expected type `&'static str` + //^ 💡 error: invalid `_` expression, expected type `&str` x = ""; } fn t() -> T { loop {} } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index dcca85d4db33e..bd5d134348e27 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -268,7 +268,7 @@ impl A { } fn main() { let a = A {a: 0, b: ""}; - A::::foo(); + A::::foo(); } "#, ); @@ -351,4 +351,26 @@ fn foo() { "#, ); } + + #[test] + fn iter_collect() { + check_diagnostics( + r#" +//- minicore: unsize, coerce_unsized, iterator, iterators, sized +struct Map(K, V); +impl FromIterator<(K, V)> for Map { + fn from_iter>(_iter: T) -> Self { + loop {} + } +} + +fn foo() -> Map { + [ + (123, &["abc", "def"] as _), + (456, &["ghi"] as _), + ].into_iter().collect() +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index a88c0c9866e5f..b623e51ee45e5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -7195,7 +7195,7 @@ fn foo() { "#, expect![[r#" ```rust - &'static str + &str ```"#]], ); } @@ -8459,7 +8459,7 @@ format_args!("{aaaaa$0}"); *aaaaa* ```rust - let aaaaa: &'static str + let aaaaa: &str ``` "#]], ); @@ -8479,7 +8479,7 @@ format_args!("{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &'static str + let aaaaa: &str ``` "#]], ); @@ -8499,7 +8499,7 @@ format_args!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &'static str + let aaaaa: &str ``` "#]], ); @@ -8524,7 +8524,7 @@ foo!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &'static str + let aaaaa: &str ``` "#]], ); @@ -10168,7 +10168,7 @@ fn baz() { --- - `U` = `i32`, `T` = `&'static str` + `U` = `i32`, `T` = `&str` "#]], ); } @@ -10261,7 +10261,7 @@ fn bar() { --- - `T` = `i8`, `U` = `&'static str` + `T` = `i8`, `U` = `&str` "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 7a4af4f7549c6..104740cbbf74a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -378,9 +378,9 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &'static dyn Fn(f64, f64) -> u32 + // ^^^ &dyn Fn(f64, f64) -> u32 let foo = foo5(); - // ^^^ &'static dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 let foo = foo6(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo7(); @@ -411,7 +411,7 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &'static dyn Fn(f64, f64) -> u32 + // ^^^ &dyn Fn(f64, f64) -> u32 let foo = foo5(); let foo = foo6(); let foo = foo7(); @@ -526,7 +526,7 @@ fn main() { //^^^^ i32 let _ = 22; let test = "test"; - //^^^^ &'static str + //^^^^ &str let test = InnerStruct {}; //^^^^ InnerStruct @@ -616,12 +616,12 @@ impl Iterator for IntoIter { fn main() { let mut data = Vec::new(); - //^^^^ Vec<&'static str> + //^^^^ Vec<&str> data.push("foo"); for i in data { - //^ &'static str + //^ &str let z = i; - //^ &'static str + //^ &str } } "#, @@ -1015,7 +1015,7 @@ fn test(t: T) { "#, expect![[r#" fn test(t: T) { - let f = |a: i32, b: &'static str, c: T| {}; + let f = |a: i32, b: &str, c: T| {}; let result: () = f(42, "", t); } "#]], 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 983ed3684a4f6..1db4f8ecd6bab 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -437,6 +437,7 @@ define_symbols! { rustc_safe_intrinsic, rustc_skip_array_during_method_dispatch, rustc_skip_during_method_dispatch, + rustc_force_inline, semitransparent, shl_assign, shl, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 1b940c70da66b..8a04bc7798f8b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -1061,7 +1061,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&'static str")); + assert!(res.to_string().contains("&str")); let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( @@ -1070,7 +1070,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&'static str")); + assert!(res.to_string().contains("&str")); server.request::( GotoDefinitionParams { 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 7c3e7fea1bdef..696928b522f94 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -169,6 +169,17 @@ pub mod marker { // region:phantom_data #[lang = "phantom_data"] pub struct PhantomData; + + // region:clone + impl Clone for PhantomData { + fn clone(&self) -> Self { Self } + } + // endregion:clone + + // region:copy + impl Copy for PhantomData {} + // endregion:copy + // endregion:phantom_data // region:discriminant @@ -1147,7 +1158,7 @@ pub mod fmt { pub struct Error; pub type Result = crate::result::Result<(), Error>; - pub struct Formatter<'a>; + pub struct Formatter<'a>(&'a ()); pub struct DebugTuple; pub struct DebugStruct; impl Formatter<'_> { @@ -1620,6 +1631,12 @@ pub mod iter { { loop {} } + fn collect>(self) -> B + where + Self: Sized, + { + loop {} + } // endregion:iterators } impl Iterator for &mut I { @@ -1689,10 +1706,13 @@ pub mod iter { loop {} } } + pub trait FromIterator: Sized { + fn from_iter>(iter: T) -> Self; + } } - pub use self::collect::IntoIterator; + pub use self::collect::{IntoIterator, FromIterator}; } - pub use self::traits::{IntoIterator, Iterator}; + pub use self::traits::{IntoIterator, FromIterator, Iterator}; } // endregion:iterator @@ -1988,7 +2008,7 @@ pub mod prelude { convert::AsRef, // :as_ref convert::{From, Into, TryFrom, TryInto}, // :from default::Default, // :default - iter::{IntoIterator, Iterator}, // :iterator + iter::{IntoIterator, Iterator, FromIterator}, // :iterator macros::builtin::{derive, derive_const}, // :derive marker::Copy, // :copy marker::Send, // :send diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs index f91192b0076ba..0462835f0675a 100644 --- a/src/tools/rust-analyzer/xtask/src/tidy.rs +++ b/src/tools/rust-analyzer/xtask/src/tidy.rs @@ -235,6 +235,10 @@ impl TidyDocs { return; } + if is_ported_from_rustc(path, &["crates/hir-ty/src/next_solver"]) { + return; + } + let first_line = match text.lines().next() { Some(it) => it, None => return, @@ -290,6 +294,11 @@ fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool { .any(|it| dirs_to_exclude.contains(&it)) } +fn is_ported_from_rustc(p: &Path, dirs_to_exclude: &[&str]) -> bool { + let p = p.strip_prefix(project_root()).unwrap(); + dirs_to_exclude.iter().any(|exclude| p.starts_with(exclude)) +} + #[derive(Default)] struct TidyMarks { hits: HashSet, From 487cdbc07d4bc73b8c52c7a35a99d2e0a64c6f55 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 16 Sep 2025 01:44:00 +0900 Subject: [PATCH 219/251] fix: More precise clause filtering for `explicit_*_predicates_of` --- .../crates/hir-ty/src/next_solver/interner.rs | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 7b6e8a1073d78..76d10f7dcc503 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1330,16 +1330,23 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::TraitId, ) -> EarlyBinder> { + let is_self = |ty: Ty<'db>| match ty.kind() { + rustc_type_ir::TyKind::Param(param) => param.index == 0, + _ => false, + }; + let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.0.into()) .iter() .filter(|p| match p.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(tr) => match tr.self_ty().kind() { - rustc_type_ir::TyKind::Param(param) => param.index == 0, - _ => false, - }, - _ => true, + // rustc has the following assertion: + // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608 + rustc_type_ir::ClauseKind::Trait(it) => is_self(it.self_ty()), + rustc_type_ir::ClauseKind::TypeOutlives(it) => is_self(it.0), + rustc_type_ir::ClauseKind::Projection(it) => is_self(it.self_ty()), + rustc_type_ir::ClauseKind::HostEffect(it) => is_self(it.self_ty()), + _ => false, }) .cloned() .map(|p| (p, Span::dummy())) @@ -1367,7 +1374,14 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .generic_predicates_ns(def_id.try_into().unwrap()) .iter() .filter(|p| match p.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(tr) => is_self_or_assoc(tr.self_ty()), + rustc_type_ir::ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()), + rustc_type_ir::ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0), + rustc_type_ir::ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()), + rustc_type_ir::ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()), + // FIXME: Not sure is this correct to allow other clauses but we might replace + // `generic_predicates_ns` query here with something closer to rustc's + // `implied_bounds_with_filter`, which is more granular lowering than this + // "lower at once and then filter" implementation. _ => true, }) .cloned() From 181bd119d07022db19b184ac23a796daa0e45246 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Sep 2025 08:25:28 +0200 Subject: [PATCH 220/251] fix: Fix expand macro recursively not working correctly for nested macro calls --- .../crates/ide/src/expand_macro.rs | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index ad84eacfb3e88..094a4a7036c40 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -1,5 +1,5 @@ use hir::db::ExpandDatabase; -use hir::{ExpandResult, InFile, InRealFile, Semantics}; +use hir::{ExpandResult, InFile, Semantics}; use ide_db::{ FileId, RootDatabase, base_db::Crate, helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, @@ -87,52 +87,55 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< return derive; } - let mut anc = sema - .descend_token_into_include_expansion(InRealFile::new(file_id, tok)) - .value - .parent_ancestors(); - let mut span_map = SpanMap::empty(); - let mut error = String::new(); - let (name, expanded, kind) = loop { - let node = anc.next()?; - - if let Some(item) = ast::Item::cast(node.clone()) - && let Some(def) = sema.resolve_attr_macro_call(&item) - { - break ( - def.name(db).display(db, file_id.edition(db)).to_string(), - expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, - SyntaxKind::MACRO_ITEMS, - ); - } - if let Some(mac) = ast::MacroCall::cast(node) { - let mut name = mac.path()?.segment()?.name_ref()?.to_string(); - name.push('!'); - let syntax_kind = - mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS); - break ( - name, - expand_macro_recur( - &sema, - &ast::Item::MacroCall(mac), - &mut error, - &mut span_map, - TextSize::new(0), - )?, - syntax_kind, - ); - } - }; + let syntax_token = sema.descend_into_macros_exact(tok); + 'tokens: for syntax_token in syntax_token { + let mut anc = syntax_token.parent_ancestors(); + let mut span_map = SpanMap::empty(); + let mut error = String::new(); + let (name, expanded, kind) = loop { + let Some(node) = anc.next() else { + continue 'tokens; + }; + + if let Some(item) = ast::Item::cast(node.clone()) + && let Some(def) = sema.resolve_attr_macro_call(&item) + { + break ( + def.name(db).display(db, file_id.edition(db)).to_string(), + expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, + SyntaxKind::MACRO_ITEMS, + ); + } + if let Some(mac) = ast::MacroCall::cast(node) { + let mut name = mac.path()?.segment()?.name_ref()?.to_string(); + name.push('!'); + let syntax_kind = + mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS); + break ( + name, + expand_macro_recur( + &sema, + &ast::Item::MacroCall(mac), + &mut error, + &mut span_map, + TextSize::new(0), + )?, + syntax_kind, + ); + } + }; - // FIXME: - // macro expansion may lose all white space information - // But we hope someday we can use ra_fmt for that - let mut expansion = format(db, kind, position.file_id, expanded, &span_map, krate); + // FIXME: + // macro expansion may lose all white space information + // But we hope someday we can use ra_fmt for that + let mut expansion = format(db, kind, position.file_id, expanded, &span_map, krate); - if !error.is_empty() { - expansion.insert_str(0, &format!("Expansion had errors:{error}\n\n")); + if !error.is_empty() { + expansion.insert_str(0, &format!("Expansion had errors:{error}\n\n")); + } + return Some(ExpandedMacro { name, expansion }); } - Some(ExpandedMacro { name, expansion }) + None } fn expand_macro_recur( @@ -752,8 +755,8 @@ fn test() { } "#, expect![[r#" - my_concat! - "<>hi""#]], + concat! + "<>""#]], ); } From 8a9ec5dd0dbf81e6337fb272aa0b90cf6e8d5655 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 23 Aug 2025 09:00:35 +0200 Subject: [PATCH 221/251] fix: Only compute unstable paths on nightly toolchains for IDE features --- .../crates/hir-def/src/find_path.rs | 8 ++-- .../rust-analyzer/crates/hir-def/src/lib.rs | 2 +- .../crates/hir-ty/src/display.rs | 4 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +-- .../rust-analyzer/crates/hir/src/semantics.rs | 7 ++++ .../crates/hir/src/term_search/expr.rs | 10 ++--- .../crates/ide-assists/src/assist_config.rs | 18 +++++++-- .../src/handlers/add_missing_match_arms.rs | 7 ++-- .../src/handlers/convert_bool_to_enum.rs | 37 ++++++++++--------- .../src/handlers/convert_into_to_from.rs | 2 +- .../convert_tuple_return_type_to_struct.rs | 3 +- .../handlers/destructure_struct_binding.rs | 3 +- .../src/handlers/extract_function.rs | 3 +- .../extract_struct_from_enum_variant.rs | 3 +- .../src/handlers/generate_deref.rs | 8 ++-- .../ide-assists/src/handlers/generate_new.rs | 3 +- .../generate_single_field_struct_from.rs | 7 +--- .../src/handlers/qualify_method_call.rs | 3 +- .../replace_derive_with_manual_impl.rs | 3 +- .../replace_qualified_name_with_use.rs | 9 ++--- .../ide-assists/src/handlers/term_search.rs | 2 +- .../src/handlers/toggle_async_sugar.rs | 7 +--- .../crates/ide-completion/src/completions.rs | 2 +- .../ide-completion/src/completions/expr.rs | 4 +- .../src/completions/flyimport.rs | 6 +-- .../ide-completion/src/completions/postfix.rs | 2 +- .../crates/ide-completion/src/config.rs | 19 ++++++++-- .../crates/ide-completion/src/render.rs | 2 +- .../crates/ide-completion/src/snippet.rs | 2 +- .../ide-db/src/imports/import_assets.rs | 21 ++++++++++- .../crates/ide-db/src/path_transform.rs | 10 ++--- .../src/handlers/json_is_not_rust.rs | 4 +- .../src/handlers/missing_fields.rs | 4 +- .../src/handlers/typed_hole.rs | 4 +- .../crates/ide-ssr/src/matching.rs | 4 +- .../rust-analyzer/src/cli/analysis_stats.rs | 6 +-- 36 files changed, 144 insertions(+), 101 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index faa0ef8ceec7b..e8a6ebcffa0a5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -12,7 +12,7 @@ use intern::sym; use rustc_hash::FxHashSet; use crate::{ - ImportPathConfig, ModuleDefId, ModuleId, + FindPathConfig, ModuleDefId, ModuleId, db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, @@ -27,7 +27,7 @@ pub fn find_path( from: ModuleId, mut prefix_kind: PrefixKind, ignore_local_imports: bool, - mut cfg: ImportPathConfig, + mut cfg: FindPathConfig, ) -> Option { let _p = tracing::info_span!("find_path").entered(); @@ -96,7 +96,7 @@ impl PrefixKind { struct FindPathCtx<'db> { db: &'db dyn DefDatabase, prefix: PrefixKind, - cfg: ImportPathConfig, + cfg: FindPathConfig, ignore_local_imports: bool, is_std_item: bool, from: ModuleId, @@ -718,7 +718,7 @@ mod tests { module, prefix, ignore_local_imports, - ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable }, + FindPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable }, ); format_to!( res, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 1f5b1e023702f..301d4cca0666c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -101,7 +101,7 @@ use crate::{ type FxIndexMap = indexmap::IndexMap; /// A wrapper around three booleans #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] -pub struct ImportPathConfig { +pub struct FindPathConfig { /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate /// over the std. pub prefer_no_std: bool, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index ae0113fcbd7f0..f3691b2e4f7e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -11,7 +11,7 @@ use base_db::Crate; use chalk_ir::{BoundVar, Safety, TyKind}; use either::Either; use hir_def::{ - GeneralConstId, GenericDefId, HasModule, ImportPathConfig, LocalFieldId, Lookup, ModuleDefId, + FindPathConfig, GeneralConstId, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, @@ -1433,7 +1433,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { PrefixKind::Plain, false, // FIXME: no_std Cfg? - ImportPathConfig { + FindPathConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f03f542e5bce3..4d1d8e2b15a9e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -130,7 +130,7 @@ pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ Complete, - ImportPathConfig, + FindPathConfig, attr::{AttrSourceMap, Attrs, AttrsWithOwner}, find_path::PrefixKind, import_map, @@ -957,7 +957,7 @@ impl Module { self, db: &dyn DefDatabase, item: impl Into, - cfg: ImportPathConfig, + cfg: FindPathConfig, ) -> Option { hir_def::find_path::find_path( db, @@ -976,7 +976,7 @@ impl Module { db: &dyn DefDatabase, item: impl Into, prefix_kind: PrefixKind, - cfg: ImportPathConfig, + cfg: FindPathConfig, ) -> Option { hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 6d6e08100b044..84f01da72f069 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -302,6 +302,13 @@ impl Semantics<'_, DB> { self.imp.hir_file_to_module_defs(file.into()) } + pub fn is_nightly(&self, krate: Crate) -> bool { + let toolchain = self.db.toolchain_channel(krate.into()); + // `toolchain == None` means we're in some detached files. Since we have no information on + // the toolchain being used, let's just allow unstable items to be listed. + matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None) + } + pub fn to_adt_def(&self, a: &ast::Adt) -> Option { self.imp.to_def(a) } diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index 78f534d014b90..e56f9e91e3f33 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -1,6 +1,6 @@ //! Type tree for term search -use hir_def::ImportPathConfig; +use hir_def::FindPathConfig; use hir_expand::mod_path::ModPath; use hir_ty::{ db::HirDatabase, @@ -18,7 +18,7 @@ use crate::{ fn mod_item_path( sema_scope: &SemanticsScope<'_>, def: &ModuleDef, - cfg: ImportPathConfig, + cfg: FindPathConfig, ) -> Option { let db = sema_scope.db; let m = sema_scope.module(); @@ -29,7 +29,7 @@ fn mod_item_path( fn mod_item_path_str( sema_scope: &SemanticsScope<'_>, def: &ModuleDef, - cfg: ImportPathConfig, + cfg: FindPathConfig, edition: Edition, ) -> Result { let path = mod_item_path(sema_scope, def, cfg); @@ -103,7 +103,7 @@ impl<'db> Expr<'db> { &self, sema_scope: &SemanticsScope<'db>, many_formatter: &mut dyn FnMut(&Type<'db>) -> String, - cfg: ImportPathConfig, + cfg: FindPathConfig, display_target: DisplayTarget, ) -> Result { let db = sema_scope.db; @@ -380,7 +380,7 @@ impl<'db> Expr<'db> { fn container_name( container: AssocItemContainer, sema_scope: &SemanticsScope<'_>, - cfg: ImportPathConfig, + cfg: FindPathConfig, edition: Edition, display_target: DisplayTarget, ) -> Result { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs index 57ced8d8534b2..597d035ebd857 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs @@ -4,8 +4,12 @@ //! module, and we use to statically check that we only produce snippet //! assists if we are allowed to. -use hir::ImportPathConfig; -use ide_db::{SnippetCap, assists::ExprFillDefaultMode, imports::insert_use::InsertUseConfig}; +use hir::FindPathConfig; +use ide_db::{ + SnippetCap, + assists::ExprFillDefaultMode, + imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig}, +}; use crate::AssistKind; @@ -31,7 +35,15 @@ impl AssistConfig { prefer_no_std: self.prefer_no_std, prefer_prelude: self.prefer_prelude, prefer_absolute: self.prefer_absolute, - allow_unstable: true, + } + } + + pub fn find_path_confg(&self, allow_unstable: bool) -> FindPathConfig { + FindPathConfig { + prefer_no_std: self.prefer_no_std, + prefer_prelude: self.prefer_prelude, + prefer_absolute: self.prefer_absolute, + allow_unstable, } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 1ece7ddab101e..4d3212c515f28 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -1,7 +1,7 @@ use std::iter::{self, Peekable}; use either::Either; -use hir::{Adt, AsAssocItem, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym}; +use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics, sym}; use ide_db::RootDatabase; use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; @@ -76,12 +76,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .filter(|pat| !matches!(pat, Pat::WildcardPat(_))) .collect(); - let cfg = ctx.config.import_path_config(); - let make = SyntaxFactory::with_mappings(); let scope = ctx.sema.scope(expr.syntax())?; let module = scope.module(); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(scope.krate())); let self_ty = if ctx.config.prefer_self_ty { scope .containing_function() @@ -498,7 +497,7 @@ fn build_pat( make: &SyntaxFactory, module: hir::Module, var: ExtendedVariant, - cfg: ImportPathConfig, + cfg: FindPathConfig, ) -> Option { let db = ctx.db(); match var { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index c208c8bf789a0..80445578fcef9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -329,8 +329,6 @@ fn augment_references_with_imports( ) -> Vec { let mut visited_modules = FxHashSet::default(); - let cfg = ctx.config.import_path_config(); - let edition = target_module.krate().edition(ctx.db()); references .into_iter() @@ -345,22 +343,27 @@ fn augment_references_with_imports( { visited_modules.insert(ref_module); - let import_scope = ImportScope::find_insert_use_container(name.syntax(), &ctx.sema); - let path = ref_module - .find_use_path( - ctx.sema.db, - ModuleDef::Module(*target_module), - ctx.config.insert_use.prefix_kind, - cfg, - ) - .map(|mod_path| { - make::path_concat( - mod_path_to_ast(&mod_path, edition), - make::path_from_text("Bool"), - ) - }); + ImportScope::find_insert_use_container(name.syntax(), &ctx.sema).and_then( + |import_scope| { + let cfg = + ctx.config.find_path_confg(ctx.sema.is_nightly(target_module.krate())); + let path = ref_module + .find_use_path( + ctx.sema.db, + ModuleDef::Module(*target_module), + ctx.config.insert_use.prefix_kind, + cfg, + ) + .map(|mod_path| { + make::path_concat( + mod_path_to_ast(&mod_path, edition), + make::path_from_text("Bool"), + ) + })?; - import_scope.zip(path) + Some((import_scope, path)) + }, + ) } else { None }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs index 3d9cde0e0a67c..3a464a3dc6aae 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -43,7 +43,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - return None; } - let cfg = ctx.config.import_path_config(); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let src_type_path = { let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 247c1011589bb..80ffb4db3e84d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -184,8 +184,6 @@ fn augment_references_with_imports( ) -> Vec<(ast::NameLike, Option<(ImportScope, ast::Path)>)> { let mut visited_modules = FxHashSet::default(); - let cfg = ctx.config.import_path_config(); - references .iter() .filter_map(|FileReference { name, .. }| { @@ -201,6 +199,7 @@ fn augment_references_with_imports( { visited_modules.insert(ref_module); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(ref_module.krate())); let import_scope = ImportScope::find_insert_use_container(new_name.syntax(), &ctx.sema); let path = ref_module diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index b8c647ac8b71d..397327cb4ff8c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -86,9 +86,8 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option) -> Op FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow(); if let Some(control_flow_enum) = control_flow_enum { + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let mod_path = module.find_use_path( ctx.sema.db, ModuleDef::from(control_flow_enum), ctx.config.insert_use.prefix_kind, - ctx.config.import_path_config(), + cfg, ); if let Some(mod_path) = mod_path { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index c56d0b3de5d6a..a5467e760bf39 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -400,11 +400,12 @@ fn process_references( let segment = builder.make_mut(segment); let scope_node = builder.make_syntax_mut(scope_node); if !visited_modules.contains(&module) { + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let mod_path = module.find_use_path( ctx.sema.db, *enum_module_def, ctx.config.insert_use.prefix_kind, - ctx.config.import_path_config(), + cfg, ); if let Some(mut mod_path) = mod_path { mod_path.pop_segment(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index 55a09c5d775d2..a1fc2c6023597 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -57,9 +57,9 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( }; let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; - let trait_path = - module.find_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.import_path_config())?; + let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?; let field_type = field.ty()?; let field_name = field.name()?; @@ -99,9 +99,9 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() }; let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; - let trait_path = - module.find_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.import_path_config())?; + let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?; let field_type = field.ty()?; let target = field.syntax().text_range(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index ac4a54a89ef1f..9760fd62aab4f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -77,10 +77,11 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?)); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(current_module.krate())); let type_path = current_module.find_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, - ctx.config.import_path_config(), + cfg, )?; let edition = current_module.krate().edition(ctx.db()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 943795d40d551..cad14d929648a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -169,6 +169,7 @@ fn make_constructors( types: &[ast::Type], ) -> Vec> { let (db, sema) = (ctx.db(), &ctx.sema); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); types .iter() .map(|ty| { @@ -179,11 +180,7 @@ fn make_constructors( let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into(); let edition = module.krate().edition(db); - let ty_path = module.find_path( - db, - item_for_path_search(db, item_in_ns)?, - ctx.config.import_path_config(), - )?; + let ty_path = module.find_path(db, item_for_path_search(db, item_in_ns)?, cfg)?; use_trivial_constructor(db, mod_path_to_ast(&ty_path, edition), &ty, edition) }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs index 985121780b1ab..e4494f0492ece 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -45,10 +45,11 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> let current_edition = current_module.krate().edition(ctx.db()); let target_module_def = ModuleDef::from(resolved_call); let item_in_ns = ItemInNs::from(target_module_def); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(current_module.krate())); let receiver_path = current_module.find_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, - ctx.config.import_path_config(), + cfg, )?; let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 175f261317058..25c5593007bcb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -71,6 +71,7 @@ pub(crate) fn replace_derive_with_manual_impl( let current_module = ctx.sema.scope(adt.syntax())?.module(); let current_crate = current_module.krate(); let current_edition = current_crate.edition(ctx.db()); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(current_crate)); let found_traits = items_locator::items_with_name( ctx.db(), @@ -84,7 +85,7 @@ pub(crate) fn replace_derive_with_manual_impl( }) .flat_map(|trait_| { current_module - .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config()) + .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), cfg) .as_ref() .map(|path| mod_path_to_ast(path, current_edition)) .zip(Some(trait_)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 9f742131e5cb4..5fc4d7a6170de 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -63,12 +63,9 @@ pub(crate) fn replace_qualified_name_with_use( ); let path_to_qualifier = starts_with_name_ref .then(|| { - ctx.sema.scope(original_path.syntax())?.module().find_use_path( - ctx.sema.db, - module, - ctx.config.insert_use.prefix_kind, - ctx.config.import_path_config(), - ) + let mod_ = ctx.sema.scope(original_path.syntax())?.module(); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(mod_.krate())); + mod_.find_use_path(ctx.sema.db, module, ctx.config.insert_use.prefix_kind, cfg) }) .flatten(); 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 6527d3706e217..209d3f08eb888 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 @@ -55,7 +55,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< path.gen_source_code( &scope, &mut formatter, - ctx.config.import_path_config(), + ctx.config.find_path_confg(ctx.sema.is_nightly(scope.module().krate())), scope.krate().to_display_target(ctx.db()), ) .ok() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs index eed070cb07dd6..aed66d3d8344c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -132,12 +132,9 @@ pub(crate) fn desugar_async_into_impl_future( let scope = ctx.sema.scope(function.syntax())?; let module = scope.module(); + let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(module.krate())); let future_trait = FamousDefs(&ctx.sema, scope.krate()).core_future_Future()?; - let trait_path = module.find_path( - ctx.db(), - ModuleDef::Trait(future_trait), - ctx.config.import_path_config(), - )?; + let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(future_trait), cfg)?; let edition = scope.krate().edition(ctx.db()); let trait_path = trait_path.display(ctx.db(), edition); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 11d26228ba201..e36e0e5704581 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -654,7 +654,7 @@ fn enum_variants_with_paths( if let Some(path) = ctx.module.find_path( ctx.db, hir::ModuleDef::from(variant), - ctx.config.import_path_config(ctx.is_nightly), + ctx.config.find_path_config(ctx.is_nightly), ) { // Variants with trivial paths are already added by the existing completion logic, // so we should avoid adding these twice diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 1972f166134a4..a5b8a0b1ceb6b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -254,7 +254,7 @@ pub(crate) fn complete_expr_path( .find_path( ctx.db, hir::ModuleDef::from(strukt), - ctx.config.import_path_config(ctx.is_nightly), + ctx.config.find_path_config(ctx.is_nightly), ) .filter(|it| it.len() > 1); @@ -276,7 +276,7 @@ pub(crate) fn complete_expr_path( .find_path( ctx.db, hir::ModuleDef::from(un), - ctx.config.import_path_config(ctx.is_nightly), + ctx.config.find_path_config(ctx.is_nightly), ) .filter(|it| it.len() > 1); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index dad8a76de87df..d1e05a4359f19 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -257,7 +257,7 @@ fn import_on_the_fly( }; let user_input_lowercased = potential_import_name.to_lowercase(); - let import_cfg = ctx.config.import_path_config(ctx.is_nightly); + let import_cfg = ctx.config.import_path_config(); import_assets .search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind) @@ -304,7 +304,7 @@ fn import_on_the_fly_pat_( ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)), }; let user_input_lowercased = potential_import_name.to_lowercase(); - let cfg = ctx.config.import_path_config(ctx.is_nightly); + let cfg = ctx.config.import_path_config(); import_assets .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind) @@ -346,7 +346,7 @@ fn import_on_the_fly_method( let user_input_lowercased = potential_import_name.to_lowercase(); - let cfg = ctx.config.import_path_config(ctx.is_nightly); + let cfg = ctx.config.import_path_config(); import_assets .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 0058611a61539..d355fdbe0739c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -63,7 +63,7 @@ pub(crate) fn complete_postfix( None => return, }; - let cfg = ctx.config.import_path_config(ctx.is_nightly); + let cfg = ctx.config.find_path_config(ctx.is_nightly); if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() && receiver_ty.impls_trait(ctx.db, drop_trait, &[]) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index 844fce5ef8019..b7367cb62f099 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -4,8 +4,11 @@ //! module, and we use to statically check that we only produce snippet //! completions if we are allowed to. -use hir::ImportPathConfig; -use ide_db::{SnippetCap, imports::insert_use::InsertUseConfig}; +use hir::FindPathConfig; +use ide_db::{ + SnippetCap, + imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig}, +}; use crate::{CompletionFieldsToResolve, snippet::Snippet}; @@ -59,12 +62,20 @@ impl CompletionConfig<'_> { .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip))) } - pub fn import_path_config(&self, allow_unstable: bool) -> ImportPathConfig { - ImportPathConfig { + pub fn find_path_config(&self, allow_unstable: bool) -> FindPathConfig { + FindPathConfig { prefer_no_std: self.prefer_no_std, prefer_prelude: self.prefer_prelude, prefer_absolute: self.prefer_absolute, allow_unstable, } } + + pub fn import_path_config(&self) -> ImportPathConfig { + ImportPathConfig { + prefer_no_std: self.prefer_no_std, + prefer_prelude: self.prefer_prelude, + prefer_absolute: self.prefer_absolute, + } + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 7d23f9d14c66f..dbf68dbe33afe 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -299,7 +299,7 @@ pub(crate) fn render_expr( .unwrap_or_else(|| String::from("...")) }; - let cfg = ctx.config.import_path_config(ctx.is_nightly); + let cfg = ctx.config.find_path_config(ctx.is_nightly); let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.display_target).ok()?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs index 9dc0c0234dc56..d326098f94071 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs @@ -164,7 +164,7 @@ impl Snippet { } fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option> { - let import_cfg = ctx.config.import_path_config(ctx.is_nightly); + let import_cfg = ctx.config.find_path_config(ctx.is_nightly); let resolve = |import| { let item = ctx.scope.resolve_mod_path(import).next()?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 1012f993344fe..0c235c8d9a57a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use hir::{ - AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, HasCrate, ImportPathConfig, + AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, FindPathConfig, HasCrate, ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Trait, TyFingerprint, Type, db::HirDatabase, }; @@ -19,6 +19,17 @@ use crate::{ items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT}, }; +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] +pub struct ImportPathConfig { + /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate + /// over the std. + pub prefer_no_std: bool, + /// If true, prefer import paths containing a prelude module. + pub prefer_prelude: bool, + /// If true, prefer abs path (starting with `::`) where it is available. + pub prefer_absolute: bool, +} + /// A candidate for import, derived during various IDE activities: /// * completion with imports on the fly proposals /// * completion edit resolve requests @@ -296,6 +307,12 @@ impl<'db> ImportAssets<'db> { Some(it) => it, None => return >::default().into_iter(), }; + let cfg = FindPathConfig { + prefer_no_std: cfg.prefer_no_std, + prefer_prelude: cfg.prefer_prelude, + prefer_absolute: cfg.prefer_absolute, + allow_unstable: sema.is_nightly(scope.krate()), + }; let db = sema.db; let krate = self.module_with_candidate.krate(); let scope_definitions = self.scope_definitions(sema); @@ -698,7 +715,7 @@ fn get_mod_path( item_to_search: ItemInNs, module_with_candidate: &Module, prefixed: Option, - cfg: ImportPathConfig, + cfg: FindPathConfig, ) -> Option { if let Some(prefix_kind) = prefixed { module_with_candidate.find_use_path(db, item_to_search, prefix_kind, cfg) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index a76a0551dd8db..4a27035afd091 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -3,7 +3,7 @@ use crate::helpers::mod_path_to_ast; use either::Either; use hir::{ - AsAssocItem, HirDisplay, HirFileId, ImportPathConfig, ModuleDef, SemanticsScope, + AsAssocItem, FindPathConfig, HirDisplay, HirFileId, ModuleDef, SemanticsScope, prettify_macro_expansion, }; use itertools::Itertools; @@ -392,7 +392,7 @@ impl Ctx<'_> { parent.segment()?.name_ref()?, ) .and_then(|trait_ref| { - let cfg = ImportPathConfig { + let cfg = FindPathConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false, @@ -452,7 +452,7 @@ impl Ctx<'_> { return None; } - let cfg = ImportPathConfig { + let cfg = FindPathConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false, @@ -501,7 +501,7 @@ impl Ctx<'_> { if let Some(adt) = ty.as_adt() && let ast::Type::PathType(path_ty) = &ast_ty { - let cfg = ImportPathConfig { + let cfg = FindPathConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false, @@ -546,7 +546,7 @@ impl Ctx<'_> { match resolution { hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => { - let cfg = ImportPathConfig { + let cfg = FindPathConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 742d614bc5673..2dfc2bb56595c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -1,7 +1,7 @@ //! This diagnostic provides an assist for creating a struct definition from a JSON //! example. -use hir::{ImportPathConfig, PathResolution, Semantics}; +use hir::{FindPathConfig, PathResolution, Semantics}; use ide_db::text_edit::TextEdit; use ide_db::{ EditionedFileId, FileRange, FxHashMap, RootDatabase, @@ -141,7 +141,7 @@ pub(crate) fn json_in_items( let scope = scb.make_import_scope_mut(import_scope); let current_module = semantics_scope.module(); - let cfg = ImportPathConfig { + let cfg = FindPathConfig { prefer_no_std: config.prefer_no_std, prefer_prelude: config.prefer_prelude, prefer_absolute: config.prefer_absolute, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 893bfca6a1298..49f925e2e0c93 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -1,6 +1,6 @@ use either::Either; use hir::{ - AssocItem, HirDisplay, ImportPathConfig, InFile, Type, + AssocItem, FindPathConfig, HirDisplay, InFile, Type, db::{ExpandDatabase, HirDatabase}, sym, }; @@ -132,7 +132,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option, d: &hir::TypedHole<'_>) -> Option Date: Thu, 7 Aug 2025 15:24:39 +0200 Subject: [PATCH 222/251] Workaround lsp-types typo --- .../crates/rust-analyzer/src/bin/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ab045e0bf9ff1..9bcf835b4cca7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -208,13 +208,24 @@ fn run_server() -> anyhow::Result<()> { tracing::info!("InitializeParams: {}", initialize_params); let lsp_types::InitializeParams { root_uri, - capabilities, + mut capabilities, workspace_folders, initialization_options, client_info, .. } = from_json::("InitializeParams", &initialize_params)?; + // lsp-types has a typo in the `/capabilities/workspace/diagnostics` field, its typoed as `diagnostic` + if let Some(val) = initialize_params.pointer("/capabilities/workspace/diagnostics") { + if let Ok(diag_caps) = from_json::( + "DiagnosticWorkspaceClientCapabilities", + val, + ) { + tracing::info!("Patching lsp-types workspace diagnostics capabilities: {diag_caps:#?}"); + capabilities.workspace.get_or_insert_default().diagnostic.get_or_insert(diag_caps); + } + } + let root_path = match root_uri .and_then(|it| it.to_file_path().ok()) .map(patch_path_prefix) From fd28cc8a1b2496ac9717d7185a40af123aaefafb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 7 Aug 2025 15:24:39 +0200 Subject: [PATCH 223/251] Add more workaround hacks for incorrect startup diagnostics --- .../crates/rust-analyzer/src/bin/main.rs | 12 ++++++------ .../crates/rust-analyzer/src/global_state.rs | 5 +++++ .../crates/rust-analyzer/src/handlers/dispatch.rs | 2 +- .../rust-analyzer/crates/rust-analyzer/src/reload.rs | 5 ++++- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 9bcf835b4cca7..e80f2953505f6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -216,14 +216,14 @@ fn run_server() -> anyhow::Result<()> { } = from_json::("InitializeParams", &initialize_params)?; // lsp-types has a typo in the `/capabilities/workspace/diagnostics` field, its typoed as `diagnostic` - if let Some(val) = initialize_params.pointer("/capabilities/workspace/diagnostics") { - if let Ok(diag_caps) = from_json::( + if let Some(val) = initialize_params.pointer("/capabilities/workspace/diagnostics") + && let Ok(diag_caps) = from_json::( "DiagnosticWorkspaceClientCapabilities", val, - ) { - tracing::info!("Patching lsp-types workspace diagnostics capabilities: {diag_caps:#?}"); - capabilities.workspace.get_or_insert_default().diagnostic.get_or_insert(diag_caps); - } + ) + { + tracing::info!("Patching lsp-types workspace diagnostics capabilities: {diag_caps:#?}"); + capabilities.workspace.get_or_insert_default().diagnostic.get_or_insert(diag_caps); } let root_path = match root_uri diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 2f1afba3634ef..89d6fb8edc2e6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -183,6 +183,10 @@ pub(crate) struct GlobalState { /// this queue should run only *after* [`GlobalState::process_changes`] has /// been called. pub(crate) deferred_task_queue: TaskQueue, + /// HACK: Workaround for https://github.com/rust-lang/rust-analyzer/issues/19709 + /// This is marked true if we failed to load a crate root file at crate graph creation, + /// which will usually end up causing a bunch of incorrect diagnostics on startup. + pub(crate) incomplete_crate_graph: bool, } /// An immutable snapshot of the world's state at a point in time. @@ -298,6 +302,7 @@ impl GlobalState { discover_workspace_queue: OpQueue::default(), deferred_task_queue: task_queue, + incomplete_crate_graph: false, }; // Apply any required database inputs from the config. this.update_configuration(config); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index b25245dd884a4..10bbb0bb31d99 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -141,7 +141,7 @@ impl RequestDispatcher<'_> { Result: Serialize, > + 'static, { - if !self.global_state.vfs_done { + if !self.global_state.vfs_done || self.global_state.incomplete_crate_graph { if let Some(lsp_server::Request { id, .. }) = self.req.take_if(|it| it.method == R::METHOD) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index a8a54930c6e5e..c15496b3f6cd2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -741,13 +741,16 @@ impl GlobalState { }) .collect(); + self.incomplete_crate_graph = false; let (crate_graph, proc_macro_paths) = { // Create crate graph from all the workspaces let vfs = &self.vfs.read().0; let load = |path: &AbsPath| { let vfs_path = vfs::VfsPath::from(path.to_path_buf()); self.crate_graph_file_dependencies.insert(vfs_path.clone()); - vfs.file_id(&vfs_path).and_then(|(file_id, excluded)| { + let file_id = vfs.file_id(&vfs_path); + self.incomplete_crate_graph |= file_id.is_none(); + file_id.and_then(|(file_id, excluded)| { (excluded == vfs::FileExcluded::No).then_some(file_id) }) }; From d23909d4d8aa2431df5ebc2fdeb2d967cd3c286d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Sep 2025 08:48:30 +0200 Subject: [PATCH 224/251] rustup --- src/tools/miri/rust-version | 2 +- src/tools/miri/tests/pass/shims/fs.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 8315eb30f9431..f27677cd50388 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a015919e54c60b1b2bec7a98dec478cfc4a48f4e +9d82de19dfae60e55c291f5f28e28cfc2c1b9630 diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 022dcc5dcbafa..0748007b3c058 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -28,7 +28,8 @@ fn main() { test_from_raw_os_error(); test_file_clone(); // Windows file handling is very incomplete. - if cfg!(not(windows)) { + // FIXME: read_dir broken on FreeBSD (https://github.com/rust-lang/miri/issues/4587) + if cfg!(not(windows)) && !cfg!(target_os = "freebsd") { test_file_set_len(); test_file_sync(); test_rename(); From f71f75669563cc9fb74c629937046c1f13d3698e Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 17 Sep 2025 03:03:00 +0900 Subject: [PATCH 225/251] Fix "sync-from-ra" for `rust-lang/rust` --- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 3 +++ src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 02fdbf0ebf0df..37d5347fe7ea1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -39,6 +39,9 @@ extern crate rustc_next_trait_solver; #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_data_structures as ena; + mod builder; mod chalk_db; mod chalk_ext; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 0225deebe4f31..99a501b05341c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -40,5 +40,8 @@ pub type AliasTy<'db> = rustc_type_ir::AliasTy>; pub type PolyFnSig<'db> = Binder<'db, rustc_type_ir::FnSig>>; pub type TypingMode<'db> = rustc_type_ir::TypingMode>; +#[cfg(feature = "in-rust-tree")] +use rustc_data_structure::sorted_map::index_map as indexmap; + pub type FxIndexMap = indexmap::IndexMap>; From 06e881042d3f58fdb60fde58de5bf112b2184b11 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 17 Sep 2025 04:52:58 +0000 Subject: [PATCH 226/251] Prepare for merging from rust-lang/rust This updates the rust-version file to 3f1552a273e43e15f6ed240d00e1efdd6a53e65e. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f27677cd50388..0eb16a943d6ab 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9d82de19dfae60e55c291f5f28e28cfc2c1b9630 +3f1552a273e43e15f6ed240d00e1efdd6a53e65e From ea8baccbb15fd58afcde959eed7dc73741dd626d Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 17 Sep 2025 12:35:21 +0000 Subject: [PATCH 227/251] rustc_codegen_llvm: Name major version of LLVM It makes LLVM version comparison clearer. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 8461c8b03d5a4..393361a1afe2a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -228,6 +228,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::with_dependencies( "sse4.2", @@ -260,7 +261,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version - ("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None, + ("loongarch32" | "loongarch64", "32s") if major < 21 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, From d9f67cbb8be4500ba73bb30177c05153cbc9424a Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 17 Sep 2025 12:35:21 +0000 Subject: [PATCH 228/251] rustc_codegen_llvm: Simplify `arch` conversion This commit simplifies construction of `arch` from `sess.target.arch`. It also preserves a reference to `sess.target.arch` as `raw_arch` to make this function future proof. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 393361a1afe2a..6849cd241644a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -217,16 +217,13 @@ impl<'a> IntoIterator for LLVMFeature<'a> { /// Rust can also be build with an external precompiled version of LLVM which might lead to failures /// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { - let arch = if sess.target.arch == "x86_64" { - "x86" - } else if sess.target.arch == "arm64ec" { - "aarch64" - } else if sess.target.arch == "sparc64" { - "sparc" - } else if sess.target.arch == "powerpc64" { - "powerpc" - } else { - &*sess.target.arch + let raw_arch = &*sess.target.arch; + let arch = match raw_arch { + "x86_64" => "x86", + "arm64ec" => "aarch64", + "sparc64" => "sparc", + "powerpc64" => "powerpc", + _ => raw_arch, }; let (major, _, _) = get_version(); match (arch, s) { From a1a3cd043815a8b6e5faf53f33002d8dec1b2f30 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 17 Sep 2025 12:35:21 +0000 Subject: [PATCH 229/251] rustc_codegen_llvm: Reorder conversion cases For maintainability, this commit reorders target feature conversion cases by the architecture. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6849cd241644a..45c5c9aa5514d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -227,15 +227,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::with_dependencies( - "sse4.2", - smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")], - )), - ("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")), - ("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")), - ("x86", "bmi1") => Some(LLVMFeature::new("bmi")), - ("x86", "cmpxchg16b") => Some(LLVMFeature::new("cx16")), - ("x86", "lahfsahf") => Some(LLVMFeature::new("sahf")), ("aarch64", "rcpc2") => Some(LLVMFeature::new("rcpc-immo")), ("aarch64", "dpb") => Some(LLVMFeature::new("ccpp")), ("aarch64", "dpb2") => Some(LLVMFeature::new("ccdp")), @@ -259,13 +250,22 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version ("loongarch32" | "loongarch64", "32s") if major < 21 => None, + ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")), + ("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")), + ("x86", "sse4.2") => Some(LLVMFeature::with_dependencies( + "sse4.2", + smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")], + )), + ("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")), + ("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")), + ("x86", "bmi1") => Some(LLVMFeature::new("bmi")), + ("x86", "cmpxchg16b") => Some(LLVMFeature::new("cx16")), + ("x86", "lahfsahf") => Some(LLVMFeature::new("sahf")), // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")], )), - ("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")), - ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")), ("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")), ("x86", "avx10.2") => Some(LLVMFeature::new("avx10.2-512")), ("x86", "apxf") => Some(LLVMFeature::with_dependencies( From 6e101637fa9485e71e77217ab32cbfb0f013e6e5 Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Wed, 17 Sep 2025 15:46:23 +0200 Subject: [PATCH 230/251] Add the `rust-analyzer.semanticHighlighting.comments.enable` configuration value --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 14 ++++++ .../crates/ide/src/syntax_highlighting.rs | 4 ++ .../ide/src/syntax_highlighting/html.rs | 42 +++++++++------- .../ide/src/syntax_highlighting/inject.rs | 2 + .../highlight_comments_disabled.html | 48 +++++++++++++++++++ .../ide/src/syntax_highlighting/tests.rs | 35 +++++++++++++- .../crates/rust-analyzer/src/config.rs | 8 ++++ .../docs/book/src/configuration_generated.md | 11 +++++ .../rust-analyzer/editors/code/package.json | 10 ++++ 9 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_comments_disabled.html diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index cddf5f04f2442..481c2312176b4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -703,6 +703,20 @@ impl Analysis { }) } + /// Computes syntax highlighting for the given file. + pub fn highlight_as_html_with_config( + &self, + config: HighlightConfig, + file_id: FileId, + rainbow: bool, + ) -> Cancellable { + // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database + // highlighting instead sets up the attach hook where neceesary for the trait solver + Cancelled::catch(|| { + syntax_highlighting::highlight_as_html_with_config(&self.db, config, file_id, rainbow) + }) + } + /// Computes syntax highlighting for the given file. pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index f98770805a451..4e43387f8d9da 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -35,6 +35,7 @@ use crate::{ }; pub(crate) use html::highlight_as_html; +pub(crate) use html::highlight_as_html_with_config; #[derive(Debug, Clone, Copy)] pub struct HlRange { @@ -47,6 +48,8 @@ pub struct HlRange { pub struct HighlightConfig { /// Whether to highlight strings pub strings: bool, + /// Whether to highlight comments + pub comments: bool, /// Whether to highlight punctuation pub punctuation: bool, /// Whether to specialize punctuation highlights @@ -588,6 +591,7 @@ fn descend_token( fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool { match &mut highlight.tag { HlTag::StringLiteral if !config.strings => return false, + HlTag::Comment if !config.comments => return false, // If punctuation is disabled, make the macro bang part of the macro call again. tag @ HlTag::Punctuation(HlPunct::MacroBang) => { if !config.macro_bang { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs index 9fd807f031f1f..358ac9b4ef352 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs @@ -10,7 +10,12 @@ use crate::{ syntax_highlighting::{HighlightConfig, highlight}, }; -pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { +pub(crate) fn highlight_as_html_with_config( + db: &RootDatabase, + config: HighlightConfig, + file_id: FileId, + rainbow: bool, +) -> String { let sema = Semantics::new(db); let file_id = sema .attach_first_edition(file_id) @@ -27,21 +32,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo ) } - let hl_ranges = highlight( - db, - HighlightConfig { - strings: true, - punctuation: true, - specialize_punctuation: true, - specialize_operator: true, - operator: true, - inject_doc_comment: true, - macro_bang: true, - syntactic_name_ref_highlighting: false, - }, - file_id.file_id(db), - None, - ); + let hl_ranges = highlight(db, config, file_id.file_id(db), None); let text = file.to_string(); let mut buf = String::new(); buf.push_str(STYLE); @@ -66,6 +57,25 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo buf } +pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { + highlight_as_html_with_config( + db, + HighlightConfig { + strings: true, + comments: true, + punctuation: true, + specialize_punctuation: true, + specialize_operator: true, + operator: true, + inject_doc_comment: true, + macro_bang: true, + syntactic_name_ref_highlighting: false, + }, + file_id, + rainbow, + ) +} + //FIXME: like, real html escaping fn html_escape(text: &str) -> String { text.replace('<', "<").replace('>', ">") diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index abe7be8c68881..4bb7308024144 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -80,6 +80,7 @@ pub(super) fn ra_fixture( .highlight( HighlightConfig { syntactic_name_ref_highlighting: false, + comments: true, punctuation: true, operator: true, strings: true, @@ -250,6 +251,7 @@ pub(super) fn doc_comment( db, HighlightConfig { syntactic_name_ref_highlighting: true, + comments: true, punctuation: true, operator: true, strings: true, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_comments_disabled.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_comments_disabled.html new file mode 100644 index 0000000000000..4607448bebaaa --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_comments_disabled.html @@ -0,0 +1,48 @@ + + +

// This is a regular comment
+/// This is a doc comment
+fn main() {
+    // Another comment
+    println!("Hello, world!");
+}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index dd359326c61d6..8198701d68432 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -9,6 +9,7 @@ use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture}; const HL_CONFIG: HighlightConfig = HighlightConfig { strings: true, + comments: true, punctuation: true, specialize_punctuation: true, specialize_operator: true, @@ -1220,16 +1221,25 @@ fn foo(x: &fn(&dyn Trait)) {} /// Highlights the code given by the `ra_fixture` argument, renders the /// result as HTML, and compares it with the HTML file given as `snapshot`. /// Note that the `snapshot` file is overwritten by the rendered HTML. -fn check_highlighting( +fn check_highlighting_with_config( #[rust_analyzer::rust_fixture] ra_fixture: &str, + config: HighlightConfig, expect: ExpectFile, rainbow: bool, ) { let (analysis, file_id) = fixture::file(ra_fixture.trim()); - let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); + let actual_html = &analysis.highlight_as_html_with_config(config, file_id, rainbow).unwrap(); expect.assert_eq(actual_html) } +fn check_highlighting( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: ExpectFile, + rainbow: bool, +) { + check_highlighting_with_config(ra_fixture, HL_CONFIG, expect, rainbow) +} + #[test] fn benchmark_syntax_highlighting_long_struct() { if skip_slow_tests() { @@ -1435,3 +1445,24 @@ fn main() { false, ); } + +#[test] +fn test_comment_highlighting_disabled() { + // Test that comments are not highlighted when disabled + check_highlighting_with_config( + r#" +// This is a regular comment +/// This is a doc comment +fn main() { + // Another comment + println!("Hello, world!"); +} +"#, + HighlightConfig { + comments: false, // Disable comment highlighting + ..HL_CONFIG + }, + expect_file!["./test_data/highlight_comments_disabled.html"], + false, + ); +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index c2252185a3aa3..8fe0a5d2eb662 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -382,6 +382,13 @@ config_data! { /// Exclude tests from find-all-references and call-hierarchy. references_excludeTests: bool = false, + /// Use semantic tokens for comments. + /// + /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. + /// By disabling semantic tokens for comments, other grammars can be used to highlight + /// their contents. + semanticHighlighting_comments_enable: bool = true, + /// Inject additional highlighting into doc comments. /// /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra @@ -1968,6 +1975,7 @@ impl Config { pub fn highlighting_config(&self) -> HighlightConfig { HighlightConfig { strings: self.semanticHighlighting_strings_enable().to_owned(), + comments: self.semanticHighlighting_comments_enable().to_owned(), punctuation: self.semanticHighlighting_punctuation_enable().to_owned(), specialize_punctuation: self .semanticHighlighting_punctuation_specialization_enable() diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 9a51212462db5..50dacd88f4072 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1378,6 +1378,17 @@ Enables the use of rustfmt's unstable range formatting command for the available on a nightly build. +## rust-analyzer.semanticHighlighting.comments.enable {#semanticHighlighting.comments.enable} + +Default: `true` + +Use semantic tokens for comments. + +In some editors (e.g. vscode) semantic tokens override other highlighting grammars. +By disabling semantic tokens for comments, other grammars can be used to highlight +their contents. + + ## rust-analyzer.semanticHighlighting.doc.comment.inject.enable {#semanticHighlighting.doc.comment.inject.enable} Default: `true` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 2b2e25e11c88a..1d27a12053552 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2850,6 +2850,16 @@ } } }, + { + "title": "Semantic Highlighting", + "properties": { + "rust-analyzer.semanticHighlighting.comments.enable": { + "markdownDescription": "Use semantic tokens for comments.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for comments, other grammars can be used to highlight\ntheir contents.", + "default": true, + "type": "boolean" + } + } + }, { "title": "Semantic Highlighting", "properties": { From 28b0e4e15e0ffd0c5f747f94dadb7a243566449d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 17 Sep 2025 22:57:25 +0800 Subject: [PATCH 231/251] Fix applicable on variant field for change_visibility Enum variant fields do not allow visibility Example --- ```rust enum Foo { Variant($0String), } ``` **Before this PR**: ```rust enum Foo { Variant(pub(crate) String), } ``` **After this PR**: Assist not applicable --- .../ide-assists/src/handlers/change_visibility.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs index 9b9f0c4522ed2..7119d5b9c23eb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/change_visibility.rs @@ -65,11 +65,13 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { if field.visibility().is_some() { return None; } + check_is_not_variant(&field)?; (vis_offset(field.syntax()), field_name.syntax().text_range()) } else if let Some(field) = ctx.find_node_at_offset::() { if field.visibility().is_some() { return None; } + check_is_not_variant(&field)?; (vis_offset(field.syntax()), field.syntax().text_range()) } else { return None; @@ -134,6 +136,11 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { None } +fn check_is_not_variant(field: &impl AstNode) -> Option<()> { + let kind = field.syntax().parent()?.parent()?.kind(); + (kind != SyntaxKind::VARIANT).then_some(()) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; @@ -239,6 +246,13 @@ mod tests { ); } + #[test] + fn not_applicable_for_enum_variant_fields() { + check_assist_not_applicable(change_visibility, r"pub enum Foo { Foo1($0i32) }"); + + check_assist_not_applicable(change_visibility, r"pub enum Foo { Foo1 { $0n: i32 } }"); + } + #[test] fn change_visibility_target() { check_assist_target(change_visibility, "$0fn foo() {}", "fn"); From 9cdc09b604f2a3bdab334911bac99d23ed556c23 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 16 Sep 2025 09:48:08 +0200 Subject: [PATCH 232/251] readdir for freebsd --- .../src/shims/unix/freebsd/foreign_items.rs | 6 +- src/tools/miri/src/shims/unix/fs.rs | 60 ++++++++++++------- .../src/shims/unix/linux/foreign_items.rs | 2 +- .../src/shims/unix/solarish/foreign_items.rs | 2 +- src/tools/miri/tests/pass/shims/fs.rs | 3 +- 5 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 9e247053fbcdb..413df85ee3aae 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -159,7 +159,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.macos_fbsd_readdir_r(dirp, entry, result)?; this.write_scalar(result, dest)?; } - + "readdir" | "readdir@FBSD_1.0" => { + let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.readdir64("dirent", dirp)?; + this.write_scalar(result, dest)?; + } // Miscellaneous "__error" => { let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index f9bcacf64c412..22bec9bd83941 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -900,14 +900,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn linux_solarish_readdir64( - &mut self, - dirent_type: &str, - dirp_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + fn readdir64(&mut self, dirent_type: &str, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos") { + if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos" | "freebsd") { panic!("`linux_solaris_readdir64` should not be called on {}", this.tcx.sess.target.os); } @@ -926,6 +922,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let entry = match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { + // If the host is a Unix system, fill in the inode number with its real value. + // If not, use 0 as a fallback value. + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0u64; + // Write the directory entry into a newly allocated buffer. // The name is written with write_bytes, while the rest of the // dirent64 (or dirent) struct is written using write_int_fields. @@ -947,6 +950,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // pub d_reclen: c_ushort, // pub d_name: [c_char; 3], // } + // + // On FreeBSD: + // pub struct dirent{ + // pub d_fileno: uint32_t, + // pub d_reclen: uint16_t, + // pub d_type: uint8_t, + // pub d_namlen: uint8_t, + // pub d_name: [c_char; 256] + // } let mut name = dir_entry.file_name(); // not a Path as there are no separators! name.push("\0"); // Add a NUL terminator @@ -965,31 +977,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MiriMemoryKind::Runtime.into(), AllocInit::Uninit, )?; - let entry: Pointer = entry.into(); + let entry = this.ptr_to_mplace(entry.into(), dirent_layout); - // If the host is a Unix system, fill in the inode number with its real value. - // If not, use 0 as a fallback value. - #[cfg(unix)] - let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); - #[cfg(not(unix))] - let ino = 0u64; - - let file_type = this.file_type_to_d_type(dir_entry.file_type())?; + // Write common fields + let ino_name = + if this.tcx.sess.target.os == "freebsd" { "d_fileno" } else { "d_ino" }; this.write_int_fields_named( - &[("d_ino", ino.into()), ("d_off", 0), ("d_reclen", size.into())], - &this.ptr_to_mplace(entry, dirent_layout), + &[(ino_name, ino.into()), ("d_reclen", size.into())], + &entry, )?; - if let Some(d_type) = this - .try_project_field_named(&this.ptr_to_mplace(entry, dirent_layout), "d_type")? - { + // Write "optional" fields. + if let Some(d_off) = this.try_project_field_named(&entry, "d_off")? { + this.write_null(&d_off)?; + } + + if let Some(d_namlen) = this.try_project_field_named(&entry, "d_namlen")? { + this.write_int(name_len.strict_sub(1), &d_namlen)?; + } + + let file_type = this.file_type_to_d_type(dir_entry.file_type())?; + if let Some(d_type) = this.try_project_field_named(&entry, "d_type")? { this.write_int(file_type, &d_type)?; } - let name_ptr = entry.wrapping_offset(Size::from_bytes(d_name_offset), this); + // The name is not a normal field, we already computed the offset above. + let name_ptr = entry.ptr().wrapping_offset(Size::from_bytes(d_name_offset), this); this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?; - Some(entry) + Some(entry.ptr()) } None => { // end of stream: return NULL diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e7e0c3b6ecd96..79052698f4bad 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "readdir64" => { let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.linux_solarish_readdir64("dirent64", dirp)?; + let result = this.readdir64("dirent64", dirp)?; this.write_scalar(result, dest)?; } "sync_file_range" => { diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index d7033a65fe22b..31269bf00c948 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -106,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "readdir" => { let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.linux_solarish_readdir64("dirent", dirp)?; + let result = this.readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 0748007b3c058..022dcc5dcbafa 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -28,8 +28,7 @@ fn main() { test_from_raw_os_error(); test_file_clone(); // Windows file handling is very incomplete. - // FIXME: read_dir broken on FreeBSD (https://github.com/rust-lang/miri/issues/4587) - if cfg!(not(windows)) && !cfg!(target_os = "freebsd") { + if cfg!(not(windows)) { test_file_set_len(); test_file_sync(); test_rename(); From f90075862346c78b4c0c373e48fb8929168d277e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Sep 2025 14:47:21 -0700 Subject: [PATCH 233/251] std: Fix WASI implementation of `remove_dir_all` This commit is a change to the WASI-specific implementation of the `std::fs::remove_dir_all` function. Specifically it changes how directory entries are read of a directory-being-deleted to specifically buffer them all into a `Vec` before actually proceeding to delete anything. This is necessary to fix an interaction with how the WASIp1 `fd_readdir` API works to have everything work out in the face of mutations while reading a directory. The basic problem is that `fd_readdir`, the WASIp1 API for reading directories, is not a stateful read of a directory but instead a "seekable" read of a directory. Its `cookie` argument enables seeking anywhere within the directory at any time to read further entries. Native host implementations do not have this ability, however, which means that this seeking property must be achieved by re-reading the directory. The problem with this is that WASIp1 has under-specified semantics around what should happen if a directory is mutated between two calls to `fd_readdir`. In essence there's not really any possible implementation in hosts except to read the entire directory and support seeking through the already-read list. This implementation is not possible in the WASIp1-to-WASIp2 adapter that is primarily used to create components for the `wasm32-wasip2` target where it has constrained memory requirements and can't buffer up arbitrarily sized directories. The WASIp1 API definitions are effectively "dead" now at the standards level meaning that `fd_readdir` won't be changing nor will a replacement be coming. For the `wasm32-wasip2` target this will get fixed once filesystem APIs are updated to use WASIp2 directly instead of WASIp1, making this buffering unnecessary. In essence while this is a hack it's sort of the least invasive thing that works everywhere for now. I don't think this is viable to fix in hosts so guests compiled to wasm are going to have to work around it by not relying on any guarantees about what happens to a directory if it's mutated between reads. --- library/std/src/sys/fs/wasi.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index b65d86de12a3d..0b65b9cb389df 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -848,7 +848,14 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { // Iterate over all the entries in this directory, and travel recursively if // necessary - for entry in ReadDir::new(fd, dummy_root) { + // + // Note that all directory entries for this directory are read first before + // any removal is done. This works around the fact that the WASIp1 API for + // reading directories is not well-designed for handling mutations between + // invocations of reading a directory. By reading all the entries at once + // this ensures that, at least without concurrent modifications, it should + // be possible to delete everything. + for entry in ReadDir::new(fd, dummy_root).collect::>() { let entry = entry?; let path = crate::str::from_utf8(&entry.name).map_err(|_| { io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") From 6e74905be29b861bcfd2780a8c81495deffec6c3 Mon Sep 17 00:00:00 2001 From: Haidong Zhang Date: Wed, 3 Sep 2025 17:40:45 +0800 Subject: [PATCH 234/251] Set lto="fat" automatically when compiling with RUSTFLAGS="-Zautodiff=Enable". --- compiler/rustc_codegen_ssa/messages.ftl | 2 -- compiler/rustc_codegen_ssa/src/errors.rs | 4 ---- compiler/rustc_session/src/config.rs | 5 +++++ compiler/rustc_session/src/session.rs | 7 +++++++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 1dd65d38a2be7..91c3806df4c34 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -8,8 +8,6 @@ codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error} -codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto - codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index fb5a82051405d..d5c30c5c7a6b0 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -37,10 +37,6 @@ pub(crate) struct CguNotRecorded<'a> { pub cgu_name: &'a str, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_autodiff_without_lto)] -pub struct AutodiffWithoutLto; - #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_reuse_kind)] pub(crate) struct UnknownReuseKind { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 297df7c2c9765..795cb2b2cfeba 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1509,6 +1509,11 @@ impl Options { pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) } + + #[inline] + pub fn autodiff_enabled(&self) -> bool { + self.unstable_opts.autodiff.contains(&AutoDiff::Enable) + } } impl UnstableOptions { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3525c7c1d1a99..d0dd2cdac0c48 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -600,6 +600,13 @@ impl Session { /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { + // Autodiff currently requires fat-lto to have access to the llvm-ir of all (indirectly) used functions and types. + // fat-lto is the easiest solution to this requirement, but quite expensive. + // FIXME(autodiff): Make autodiff also work with embed-bc instead of fat-lto. + if self.opts.autodiff_enabled() { + return config::Lto::Fat; + } + // If our target has codegen requirements ignore the command line if self.target.requires_lto { return config::Lto::Fat; From 2c1f1f0e9bb706d9adbb71e0bc33923c4478eb85 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 8 Sep 2025 10:17:14 +0200 Subject: [PATCH 235/251] Add GenMC estimation mode. Improve error handling and output printing. --- src/tools/miri/doc/genmc.md | 3 + .../genmc-sys/cpp/include/MiriInterface.hpp | 8 +- .../cpp/src/MiriInterface/Exploration.cpp | 14 ++ .../genmc-sys/cpp/src/MiriInterface/Setup.cpp | 23 ++- src/tools/miri/genmc-sys/src/lib.rs | 55 +++++- src/tools/miri/src/bin/miri.rs | 9 +- .../miri/src/concurrency/genmc/config.rs | 17 ++ src/tools/miri/src/concurrency/genmc/dummy.rs | 12 -- src/tools/miri/src/concurrency/genmc/mod.rs | 61 ++++--- src/tools/miri/src/concurrency/genmc/run.rs | 156 ++++++++++++++---- .../genmc/fail/data_race/mpu2_rels_rlx.stderr | 2 + .../data_race/weak_orderings.rel_rlx.stderr | 2 + .../data_race/weak_orderings.rlx_acq.stderr | 2 + .../data_race/weak_orderings.rlx_rlx.stderr | 2 + .../tests/genmc/fail/loom/buggy_inc.stderr | 2 + .../fail/loom/store_buffering.genmc.stderr | 2 + .../fail/simple/2w2w_weak.relaxed4.stderr | 2 + .../fail/simple/2w2w_weak.release4.stderr | 2 + .../fail/simple/2w2w_weak.sc3_rel1.stderr | 2 + .../cas_failure_ord_racy_key_init.stderr | 4 +- .../genmc/pass/atomics/cas_simple.stderr | 4 +- .../tests/genmc/pass/atomics/rmw_ops.stderr | 4 +- .../miri/tests/genmc/pass/litmus/2cowr.stderr | 4 +- .../genmc/pass/litmus/2w2w_2sc_scf.stderr | 4 +- .../pass/litmus/2w2w_3sc_1rel.release1.stderr | 4 +- .../pass/litmus/2w2w_3sc_1rel.release2.stderr | 4 +- .../genmc/pass/litmus/2w2w_4rel.sc.stderr | 4 +- .../genmc/pass/litmus/2w2w_4rel.weak.stderr | 4 +- .../tests/genmc/pass/litmus/2w2w_4sc.stderr | 4 +- .../genmc/pass/litmus/IRIW-acq-sc.stderr | 4 +- .../tests/genmc/pass/litmus/IRIWish.stderr | 4 +- .../miri/tests/genmc/pass/litmus/LB.stderr | 4 +- .../tests/genmc/pass/litmus/LB_incMPs.stderr | 4 +- .../miri/tests/genmc/pass/litmus/MP.stderr | 4 +- .../genmc/pass/litmus/MPU2_rels_acqf.stderr | 4 +- .../genmc/pass/litmus/MPU_rels_acq.stderr | 4 +- .../tests/genmc/pass/litmus/MP_incMPs.stderr | 4 +- .../genmc/pass/litmus/MP_rels_acqf.stderr | 4 +- .../miri/tests/genmc/pass/litmus/SB.stderr | 4 +- .../tests/genmc/pass/litmus/SB_2sc_scf.stderr | 4 +- .../tests/genmc/pass/litmus/Z6_U.sc.stderr | 4 +- .../tests/genmc/pass/litmus/Z6_U.weak.stderr | 4 +- .../tests/genmc/pass/litmus/Z6_acq.stderr | 4 +- .../tests/genmc/pass/litmus/atomicpo.stderr | 4 +- .../tests/genmc/pass/litmus/casdep.stderr | 4 +- .../miri/tests/genmc/pass/litmus/ccr.stderr | 4 +- .../miri/tests/genmc/pass/litmus/cii.stderr | 4 +- .../miri/tests/genmc/pass/litmus/corr.stderr | 4 +- .../miri/tests/genmc/pass/litmus/corr0.stderr | 4 +- .../miri/tests/genmc/pass/litmus/corr1.stderr | 4 +- .../miri/tests/genmc/pass/litmus/corr2.stderr | 4 +- .../miri/tests/genmc/pass/litmus/corw.stderr | 4 +- .../miri/tests/genmc/pass/litmus/cowr.stderr | 4 +- .../genmc/pass/litmus/cumul-release.stderr | 4 +- .../tests/genmc/pass/litmus/default.stderr | 4 +- .../genmc/pass/litmus/detour.join.stderr | 4 +- .../genmc/pass/litmus/detour.no_join.stderr | 4 +- .../genmc/pass/litmus/fr_w_w_w_reads.stderr | 4 +- .../miri/tests/genmc/pass/litmus/inc2w.stderr | 4 +- .../genmc/pass/litmus/inc_inc_RR_W_RR.stderr | 4 +- .../miri/tests/genmc/pass/litmus/riwi.stderr | 4 +- .../tests/genmc/pass/litmus/viktor-relseq.rs | 4 +- .../genmc/pass/litmus/viktor-relseq.stderr | 6 +- src/tools/miri/tests/ui.rs | 2 + 64 files changed, 386 insertions(+), 170 deletions(-) diff --git a/src/tools/miri/doc/genmc.md b/src/tools/miri/doc/genmc.md index 8af697be34a61..44e11dcbec44c 100644 --- a/src/tools/miri/doc/genmc.md +++ b/src/tools/miri/doc/genmc.md @@ -24,6 +24,8 @@ Note that `cargo miri test` in GenMC mode is currently not supported. ### Supported Parameters - `-Zmiri-genmc`: Enable GenMC mode (not required if any other GenMC options are used). +- `-Zmiri-genmc-estimate`: This enables estimation of the concurrent execution space and verification time, before running the full verification. This should help users detect when their program is too complex to fully verify in a reasonable time. This will explore enough executions to make a good estimation, but at least 10 and at most `estimation-max` executions. +- `-Zmiri-genmc-estimation-max={MAX_ITERATIONS}`: Set the maximum number of executions that will be explored during estimation (default: 1000). - `-Zmiri-genmc-print-exec-graphs={none,explored,blocked,all}`: Make GenMC print the execution graph of the program after every explored, every blocked, or after every execution (default: None). - `-Zmiri-genmc-print-exec-graphs`: Shorthand for suffix `=explored`. - `-Zmiri-genmc-print-genmc-output`: Print the output that GenMC provides. NOTE: this output is quite verbose and the events in the printed execution graph are hard to map back to the Rust code location they originate from. @@ -36,6 +38,7 @@ Note that `cargo miri test` in GenMC mode is currently not supported. - `debug1`: Print revisits considered by GenMC. - `debug2`: Print the execution graph after every memory access. - `debug3`: Print reads-from values considered by GenMC. +- `-Zmiri-genmc-verbose`: Show more information, such as estimated number of executions, and time taken for verification. #### Regular Miri parameters useful for GenMC mode diff --git a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp index 662eb0e173ca8..444c9375319af 100644 --- a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp +++ b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp @@ -31,6 +31,7 @@ enum class LogLevel : std::uint8_t; struct GenmcScalar; struct SchedulingResult; +struct EstimationResult; struct LoadResult; struct StoreResult; struct ReadModifyWriteResult; @@ -66,7 +67,7 @@ struct MiriGenmcShim : private GenMCDriver { /// `logLevel`, causing a data race. The safest way to use these functions is to call /// `set_log_level_raw` once, and only then start creating handles. There should not be any /// other (safe) way to create a `MiriGenmcShim`. - /* unsafe */ static auto create_handle(const GenmcParams& params) + /* unsafe */ static auto create_handle(const GenmcParams& params, bool estimation_mode) -> std::unique_ptr; virtual ~MiriGenmcShim() {} @@ -183,6 +184,11 @@ struct MiriGenmcShim : private GenMCDriver { return nullptr; } + /**** Printing and estimation mode functionality. ****/ + + /// Get the results of a run in estimation mode. + auto get_estimation_results() const -> EstimationResult; + private: /** Increment the event index in the given thread by 1 and return the new event. */ [[nodiscard]] inline auto inc_pos(ThreadId tid) -> Event { diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp index c51b59e865170..5e7188f17e0d2 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Exploration.cpp @@ -10,7 +10,9 @@ #include "Support/Verbosity.hpp" // C++ headers: +#include #include +#include auto MiriGenmcShim::schedule_next( const int curr_thread_id, @@ -40,3 +42,15 @@ auto MiriGenmcShim::handle_execution_end() -> std::unique_ptr { GenMCDriver::handleExecutionEnd(); return {}; } + +/**** Estimation mode result ****/ + +auto MiriGenmcShim::get_estimation_results() const -> EstimationResult { + const auto& res = getResult(); + return EstimationResult { + .mean = static_cast(res.estimationMean), + .sd = static_cast(std::sqrt(res.estimationVariance)), + .explored_execs = static_cast(res.explored), + .blocked_execs = static_cast(res.exploredBlocked), + }; +} diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp index a17a83aa06e13..af13f0d07746e 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp @@ -58,7 +58,7 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel logLevel = to_genmc_verbosity_level(log_level); } -/* unsafe */ auto MiriGenmcShim::create_handle(const GenmcParams& params) +/* unsafe */ auto MiriGenmcShim::create_handle(const GenmcParams& params, bool estimation_mode) -> std::unique_ptr { auto conf = std::make_shared(); @@ -82,7 +82,8 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel // Miri. conf->warnOnGraphSize = 1024 * 1024; - // We only support the `RC11` memory model for Rust, and `SC` when weak memory emulation is disabled. + // We only support the `RC11` memory model for Rust, and `SC` when weak memory emulation is + // disabled. conf->model = params.disable_weak_memory_emulation ? ModelType::SC : ModelType::RC11; // This prints the seed that GenMC picks for randomized scheduling during estimation mode. @@ -119,12 +120,20 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel ); conf->symmetryReduction = params.do_symmetry_reduction; - // FIXME(genmc): expose this setting to Miri (useful for testing Miri-GenMC). - conf->schedulePolicy = SchedulePolicy::WF; - + // Set the scheduling policy. GenMC uses `WFR` for estimation mode. + // For normal verification, `WF` has the best performance and is the GenMC default. + // Other scheduling policies are used by GenMC for testing and for modes currently + // unsupported with Miri such as bounding, which uses LTR. + conf->schedulePolicy = estimation_mode ? SchedulePolicy::WFR : SchedulePolicy::WF; + + // Set the min and max number of executions tested in estimation mode. + conf->estimationMin = 10; // default taken from GenMC + conf->estimationMax = params.estimation_max; + // Deviation threshold % under which estimation is deemed good enough. + conf->sdThreshold = 10; // default taken from GenMC // Set the mode used for this driver, either estimation or verification. - // FIXME(genmc): implement estimation mode. - const auto mode = GenMCDriver::Mode(GenMCDriver::VerificationMode {}); + const auto mode = estimation_mode ? GenMCDriver::Mode(GenMCDriver::EstimationMode {}) + : GenMCDriver::Mode(GenMCDriver::VerificationMode {}); // Running Miri-GenMC without race detection is not supported. // Disabling this option also changes the behavior of the replay scheduler to only schedule diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs index 31bc2606adc01..733b3d780b187 100644 --- a/src/tools/miri/genmc-sys/src/lib.rs +++ b/src/tools/miri/genmc-sys/src/lib.rs @@ -27,6 +27,7 @@ static GENMC_LOG_LEVEL: OnceLock = OnceLock::new(); pub fn create_genmc_driver_handle( params: &GenmcParams, genmc_log_level: LogLevel, + do_estimation: bool, ) -> UniquePtr { // SAFETY: Only setting the GenMC log level once is guaranteed by the `OnceLock`. // No other place calls `set_log_level_raw`, so the `logLevel` value in GenMC will not change once we initialize it once. @@ -40,7 +41,7 @@ pub fn create_genmc_driver_handle( }), "Attempt to change the GenMC log level after it was already set" ); - unsafe { MiriGenmcShim::create_handle(params) } + unsafe { MiriGenmcShim::create_handle(params, do_estimation) } } impl GenmcScalar { @@ -54,6 +55,7 @@ impl GenmcScalar { impl Default for GenmcParams { fn default() -> Self { Self { + estimation_max: 1000, // default taken from GenMC print_random_schedule_seed: false, do_symmetry_reduction: false, // GenMC graphs can be quite large since Miri produces a lot of (non-atomic) events. @@ -70,6 +72,20 @@ impl Default for LogLevel { } } +impl FromStr for SchedulePolicy { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + Ok(match s { + "wf" => SchedulePolicy::WF, + "wfr" => SchedulePolicy::WFR, + "arbitrary" | "random" => SchedulePolicy::Arbitrary, + "ltr" => SchedulePolicy::LTR, + _ => return Err("invalid scheduling policy"), + }) + } +} + impl FromStr for LogLevel { type Err = &'static str; @@ -92,9 +108,12 @@ mod ffi { /**** Types shared between Miri/Rust and Miri/C++ through cxx_bridge: ****/ /// Parameters that will be given to GenMC for setting up the model checker. - /// (The fields of this struct are visible to both Rust and C++) + /// The fields of this struct are visible to both Rust and C++. + /// Note that this struct is #[repr(C)], so the order of fields matters. #[derive(Clone, Debug)] struct GenmcParams { + /// Maximum number of executions explored in estimation mode. + pub estimation_max: u32, pub print_random_schedule_seed: bool, pub do_symmetry_reduction: bool, pub print_execution_graphs: ExecutiongraphPrinting, @@ -165,6 +184,19 @@ mod ffi { next_thread: i32, } + #[must_use] + #[derive(Debug)] + struct EstimationResult { + /// Expected number of total executions. + mean: f64, + /// Standard deviation of the total executions estimate. + sd: f64, + /// Number of explored executions during the estimation. + explored_execs: u64, + /// Number of encounteded blocked executions during the estimation. + blocked_execs: u64, + } + #[must_use] #[derive(Debug)] struct LoadResult { @@ -214,6 +246,14 @@ mod ffi { /**** These are GenMC types that we have to copy-paste here since cxx does not support "importing" externally defined C++ types. ****/ + #[derive(Clone, Copy, Debug)] + enum SchedulePolicy { + LTR, + WF, + WFR, + Arbitrary, + } + #[derive(Debug)] /// Corresponds to GenMC's type with the same name. /// Should only be modified if changed by GenMC. @@ -272,6 +312,7 @@ mod ffi { type ActionKind; type MemOrdering; type RMWBinOp; + type SchedulePolicy; /// Set the log level for GenMC. /// @@ -295,7 +336,10 @@ mod ffi { /// start creating handles. /// There should not be any other (safe) way to create a `MiriGenmcShim`. #[Self = "MiriGenmcShim"] - unsafe fn create_handle(params: &GenmcParams) -> UniquePtr; + unsafe fn create_handle( + params: &GenmcParams, + estimation_mode: bool, + ) -> UniquePtr; /// Get the bit mask that GenMC expects for global memory allocations. fn get_global_alloc_static_mask() -> u64; @@ -403,5 +447,10 @@ mod ffi { fn get_result_message(self: &MiriGenmcShim) -> UniquePtr; /// If an error occurred, return a string describing the error, otherwise, return `nullptr`. fn get_error_string(self: &MiriGenmcShim) -> UniquePtr; + + /**** Printing functionality. ****/ + + /// Get the results of a run in estimation mode. + fn get_estimation_results(self: &MiriGenmcShim) -> EstimationResult; } } diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 731fe283a2195..8b15a7863476e 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -186,18 +186,17 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { optimizations is usually marginal at best."); } - if let Some(_genmc_config) = &config.genmc_config { + // Run in GenMC mode if enabled. + if config.genmc_config.is_some() { + // This is the entry point used in GenMC mode. + // This closure will be called multiple times to explore the concurrent execution space of the program. let eval_entry_once = |genmc_ctx: Rc| { miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx)) }; - - // FIXME(genmc): add estimation mode here. - let return_code = run_genmc_mode(&config, eval_entry_once, tcx).unwrap_or_else(|| { tcx.dcx().abort_if_errors(); rustc_driver::EXIT_FAILURE }); - exit(return_code); }; diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs index 34933d423f064..c7cfa6012b8dc 100644 --- a/src/tools/miri/src/concurrency/genmc/config.rs +++ b/src/tools/miri/src/concurrency/genmc/config.rs @@ -10,11 +10,15 @@ use crate::{IsolatedOp, MiriConfig, RejectOpWith}; pub struct GenmcConfig { /// Parameters sent to the C++ side to create a new handle to the GenMC model checker. pub(super) params: GenmcParams, + pub(super) do_estimation: bool, /// Print the output message that GenMC generates when an error occurs. /// This error message is currently hard to use, since there is no clear mapping between the events that GenMC sees and the Rust code location where this event was produced. pub(super) print_genmc_output: bool, /// The log level for GenMC. pub(super) log_level: LogLevel, + /// Enable more verbose output, such as number of executions estimate + /// and time to completion of verification step. + pub(super) verbose_output: bool, } impl GenmcConfig { @@ -57,8 +61,21 @@ impl GenmcConfig { "Invalid suffix to GenMC argument '-Zmiri-genmc-print-exec-graphs', expected '', '=none', '=explored', '=blocked' or '=all'" )), } + } else if trimmed_arg == "estimate" { + // FIXME(genmc): should this be on by default (like for GenMC)? + // Enable estimating the execution space and require time before running the actual verification. + genmc_config.do_estimation = true; + } else if let Some(estimation_max_str) = trimmed_arg.strip_prefix("estimation-max=") { + // Set the maximum number of executions to explore during estimation. + genmc_config.params.estimation_max = estimation_max_str.parse().ok().filter(|estimation_max| *estimation_max > 0).ok_or_else(|| { + format!( + "'-Zmiri-genmc-estimation-max=...' expects a positive integer argument, but got '{estimation_max_str}'" + ) + })?; } else if trimmed_arg == "print-genmc-output" { genmc_config.print_genmc_output = true; + } else if trimmed_arg == "verbose" { + genmc_config.verbose_output = true; } else { return Err(format!("Invalid GenMC argument: \"-Zmiri-genmc-{trimmed_arg}\"")); } diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs index 92b34b83ee0fc..c28984cef35ad 100644 --- a/src/tools/miri/src/concurrency/genmc/dummy.rs +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -39,18 +39,6 @@ mod run { impl GenmcCtx { // We don't provide the `new` function in the dummy module. - pub fn get_blocked_execution_count(&self) -> usize { - unreachable!() - } - - pub fn get_explored_execution_count(&self) -> usize { - unreachable!() - } - - pub fn is_exploration_done(&self) -> bool { - unreachable!() - } - /**** Memory access handling ****/ pub(super) fn set_ongoing_action_data_race_free(&self, _enable: bool) { diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs index 7270c66810608..0086d3f2bf0bc 100644 --- a/src/tools/miri/src/concurrency/genmc/mod.rs +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -2,8 +2,8 @@ use std::cell::{Cell, RefCell}; use std::sync::Arc; use genmc_sys::{ - GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, MemOrdering, MiriGenmcShim, RMWBinOp, UniquePtr, - create_genmc_driver_handle, + EstimationResult, GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, MemOrdering, MiriGenmcShim, + RMWBinOp, UniquePtr, create_genmc_driver_handle, }; use rustc_abi::{Align, Size}; use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult, interp_ok}; @@ -16,6 +16,7 @@ use self::helper::{ MAX_ACCESS_SIZE, Warnings, emit_warning, genmc_scalar_to_scalar, maybe_upgrade_compare_exchange_success_orderings, scalar_to_genmc_scalar, to_genmc_rmw_op, }; +use self::run::GenmcMode; use self::thread_id_map::ThreadIdMap; use crate::concurrency::genmc::helper::split_access; use crate::intrinsics::AtomicRmwOp; @@ -37,6 +38,16 @@ pub use genmc_sys::GenmcParams; pub use self::config::GenmcConfig; pub use self::run::run_genmc_mode; +#[derive(Debug)] +pub enum ExecutionEndResult { + /// An error occurred at the end of the execution. + Error(String), + /// No errors occurred, and there are more executions to explore. + Continue, + /// No errors occurred and we are finished. + Stop, +} + #[derive(Clone, Copy, Debug)] pub enum ExitType { MainThreadFinish, @@ -128,26 +139,33 @@ pub struct GenmcCtx { /// GenMC Context creation and administrative / query actions impl GenmcCtx { /// Create a new `GenmcCtx` from a given config. - fn new(miri_config: &MiriConfig, global_state: Arc) -> Self { + fn new(miri_config: &MiriConfig, global_state: Arc, mode: GenmcMode) -> Self { let genmc_config = miri_config.genmc_config.as_ref().unwrap(); - let handle = - RefCell::new(create_genmc_driver_handle(&genmc_config.params, genmc_config.log_level)); + let handle = RefCell::new(create_genmc_driver_handle( + &genmc_config.params, + genmc_config.log_level, + /* do_estimation: */ mode == GenmcMode::Estimation, + )); Self { handle, exec_state: Default::default(), global_state } } + fn get_estimation_results(&self) -> EstimationResult { + self.handle.borrow().get_estimation_results() + } + /// Get the number of blocked executions encountered by GenMC. - pub fn get_blocked_execution_count(&self) -> u64 { + fn get_blocked_execution_count(&self) -> u64 { self.handle.borrow().get_blocked_execution_count() } /// Get the number of explored executions encountered by GenMC. - pub fn get_explored_execution_count(&self) -> u64 { + fn get_explored_execution_count(&self) -> u64 { self.handle.borrow().get_explored_execution_count() } /// Check if GenMC encountered an error that wasn't immediately returned during execution. /// Returns a string representation of the error if one occurred. - pub fn try_get_error(&self) -> Option { + fn try_get_error(&self) -> Option { self.handle .borrow() .get_error_string() @@ -157,7 +175,7 @@ impl GenmcCtx { /// Check if GenMC encountered an error that wasn't immediately returned during execution. /// Returns a string representation of the error if one occurred. - pub fn get_result_message(&self) -> String { + fn get_result_message(&self) -> String { self.handle .borrow() .get_result_message() @@ -166,13 +184,6 @@ impl GenmcCtx { .expect("there should always be a message") } - /// This function determines if we should continue exploring executions or if we are done. - /// - /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. - pub fn is_exploration_done(&self) -> bool { - self.handle.borrow_mut().pin_mut().is_exploration_done() - } - /// Select whether data race free actions should be allowed. This function should be used carefully! /// /// If `true` is passed, allow for data races to happen without triggering an error, until this function is called again with argument `false`. @@ -218,13 +229,25 @@ impl GenmcCtx { /// This function will also check for those, and return their error description. /// /// To get the all messages (warnings, errors) that GenMC produces, use the `get_result_message` method. - fn handle_execution_end(&self) -> Option { + fn handle_execution_end(&self) -> ExecutionEndResult { let result = self.handle.borrow_mut().pin_mut().handle_execution_end(); - result.as_ref().map(|msg| msg.to_string_lossy().to_string())?; + if let Some(error) = result.as_ref() { + return ExecutionEndResult::Error(error.to_string_lossy().to_string()); + } + + // GenMC decides if there is more to explore: + let exploration_done = self.handle.borrow_mut().pin_mut().is_exploration_done(); // GenMC currently does not return an error value immediately in all cases. + // Both `handle_execution_end` and `is_exploration_done` can produce such errors. // We manually query for any errors here to ensure we don't miss any. - self.try_get_error() + if let Some(error) = self.try_get_error() { + ExecutionEndResult::Error(error) + } else if exploration_done { + ExecutionEndResult::Stop + } else { + ExecutionEndResult::Continue + } } /**** Memory access handling ****/ diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs index 7e4ed816a76a1..bc2f5f7b79ec4 100644 --- a/src/tools/miri/src/concurrency/genmc/run.rs +++ b/src/tools/miri/src/concurrency/genmc/run.rs @@ -1,32 +1,65 @@ use std::rc::Rc; use std::sync::Arc; +use std::time::Instant; +use genmc_sys::EstimationResult; use rustc_middle::ty::TyCtxt; use super::GlobalState; +use crate::concurrency::genmc::ExecutionEndResult; use crate::rustc_const_eval::interpret::PointerArithmetic; -use crate::{GenmcCtx, MiriConfig}; +use crate::{GenmcConfig, GenmcCtx, MiriConfig}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub(super) enum GenmcMode { + Estimation, + Verification, +} + +impl GenmcMode { + /// Return whether warnings on unsupported features should be printed in this mode. + fn print_unsupported_warnings(self) -> bool { + self == GenmcMode::Verification + } +} /// Do a complete run of the program in GenMC mode. /// This will call `eval_entry` multiple times, until either: /// - An error is detected (indicated by a `None` return value) /// - All possible executions are explored. /// -/// FIXME(genmc): add estimation mode setting. +/// Returns `None` is an error is detected, or `Some(return_value)` with the return value of the last run of the program. pub fn run_genmc_mode<'tcx>( config: &MiriConfig, eval_entry: impl Fn(Rc) -> Option, tcx: TyCtxt<'tcx>, ) -> Option { let genmc_config = config.genmc_config.as_ref().unwrap(); + // Run in Estimation mode if requested. + if genmc_config.do_estimation { + eprintln!("Estimating GenMC verification time..."); + run_genmc_mode_impl(config, &eval_entry, tcx, GenmcMode::Estimation)?; + } + // Run in Verification mode. + eprintln!("Running GenMC Verification..."); + run_genmc_mode_impl(config, &eval_entry, tcx, GenmcMode::Verification) +} + +fn run_genmc_mode_impl<'tcx>( + config: &MiriConfig, + eval_entry: &impl Fn(Rc) -> Option, + tcx: TyCtxt<'tcx>, + mode: GenmcMode, +) -> Option { + let time_start = Instant::now(); + let genmc_config = config.genmc_config.as_ref().unwrap(); // There exists only one `global_state` per full run in GenMC mode. // It is shared by all `GenmcCtx` in this run. // FIXME(genmc): implement multithreading once GenMC supports it. - // FIXME(genmc): disable warnings in estimation mode once it is added. let global_state = - Arc::new(GlobalState::new(tcx.target_usize_max(), /* print_warnings */ true)); - let genmc_ctx = Rc::new(GenmcCtx::new(config, global_state)); + Arc::new(GlobalState::new(tcx.target_usize_max(), mode.print_unsupported_warnings())); + let genmc_ctx = Rc::new(GenmcCtx::new(config, global_state, mode)); // `rep` is used to report the progress, Miri will panic on wrap-around. for rep in 0u64.. { @@ -37,46 +70,97 @@ pub fn run_genmc_mode<'tcx>( // Execute the program until completion to get the return value, or return if an error happens: let Some(return_code) = eval_entry(genmc_ctx.clone()) else { - // If requested, print the output GenMC produced: - if genmc_config.print_genmc_output { - eprintln!("== raw GenMC output ========================="); - eprintln!("{}", genmc_ctx.get_result_message()); - eprintln!("== end of raw GenMC output =================="); - } + genmc_ctx.print_genmc_output(genmc_config); return None; }; - // We inform GenMC that the execution is complete. If there was an error, we print it. - if let Some(error) = genmc_ctx.handle_execution_end() { - // This can be reached for errors that affect the entire execution, not just a specific event. - // For instance, linearizability checking and liveness checking report their errors this way. - // Neither are supported by Miri-GenMC at the moment though. However, GenMC also - // treats races on deallocation as global errors, so this code path is still reachable. - // Since we don't have any span information for the error at this point, - // we just print GenMC's error message. - eprintln!("(GenMC) Error detected: {error}"); - eprintln!(); - eprintln!("{}", genmc_ctx.get_result_message()); - return None; + // We inform GenMC that the execution is complete. + // If there was an error, we print it. + match genmc_ctx.handle_execution_end() { + ExecutionEndResult::Continue => continue, + ExecutionEndResult::Stop => { + let elapsed_time_sec = Instant::now().duration_since(time_start).as_secs_f64(); + // Print the output for the current mode. + if mode == GenmcMode::Estimation { + genmc_ctx.print_estimation_output(genmc_config, elapsed_time_sec); + } else { + genmc_ctx.print_verification_output(genmc_config, elapsed_time_sec); + } + // Return the return code of the last execution. + return Some(return_code); + } + ExecutionEndResult::Error(error) => { + // This can be reached for errors that affect the entire execution, not just a specific event. + // For instance, linearizability checking and liveness checking report their errors this way. + // Neither are supported by Miri-GenMC at the moment though. However, GenMC also + // treats races on deallocation as global errors, so this code path is still reachable. + // Since we don't have any span information for the error at this point, + // we just print GenMC's error string, and the full GenMC output if requested. + eprintln!("(GenMC) Error detected: {error}"); + genmc_ctx.print_genmc_output(genmc_config); + return None; + } } + } + unreachable!() +} - // Check if we've explored enough executions: - if !genmc_ctx.is_exploration_done() { - continue; +impl GenmcCtx { + /// Print the full output message produced by GenMC if requested, or a hint on how to enable it. + /// + /// This message can be very verbose and is likely not useful for the average user. + /// This function should be called *after* Miri has printed all of its output. + fn print_genmc_output(&self, genmc_config: &GenmcConfig) { + if genmc_config.print_genmc_output { + eprintln!("GenMC error report:"); + eprintln!("{}", self.get_result_message()); + } else { + eprintln!( + "(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.)" + ); } + } - eprintln!("(GenMC) Verification complete. No errors were detected."); - - let explored_execution_count = genmc_ctx.get_explored_execution_count(); - let blocked_execution_count = genmc_ctx.get_blocked_execution_count(); + /// Given the time taken for the estimation mode run, print the expected time range for verification. + /// Verbose output also includes information about the expected number of executions and how many estimation rounds were explored or got blocked. + fn print_estimation_output(&self, genmc_config: &GenmcConfig, elapsed_time_sec: f64) { + let EstimationResult { mean, sd, explored_execs, blocked_execs } = + self.get_estimation_results(); + #[allow(clippy::as_conversions)] + let time_per_exec_sec = elapsed_time_sec / (explored_execs as f64 + blocked_execs as f64); + let estimated_mean_sec = time_per_exec_sec * mean; + let estimated_sd_sec = time_per_exec_sec * sd; - eprintln!("Number of complete executions explored: {explored_execution_count}"); - if blocked_execution_count > 0 { - eprintln!("Number of blocked executions seen: {blocked_execution_count}"); + if genmc_config.verbose_output { + eprintln!("Finished estimation in {elapsed_time_sec:.2?}s"); + if blocked_execs != 0 { + eprintln!(" Explored executions: {explored_execs}"); + eprintln!(" Blocked executions: {blocked_execs}"); + } + eprintln!("Expected number of executions: {mean:.0} ± {sd:.0}"); + } + // The estimation can be out-of-bounds of an `f64`. + if !(mean.is_finite() && mean >= 0.0 && sd.is_finite() && sd >= 0.0) { + eprintln!("WARNING: Estimation gave weird results, there may have been an overflow."); } + eprintln!("Expected verification time: {estimated_mean_sec:.2}s ± {estimated_sd_sec:.2}s"); + } - // Return the return code of the last execution. - return Some(return_code); + /// Given the time taken for the verification mode run, print the expected time range for verification. + /// Verbose output also includes information about the expected number of executions and how many estimation rounds were explored or got blocked. + fn print_verification_output(&self, genmc_config: &GenmcConfig, elapsed_time_sec: f64) { + let explored_execution_count = self.get_explored_execution_count(); + let blocked_execution_count = self.get_blocked_execution_count(); + eprintln!( + "Verification complete with {} executions. No errors found.", + explored_execution_count + blocked_execution_count + ); + if genmc_config.verbose_output { + if blocked_execution_count > 0 { + eprintln!("Number of complete executions explored: {explored_execution_count}"); + eprintln!("Number of blocked executions seen: {blocked_execution_count}"); + } + eprintln!("Verification took {elapsed_time_sec:.2?}s."); + } } - unreachable!() } diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr index 946d9a2124b88..00de74009d9b8 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: Undefined Behavior: Non-atomic race --> tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC | @@ -15,5 +16,6 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr index 121ded2a181ca..501957a90d3ac 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: Undefined Behavior: Non-atomic race --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC | @@ -15,5 +16,6 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr index 121ded2a181ca..501957a90d3ac 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: Undefined Behavior: Non-atomic race --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC | @@ -15,5 +16,6 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr index 121ded2a181ca..501957a90d3ac 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: Undefined Behavior: Non-atomic race --> tests/genmc/fail/data_race/weak_orderings.rs:LL:CC | @@ -15,5 +16,6 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr index 5a8948ff9b4b8..9c3ba1d4c5924 100644 --- a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: abnormal termination: the program aborted execution --> tests/genmc/fail/loom/buggy_inc.rs:LL:CC | @@ -9,5 +10,6 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr index a6c3ed7055e75..db92d0573fad2 100644 --- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: abnormal termination: the program aborted execution --> tests/genmc/fail/loom/store_buffering.rs:LL:CC | @@ -9,5 +10,6 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr index cbfb6ec833eb0..773f86a975967 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | @@ -9,5 +10,6 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr index cbfb6ec833eb0..773f86a975967 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | @@ -9,5 +10,6 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr index cbfb6ec833eb0..773f86a975967 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... error: abnormal termination: the program aborted execution --> tests/genmc/fail/simple/2w2w_weak.rs:LL:CC | @@ -9,5 +10,6 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr index d97b8b3d92f48..31438f9352fe6 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... warning: GenMC currently does not model the failure ordering for `compare_exchange`. Success ordering 'Release' was upgraded to 'AcqRel' to match failure ordering 'Acquire'. Miri with GenMC might miss bugs related to this memory access. --> tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC | @@ -18,5 +19,4 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/p LL | f(); | ^^^ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 +Verification complete with 2 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr index 3b22247ee44cb..7867be2dbe8ed 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 +Running GenMC Verification... +Verification complete with 1 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr index 3b22247ee44cb..7867be2dbe8ed 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/rmw_ops.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 +Running GenMC Verification... +Verification complete with 1 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr b/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2cowr.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_2sc_scf.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release1.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_3sc_1rel.release2.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.sc.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4rel.weak.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/2w2w_4sc.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr index c760b44605112..d6ec73a8c6672 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIW-acq-sc.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 16 +Running GenMC Verification... +Verification complete with 16 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr index 4fc77b63f3803..7ea2dd5085136 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... [1, 1, 1, 1, 1] [1, 1, 1, 0, 1] [1, 1, 1, 0, 0] @@ -26,5 +27,4 @@ [0, 0, 0, 0, 0] [0, 0, 0, 0, 1] [0, 0, 0, 0, 0] -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 28 +Verification complete with 28 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB.stderr b/src/tools/miri/tests/genmc/pass/litmus/LB.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/LB.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/LB.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr index c879e95a17085..e414cd5e064d9 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/LB_incMPs.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 15 +Running GenMC Verification... +Verification complete with 15 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/MP.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/MP.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr index 4551c00b0575d..29b59ce3bc1a3 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... X=1, Y=2, a=Err(1), b=Ok(1), c=2 X=1, Y=2, a=Err(1), b=Ok(1), c=1 X=1, Y=2, a=Err(1), b=Ok(1), c=0 @@ -34,5 +35,4 @@ X=1, Y=1, a=Err(0), b=Err(0), c=0 X=1, Y=1, a=Err(0), b=Err(0), c=1 X=1, Y=1, a=Err(0), b=Err(0), c=0 X=1, Y=1, a=Err(0), b=Err(0), c=0 -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 +Verification complete with 36 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr index c5e34b00642aa..423ee6dc39996 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU_rels_acq.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 13 +Running GenMC Verification... +Verification complete with 13 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr index 2be9a6c7fbded..f527b61202327 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_incMPs.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 7 +Running GenMC Verification... +Verification complete with 7 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/MP_rels_acqf.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB.stderr b/src/tools/miri/tests/genmc/pass/litmus/SB.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/SB.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/SB.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/SB_2sc_scf.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr index 8dd2fbe1b9757..c8fbb8951a386 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.sc.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... a=2, b=1, X=1, Y=3 a=4, b=1, X=1, Y=4 a=3, b=1, X=1, Y=3 @@ -16,5 +17,4 @@ a=3, b=0, X=1, Y=1 a=1, b=1, X=1, Y=3 a=1, b=1, X=1, Y=1 a=1, b=0, X=1, Y=1 -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 18 +Verification complete with 18 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr index 65622575de21d..72c59d33f77cf 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.weak.stderr @@ -1,3 +1,4 @@ +Running GenMC Verification... a=2, b=1, X=1, Y=3 a=4, b=1, X=1, Y=4 a=4, b=0, X=1, Y=4 @@ -20,5 +21,4 @@ a=1, b=1, X=1, Y=3 a=1, b=0, X=1, Y=3 a=1, b=1, X=1, Y=1 a=1, b=0, X=1, Y=1 -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 22 +Verification complete with 22 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr index 2be9a6c7fbded..f527b61202327 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_acq.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 7 +Running GenMC Verification... +Verification complete with 7 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/atomicpo.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr b/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr index 01701dfe6918a..bde951866d013 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 +Running GenMC Verification... +Verification complete with 2 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr b/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr index 01701dfe6918a..bde951866d013 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 +Running GenMC Verification... +Verification complete with 2 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/cii.stderr b/src/tools/miri/tests/genmc/pass/litmus/cii.stderr index be75e68fde77d..b9bdf2245aed6 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/cii.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/cii.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 +Running GenMC Verification... +Verification complete with 6 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr.stderr index be75e68fde77d..b9bdf2245aed6 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/corr.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/corr.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 +Running GenMC Verification... +Verification complete with 6 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr index 0667962f99c88..a67635dee1bef 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/corr0.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 +Running GenMC Verification... +Verification complete with 4 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr index f6d07e9c77b2b..384425fc43c67 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/corr1.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 +Running GenMC Verification... +Verification complete with 36 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr b/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr index 78a90b63feab6..07fd2d4de180c 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/corr2.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 +Running GenMC Verification... +Verification complete with 72 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/corw.stderr b/src/tools/miri/tests/genmc/pass/litmus/corw.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/corw.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/corw.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr b/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/cowr.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr index 00394048ec5c6..a031dfc8977a5 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/cumul-release.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 8 +Running GenMC Verification... +Verification complete with 8 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/default.stderr b/src/tools/miri/tests/genmc/pass/litmus/default.stderr index e0313930282ea..87d38d250411a 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/default.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/default.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 12 +Running GenMC Verification... +Verification complete with 12 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr b/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr index 15017249dc3a7..5006f11fefb1c 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/detour.join.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 9 +Running GenMC Verification... +Verification complete with 9 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr b/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr index 15017249dc3a7..5006f11fefb1c 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/detour.no_join.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 9 +Running GenMC Verification... +Verification complete with 9 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr index 3b6ba238f5342..c09b50e282f1e 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/fr_w_w_w_reads.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 210 +Running GenMC Verification... +Verification complete with 210 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr b/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr index be75e68fde77d..b9bdf2245aed6 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/inc2w.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 +Running GenMC Verification... +Verification complete with 6 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr index b5f8cd15b683f..770fb7ef88046 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/inc_inc_RR_W_RR.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 600 +Running GenMC Verification... +Verification complete with 600 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr b/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr index 115b1986ce557..485142e945a72 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/riwi.stderr @@ -1,2 +1,2 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 +Running GenMC Verification... +Verification complete with 3 executions. No errors found. diff --git a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs index a193dcf0683ea..3256c9f421193 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.rs @@ -1,6 +1,8 @@ -//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows -Zmiri-genmc-estimate // Translated from GenMC's "litmus/viktor-relseq" test. +// +// This test also checks that we can run the GenMC estimation mode. #![no_main] diff --git a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr index d63ac5199d5d4..c53d5c569b9ca 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr +++ b/src/tools/miri/tests/genmc/pass/litmus/viktor-relseq.stderr @@ -1,2 +1,4 @@ -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 180 +Estimating GenMC verification time... +Expected verification time: [MEAN] ± [SD] +Running GenMC Verification... +Verification complete with 180 executions. No errors found. diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index b7286d9a3673a..efaaf9fc84170 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -277,6 +277,8 @@ regexes! { r"\bsys/([a-z_]+)/[a-z]+\b" => "sys/$1/PLATFORM", // erase paths into the crate registry r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", + // remove time print from GenMC estimation mode output. + "\nExpected verification time: .* ± .*" => "\nExpected verification time: [MEAN] ± [SD]", } enum Dependencies { From 7e270ab27e80c06275c80fa1041f5ff9af3ffcd4 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 18 Sep 2025 22:22:29 +0900 Subject: [PATCH 236/251] chore: Update rustc deps --- src/tools/rust-analyzer/Cargo.lock | 44 +++++++++---------- src/tools/rust-analyzer/Cargo.toml | 16 +++---- .../crates/hir-ty/src/next_solver/interner.rs | 14 ++++++ 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b70b89ea543d8..9475391acdb7f 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da95e732b424802b1f043ab4007c78a0fc515ab249587abbea4634bf5fdce9a" +checksum = "aa338fe027a8915009ca4a5a1cb7dde5fb4bc4170a928cb9462fda9d2ec52cec" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1875,24 +1875,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3838d9d7a3a5cdc511cfb6ad78740ce532f75a2366d3fc3b9853ea1b5c872779" +checksum = "a8468ef77e5359b3a51e327406f29ca2283a4feef93d3ba04f6740b274636922" [[package]] name = "ra-ap-rustc_hashes" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc8995d268d3bb4ece910f575ea5a063d6003e193ec155d15703b65882d53fb" +checksum = "300bc3264ccc1e7a5b3f065023a02e612774206d8ad685b3b05c2e4e317f8daa" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0ccdf6e5627c6c3e54e571e52ce0bc8b94d5f0b94b7460269ca68a4706be69" +checksum = "5eaa4a3ff61302e45c17ee72e067a39179081c19a12aa03192975a095f5d4e4b" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1900,9 +1900,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd28f42362b5c9fb9b8766c3189df02a402b13363600c6885e11027889f03ee6" +checksum = "0f7af0d51ee6bd5280be8e2eb7e9ac5cd9fc87af7a99f50cdb1316a8779c15ab" dependencies = [ "proc-macro2", "quote", @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c31a82f091b910a27ee53a86a9af28a2df10c3484e2f1bbfe70633aa84dee9" +checksum = "ee4e7df9bf702c855de7bea5e3c14b96f0728d4712edb663b0f4b183622341fc" dependencies = [ "memchr", "unicode-properties", @@ -1922,9 +1922,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cac6c2b5a8924209d4ca682cbc507252c58a664911e0ef463c112882ba6f72" +checksum = "15768080a276088a4a6af1e08a4ca622c57d5b4845ce5329dbbd71a2e025eecb" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a085a1cf902dcca8abbc537faaef154bbccbbb51850f779ce5484ae3782b5d8f" +checksum = "e6f0c54b200c47768eaf142b1c829da9be1a3331a5defa4ac60bad4996f474e9" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba32e3985367bc34856b41c7604133649d4a367eb5d7bdf50623025731459d8" +checksum = "a078fbbefda17d8d5d2c9d6b5a1f9ee1e23fae5f057e74784f6b95c189b0b048" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1958,9 +1958,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9911d72f75d85d21fe88374d7bcec94f2200feffb7234108a24cc3da7c3591" +checksum = "644e980122cdb7f2d7e175f33224dc6df414e8cf3e5dfbba9047e63336d9737a" dependencies = [ "arrayvec", "bitflags 2.9.1", @@ -1978,9 +1978,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.128.0" +version = "0.129.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f539b87991683ce17cc52e62600fdf2b4a8af43952db30387edc1a576d3b43" +checksum = "827d242d444cea86d9a64b5ce99db1462c9d43c7c6226d44ec2bc621b7c253c0" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index c5ffad544a6b3..94ec1a07438f4 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,14 +89,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.128", default-features = false } -ra-ap-rustc_parse_format = { version = "0.128", default-features = false } -ra-ap-rustc_index = { version = "0.128", default-features = false } -ra-ap-rustc_abi = { version = "0.128", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.128", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.128", default-features = false } -ra-ap-rustc_type_ir = { version = "0.128", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.128", default-features = false } +ra-ap-rustc_lexer = { version = "0.129", default-features = false } +ra-ap-rustc_parse_format = { version = "0.129", default-features = false } +ra-ap-rustc_index = { version = "0.129", default-features = false } +ra-ap-rustc_abi = { version = "0.129", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.129", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.129", default-features = false } +ra-ap-rustc_type_ir = { version = "0.129", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.129", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 062f6aebf160d..9cf56bef9578a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1674,6 +1674,20 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } + fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, mut f: impl FnMut(Self::ImplId)) { + let Some(krate) = self.krate else { return }; + + for impls in self.db.trait_impls_in_deps(krate).iter() { + for impl_id in impls.for_trait(trait_def_id.0) { + let impl_data = self.db.impl_signature(impl_id); + let self_ty_ref = &impl_data.store[impl_data.self_ty]; + if matches!(self_ty_ref, hir_def::type_ref::TypeRef::TypeParam(_)) { + f(impl_id.into()); + } + } + } + } + fn has_item_definition(self, def_id: Self::DefId) -> bool { // FIXME(next-solver): should check if the associated item has a value. true From c6b4f6f33f6e78d575a477a3398af44e47b18630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 18 Sep 2025 19:03:35 +0300 Subject: [PATCH 237/251] Bump rustc crates again --- src/tools/rust-analyzer/Cargo.lock | 44 +++++++++---------- src/tools/rust-analyzer/Cargo.toml | 16 +++---- .../crates/hir-ty/src/display.rs | 6 +-- .../crates/hir-ty/src/infer/coerce.rs | 2 +- .../crates/hir-ty/src/lower_nextsolver.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 2 +- .../crates/hir-ty/src/mir/eval.rs | 2 +- .../hir-ty/src/next_solver/fulfill/errors.rs | 2 +- .../crates/hir-ty/src/next_solver/mapping.rs | 6 +-- .../crates/hir-ty/src/next_solver/ty.rs | 23 ++++------ .../crates/hir-ty/src/next_solver/util.rs | 2 +- 11 files changed, 50 insertions(+), 57 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9475391acdb7f..be21cfd9c24fe 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa338fe027a8915009ca4a5a1cb7dde5fb4bc4170a928cb9462fda9d2ec52cec" +checksum = "dd3df655461690c1554bc0e355f19495eef6cd729dc29f01bd07cb7cd2a0990a" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1875,24 +1875,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8468ef77e5359b3a51e327406f29ca2283a4feef93d3ba04f6740b274636922" +checksum = "10f55c57676d67dba036171d23f7941a9c3b884181c5e93d3bd5fa599f8f129b" [[package]] name = "ra-ap-rustc_hashes" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300bc3264ccc1e7a5b3f065023a02e612774206d8ad685b3b05c2e4e317f8daa" +checksum = "feec9ffe50d93b8f17770b49d4cbf46280e074a105c7c9325c8d2171cf395b76" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eaa4a3ff61302e45c17ee72e067a39179081c19a12aa03192975a095f5d4e4b" +checksum = "a73bab902bcdeceac4a9630ed732d19f6b7189cbe8e828a94156a780bd8e1196" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1900,9 +1900,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7af0d51ee6bd5280be8e2eb7e9ac5cd9fc87af7a99f50cdb1316a8779c15ab" +checksum = "88c7906b654b9c4188aee3fde82a7449bac6e156a5d86ad923bae05bd5040690" dependencies = [ "proc-macro2", "quote", @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e7df9bf702c855de7bea5e3c14b96f0728d4712edb663b0f4b183622341fc" +checksum = "acec3893f60dca2a37f9e838c08f3f3c8e012ce36194c2b84da96781e794e359" dependencies = [ "memchr", "unicode-properties", @@ -1922,9 +1922,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15768080a276088a4a6af1e08a4ca622c57d5b4845ce5329dbbd71a2e025eecb" +checksum = "c4626e22dc21062bdac1a8340b497365e1983a69cc271d7d052a62348b88bd7f" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f0c54b200c47768eaf142b1c829da9be1a3331a5defa4ac60bad4996f474e9" +checksum = "47a95720d31edf45a8ccde190c14954425af0d53c9b6d4702fdd905b3951a2e1" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a078fbbefda17d8d5d2c9d6b5a1f9ee1e23fae5f057e74784f6b95c189b0b048" +checksum = "0c1ebf6272bf11f0ba3b909e3405f547de32ea19d745b8fef11f1fb643b72fcd" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1958,9 +1958,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644e980122cdb7f2d7e175f33224dc6df414e8cf3e5dfbba9047e63336d9737a" +checksum = "a9aa8f1344940e097514403c53bb5a1e4f5c3986da888461bc651373d195090b" dependencies = [ "arrayvec", "bitflags 2.9.1", @@ -1978,9 +1978,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.129.0" +version = "0.130.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "827d242d444cea86d9a64b5ce99db1462c9d43c7c6226d44ec2bc621b7c253c0" +checksum = "30c65f1a5da2f3c39d72a56687694568abb203b3737a2321090e112da04958b3" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 94ec1a07438f4..e81c4088122bf 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,14 +89,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.129", default-features = false } -ra-ap-rustc_parse_format = { version = "0.129", default-features = false } -ra-ap-rustc_index = { version = "0.129", default-features = false } -ra-ap-rustc_abi = { version = "0.129", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.129", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.129", default-features = false } -ra-ap-rustc_type_ir = { version = "0.129", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.129", default-features = false } +ra-ap-rustc_lexer = { version = "0.130", default-features = false } +ra-ap-rustc_parse_format = { version = "0.130", default-features = false } +ra-ap-rustc_index = { version = "0.130", default-features = false } +ra-ap-rustc_abi = { version = "0.130", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.130", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.130", default-features = false } +ra-ap-rustc_type_ir = { version = "0.130", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.130", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 0a514f389b471..519e4b59237f4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -897,7 +897,7 @@ fn render_const_scalar_inner( } f.write_str("]") } - TyKind::Dynamic(_, _, _) => { + TyKind::Dynamic(_, _) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); let Ok(t) = memory_map.vtable_ty(ty_id) else { @@ -1064,7 +1064,7 @@ fn render_const_scalar_inner( | TyKind::Bound(_, _) | TyKind::Infer(_) => f.write_str(""), // The below arms are unreachable, since we handled them in ref case. - TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _, _) => f.write_str(""), + TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _) => f.write_str(""), } } @@ -1213,7 +1213,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { }) }; let (preds_to_print, has_impl_fn_pred) = match t.kind() { - TyKind::Dynamic(bounds, region, _) => { + TyKind::Dynamic(bounds, region) => { let render_lifetime = f.render_region(region); ( bounds.len() + render_lifetime as usize, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 88b10e87e531e..7930d8b0ed68f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -611,7 +611,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { | TyKind::Slice(_) | TyKind::FnDef(_, _) | TyKind::FnPtr(_, _) - | TyKind::Dynamic(_, _, _) + | TyKind::Dynamic(_, _) | TyKind::Closure(_, _) | TyKind::CoroutineClosure(_, _) | TyKind::Coroutine(_, _) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 2292e5c99413e..b8e0599dba289 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -790,7 +790,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }, None => Region::new_static(self.interner), }; - Ty::new_dynamic(self.interner, bounds, region, rustc_type_ir::DynKind::Dyn) + Ty::new_dynamic(self.interner, bounds, region) } else { // FIXME: report error // (additional non-auto traits, associated type rebound, or no resolved trait) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index a4427517a10b8..7fa3d31fe5fdc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -164,7 +164,7 @@ impl TyFingerprint { rustc_ast_ir::Mutability::Not => TyFingerprint::RawPtr(Mutability::Not), }, TyKind::Foreign(def) => TyFingerprint::ForeignType(crate::to_foreign_def_id(def.0)), - TyKind::Dynamic(bounds, _, _) => { + TyKind::Dynamic(bounds, _) => { let trait_ref = bounds .as_slice() .iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 6f950b8022c98..3e658cb93ed8a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -2446,7 +2446,7 @@ impl<'db> Evaluator<'db> { | TyKind::Foreign(_) | TyKind::Error(_) | TyKind::Placeholder(_) - | TyKind::Dynamic(_, _, _) + | TyKind::Dynamic(_, _) | TyKind::Alias(_, _) | TyKind::Bound(_, _) | TyKind::Infer(_) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs index 6cd9e55acf0e7..b49fac18c5dd3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -1146,7 +1146,7 @@ mod wf { } TyKind::UnsafeBinder(ty) => {} - TyKind::Dynamic(data, r, _) => { + TyKind::Dynamic(data, r) => { // WfObject // // Here, we defer WF checking due to higher-ranked diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index d8a86ea083e08..b24b996b0927c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -370,8 +370,7 @@ impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { }), ); let region = dyn_ty.lifetime.to_nextsolver(interner); - let kind = rustc_type_ir::DynKind::Dyn; - rustc_type_ir::TyKind::Dynamic(bounds, region, kind) + rustc_type_ir::TyKind::Dynamic(bounds, region) } chalk_ir::TyKind::Alias(alias_ty) => match alias_ty { chalk_ir::AliasTy::Projection(projection_ty) => { @@ -1445,8 +1444,7 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) TyKind::Function(fnptr) } - rustc_type_ir::TyKind::Dynamic(preds, region, dyn_kind) => { - assert!(matches!(dyn_kind, rustc_type_ir::DynKind::Dyn)); + rustc_type_ir::TyKind::Dynamic(preds, region) => { let self_ty = Ty::new_bound( interner, DebruijnIndex::from_u32(1), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index e6c444d0d6bed..70139e8666948 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -178,7 +178,7 @@ impl<'db> Ty<'db> { | TyKind::Never | TyKind::Error(_) => true, - TyKind::Str | TyKind::Slice(_) | TyKind::Dynamic(_, _, _) => match sizedness { + TyKind::Str | TyKind::Slice(_) | TyKind::Dynamic(_, _) => match sizedness { SizedTraitKind::Sized => false, SizedTraitKind::MetaSized => true, }, @@ -421,7 +421,7 @@ impl<'db> TypeSuperVisitable> for Ty<'db> { } TyKind::Slice(typ) => typ.visit_with(visitor), TyKind::Adt(_, args) => args.visit_with(visitor), - TyKind::Dynamic(ref trait_ty, ref reg, _) => { + TyKind::Dynamic(ref trait_ty, ref reg) => { try_visit!(trait_ty.visit_with(visitor)); reg.visit_with(visitor) } @@ -486,11 +486,9 @@ impl<'db> TypeSuperFoldable> for Ty<'db> { } TyKind::Slice(typ) => TyKind::Slice(typ.try_fold_with(folder)?), TyKind::Adt(tid, args) => TyKind::Adt(tid, args.try_fold_with(folder)?), - TyKind::Dynamic(trait_ty, region, representation) => TyKind::Dynamic( - trait_ty.try_fold_with(folder)?, - region.try_fold_with(folder)?, - representation, - ), + TyKind::Dynamic(trait_ty, region) => { + TyKind::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) + } TyKind::Tuple(ts) => TyKind::Tuple(ts.try_fold_with(folder)?), TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.try_fold_with(folder)?), TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.try_fold_with(folder)?, hdr), @@ -537,11 +535,9 @@ impl<'db> TypeSuperFoldable> for Ty<'db> { TyKind::Array(typ, sz) => TyKind::Array(typ.fold_with(folder), sz.fold_with(folder)), TyKind::Slice(typ) => TyKind::Slice(typ.fold_with(folder)), TyKind::Adt(tid, args) => TyKind::Adt(tid, args.fold_with(folder)), - TyKind::Dynamic(trait_ty, region, representation) => TyKind::Dynamic( - trait_ty.fold_with(folder), - region.fold_with(folder), - representation, - ), + TyKind::Dynamic(trait_ty, region) => { + TyKind::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) + } TyKind::Tuple(ts) => TyKind::Tuple(ts.fold_with(folder)), TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.fold_with(folder)), TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.fold_with(folder), hdr), @@ -676,9 +672,8 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { interner: DbInterner<'db>, preds: as rustc_type_ir::Interner>::BoundExistentialPredicates, region: as rustc_type_ir::Interner>::Region, - kind: rustc_type_ir::DynKind, ) -> Self { - Ty::new(interner, TyKind::Dynamic(preds, region, kind)) + Ty::new(interner, TyKind::Dynamic(preds, region)) } fn new_coroutine( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index a50f20a565ee2..a7f9817f9c08e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -461,7 +461,7 @@ pub fn sizedness_constraint_for_ty<'db>( | CoroutineWitness(..) | Never => None, // these are never sized - Str | Slice(..) | Dynamic(_, _, rustc_type_ir::DynKind::Dyn) => match sizedness { + Str | Slice(..) | Dynamic(_, _) => match sizedness { // Never `Sized` SizedTraitKind::Sized => Some(ty), // Always `MetaSized` From 7f55f5761cd44b8ad49efb976ae650602fc2d42a Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 12 Sep 2025 20:29:23 +0000 Subject: [PATCH 238/251] Allow windows resource compiler to be overridden It is now required to provide a resource compiler on windows when compiling rust. This allows toolchain builders to explicitly provide a path to an alternative, such as llvm-rc, instead of the one that's provided by the Windows SDK. --- bootstrap.example.toml | 3 +++ compiler/rustc_windows_rc/src/lib.rs | 7 +++++-- src/bootstrap/src/core/builder/cargo.rs | 5 +++++ src/bootstrap/src/core/config/config.rs | 3 +++ src/bootstrap/src/core/config/toml/build.rs | 1 + src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 51529751dd58f..0cd571134ef15 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -325,6 +325,9 @@ # Defaults to the Python interpreter used to execute x.py. #build.python = "python" +# The path to (or name of) the resource compiler executable to use on Windows. +#build.windows-rc = "rc.exe" + # The path to the REUSE executable to use. Note that REUSE is not required in # most cases, as our tooling relies on a cached (and shrunk) copy of the # REUSE output present in the git repository and in our source tarballs. diff --git a/compiler/rustc_windows_rc/src/lib.rs b/compiler/rustc_windows_rc/src/lib.rs index caa5e5ef27656..5e95557501ea2 100644 --- a/compiler/rustc_windows_rc/src/lib.rs +++ b/compiler/rustc_windows_rc/src/lib.rs @@ -35,8 +35,11 @@ pub fn compile_windows_resource_file( resources_dir.push("resources"); fs::create_dir_all(&resources_dir).unwrap(); - let resource_compiler = - find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe"); + let resource_compiler = if let Ok(path) = env::var("RUSTC_WINDOWS_RC") { + path.into() + } else { + find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe") + }; let rc_path = resources_dir.join(file_stem.with_extension("rc")); diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 6121bf7d9cd62..ee2bb710674c0 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1227,6 +1227,11 @@ impl Builder<'_> { rustflags.arg("-Zehcont-guard"); } + // Optionally override the rc.exe when compiling rustc on Windows. + if let Some(windows_rc) = &self.config.windows_rc { + cargo.env("RUSTC_WINDOWS_RC", windows_rc); + } + // For `cargo doc` invocations, make rustdoc print the Rust version into the docs // This replaces spaces with tabs because RUSTDOCFLAGS does not // support arguments with regular spaces. Hopefully someday Cargo will diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index efb7ad9169971..a97399b3d4ae9 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -273,6 +273,7 @@ pub struct Config { pub gdb: Option, pub lldb: Option, pub python: Option, + pub windows_rc: Option, pub reuse: Option, pub cargo_native_static: bool, pub configure_args: Vec, @@ -450,6 +451,7 @@ impl Config { nodejs: build_nodejs, npm: build_npm, python: build_python, + windows_rc: build_windows_rc, reuse: build_reuse, locked_deps: build_locked_deps, vendor: build_vendor, @@ -1342,6 +1344,7 @@ impl Config { .unwrap_or(rust_debug == Some(true)), vendor, verbose_tests, + windows_rc: build_windows_rc.map(PathBuf::from), // tidy-alphabetical-end } } diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 25c19f1070a39..a9d4d3961c9b7 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -37,6 +37,7 @@ define_config! { nodejs: Option = "nodejs", npm: Option = "npm", python: Option = "python", + windows_rc: Option = "windows-rc", reuse: Option = "reuse", locked_deps: Option = "locked-deps", vendor: Option = "vendor", diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 2c48cebd2df05..6b187578c31ec 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -551,4 +551,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "There is now a bootstrap option called `rust.parallel-frontend-threads`, which can be used to set the number of threads for the compiler frontend used during compilation of Rust code.", }, + ChangeInfo { + change_id: 146663, + severity: ChangeSeverity::Info, + summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.", + }, ]; From 60f0407ba313fbea163ee4fe21a8a71ba633ecc6 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 19 Sep 2025 03:04:14 +0900 Subject: [PATCH 239/251] fix: Fix `indexmap` with `in-rust-tree` --- src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index deee8dd1ff06e..073a02908deeb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -45,9 +45,4 @@ pub type PolyFnSig<'db> = Binder<'db, rustc_type_ir::FnSig>>; pub type TypingMode<'db> = rustc_type_ir::TypingMode>; pub type TypeError<'db> = rustc_type_ir::error::TypeError>; pub type QueryResult<'db> = rustc_type_ir::solve::QueryResult>; - -#[cfg(feature = "in-rust-tree")] -use rustc_data_structure::sorted_map::index_map as indexmap; - -pub type FxIndexMap = - indexmap::IndexMap>; +pub type FxIndexMap = rustc_type_ir::data_structures::IndexMap; From 3ba8b8e0e5284ad3c33eb6a1490a6adcea4c105d Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 19 Sep 2025 03:26:03 +0900 Subject: [PATCH 240/251] minor: Yet another rustc crates bump --- src/tools/rust-analyzer/Cargo.lock | 44 +++++++++---------- src/tools/rust-analyzer/Cargo.toml | 16 +++---- .../crates/hir-ty/src/infer/unify.rs | 2 +- .../crates/hir-ty/src/next_solver/fulfill.rs | 4 +- .../hir-ty/src/next_solver/fulfill/errors.rs | 22 ++++++---- .../hir-ty/src/next_solver/infer/context.rs | 9 ++++ .../hir-ty/src/next_solver/infer/select.rs | 8 ++-- .../crates/hir-ty/src/next_solver/inspect.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 4 +- 9 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index be21cfd9c24fe..97c4f06dd5960 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd3df655461690c1554bc0e355f19495eef6cd729dc29f01bd07cb7cd2a0990a" +checksum = "016c05852e89655395fbf7d5e729e31cd58b2690480b3a8468eb2b38c91f3756" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1875,24 +1875,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f55c57676d67dba036171d23f7941a9c3b884181c5e93d3bd5fa599f8f129b" +checksum = "c5bff48bd0a26f17a4e2e8610bc393296c3d002e221f5c6c4d2875e6a64a3b4b" [[package]] name = "ra-ap-rustc_hashes" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feec9ffe50d93b8f17770b49d4cbf46280e074a105c7c9325c8d2171cf395b76" +checksum = "5d15e7571f6f31f6112fd2fcbc3450a6ef477cc6bfe51643a2b110436a7455f0" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a73bab902bcdeceac4a9630ed732d19f6b7189cbe8e828a94156a780bd8e1196" +checksum = "60a30f0a15682f1194e5812cc3544266f3494ca8fb3c5033e8b9c08f4f8b8c6d" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1900,9 +1900,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c7906b654b9c4188aee3fde82a7449bac6e156a5d86ad923bae05bd5040690" +checksum = "e2f82c9176b964591e1657a9f0fae2850525542d39075c49c2459afc291f4804" dependencies = [ "proc-macro2", "quote", @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acec3893f60dca2a37f9e838c08f3f3c8e012ce36194c2b84da96781e794e359" +checksum = "585c71ff7da5ca1e8a0c65d5e7cec7ab2a7e9e45b6859543bd2d0be21bee631c" dependencies = [ "memchr", "unicode-properties", @@ -1922,9 +1922,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4626e22dc21062bdac1a8340b497365e1983a69cc271d7d052a62348b88bd7f" +checksum = "839f521a6cd97c71b2b6681604ace38a9c6737f7a223d072fa8f909879f9dc4b" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a95720d31edf45a8ccde190c14954425af0d53c9b6d4702fdd905b3951a2e1" +checksum = "83e7872a4fa0620937b60fc6270aa8c31864cb324357553e2be5b2bdc25fa89a" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1ebf6272bf11f0ba3b909e3405f547de32ea19d745b8fef11f1fb643b72fcd" +checksum = "4ecd7f9b960c8cf1e9d02a25297f52a520134132164cfedd3e69fee4f294d41c" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1958,9 +1958,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aa8f1344940e097514403c53bb5a1e4f5c3986da888461bc651373d195090b" +checksum = "9494498f8f7c57a5b4ea4e35a6c554cca8d5323adb534d13dc6cd117a7e00e4d" dependencies = [ "arrayvec", "bitflags 2.9.1", @@ -1978,9 +1978,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.130.0" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c65f1a5da2f3c39d72a56687694568abb203b3737a2321090e112da04958b3" +checksum = "28ed893760b86529080af59438c28dfa9ca976b821cfd0a3b0eb9591932847e6" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index e81c4088122bf..513af11a87aad 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -89,14 +89,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.130", default-features = false } -ra-ap-rustc_parse_format = { version = "0.130", default-features = false } -ra-ap-rustc_index = { version = "0.130", default-features = false } -ra-ap-rustc_abi = { version = "0.130", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.130", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.130", default-features = false } -ra-ap-rustc_type_ir = { version = "0.130", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.130", default-features = false } +ra-ap-rustc_lexer = { version = "0.131", default-features = false } +ra-ap-rustc_parse_format = { version = "0.131", default-features = false } +ra-ap-rustc_index = { version = "0.131", default-features = false } +ra-ap-rustc_abi = { version = "0.131", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.131", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.131", default-features = false } +ra-ap-rustc_type_ir = { version = "0.131", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.131", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 77eaf83eec73d..1687857ae1ac2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -910,7 +910,7 @@ impl<'db> InferenceTable<'db> { match result { Ok((_, Certainty::Yes)) => {} Err(rustc_type_ir::solve::NoSolution) => {} - Ok((_, Certainty::Maybe(_))) => { + Ok((_, Certainty::Maybe { .. })) => { self.fulfillment_cx.register_predicate_obligation( &self.infer_ctxt, Obligation::new( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs index a8183ab422792..34dff37972e7e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -182,7 +182,7 @@ impl<'db> FulfillmentCtxt<'db> { if let Some(certainty) = delegate.compute_goal_fast_path(goal, Span::dummy()) { match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => { + Certainty::Maybe { .. } => { self.obligations.register(obligation, None); } } @@ -211,7 +211,7 @@ impl<'db> FulfillmentCtxt<'db> { match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on), + Certainty::Maybe { .. } => self.obligations.register(obligation, stalled_on), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs index b49fac18c5dd3..ab4a229fbc05f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -153,15 +153,17 @@ pub(super) fn fulfillment_error_for_stalled<'db>( Span::dummy(), None, ) { - Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { - (FulfillmentErrorCode::Ambiguity { overflow: None }, true) - } + Ok(GoalEvaluation { + certainty: Certainty::Maybe { cause: MaybeCause::Ambiguity, .. }, + .. + }) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true), Ok(GoalEvaluation { certainty: - Certainty::Maybe(MaybeCause::Overflow { - suggest_increasing_limit, - keep_constraints: _, - }), + Certainty::Maybe { + cause: + MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ }, + .. + }, .. }) => ( FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, @@ -314,7 +316,8 @@ impl<'db> BestObligation<'db> { .instantiate_proof_tree_for_nested_goal(GoalSource::Misc, obligation.as_goal()); // Skip nested goals that aren't the *reason* for our goal's failure. match (self.consider_ambiguities, nested_goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. })) + | (false, Err(_)) => {} _ => continue, } @@ -456,7 +459,8 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { let interner = goal.infcx().interner; // Skip goals that aren't the *reason* for our goal's failure. match (self.consider_ambiguities, goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + (true, Ok(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. })) | (false, Err(_)) => { + } _ => return ControlFlow::Continue(()), } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs index 45ce7e6f6cc75..5aa5ad14af551 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs @@ -321,4 +321,13 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { fn sub_unify_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { self.sub_unify_ty_vids_raw(a, b); } + + fn opaques_with_sub_unified_hidden_type( + &self, + _ty: TyVid, + ) -> Vec> { + // FIXME: I guess we are okay without this for now since currently r-a lacks of + // detailed checks over opaque types. Might need to implement this in future. + vec![] + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs index d656d94f4f91e..4f111fa662668 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs @@ -208,7 +208,7 @@ impl<'db> ProofTreeVisitor<'db> for Select { // Don't winnow until `Certainty::Yes` -- we don't need to winnow until // codegen, and only on the good path. - if matches!(goal.result().unwrap(), Certainty::Maybe(..)) { + if matches!(goal.result().unwrap(), Certainty::Maybe { .. }) { return ControlFlow::Break(Ok(None)); } @@ -241,7 +241,7 @@ fn candidate_should_be_dropped_in_favor_of<'db>( ) -> bool { // Don't winnow until `Certainty::Yes` -- we don't need to winnow until // codegen, and only on the good path. - if matches!(other.result().unwrap(), Certainty::Maybe(..)) { + if matches!(other.result().unwrap(), Certainty::Maybe { .. }) { return false; } @@ -284,13 +284,13 @@ fn candidate_should_be_dropped_in_favor_of<'db>( } fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option> { - if let Certainty::Maybe(..) = cand.shallow_certainty() { + if let Certainty::Maybe { .. } = cand.shallow_certainty() { return None; } let nested = match cand.result().expect("expected positive result") { Certainty::Yes => Vec::new(), - Certainty::Maybe(_) => cand + Certainty::Maybe { .. } => cand .instantiate_nested_goals() .into_iter() .map(|nested| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs index cab3c69118f64..f9d0aa99cf4f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs @@ -350,7 +350,7 @@ impl<'a, 'db> InspectGoal<'a, 'db> { inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { assert!(matches!( shallow_certainty.replace(c), - None | Some(Certainty::Maybe(MaybeCause::Ambiguity)) + None | Some(Certainty::Maybe { cause: MaybeCause::Ambiguity, .. }) )); } inspect::ProbeStep::NestedProbe(ref probe) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index d73d7da4b9b98..8b6836c0e90bf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -277,7 +277,7 @@ pub fn next_trait_solve( Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args), ), - Ok((_, Certainty::Maybe(_), args)) => { + Ok((_, Certainty::Maybe { .. }, args)) => { let subst = convert_canonical_args_for_result( DbInterner::new_with(db, Some(krate), block), args, @@ -316,7 +316,7 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>( Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( convert_canonical_args_for_result(infer_ctxt.interner, args), ), - Ok((_, Certainty::Maybe(_), args)) => { + Ok((_, Certainty::Maybe { .. }, args)) => { let subst = convert_canonical_args_for_result(infer_ctxt.interner, args); NextTraitSolveResult::Uncertain(chalk_ir::Canonical { binders: subst.binders, From 00bfe9ce6ed3d21b39a40309974dda5c19dc6fb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Sep 2025 20:41:06 +0200 Subject: [PATCH 241/251] tweak genmc error report note --- src/tools/miri/src/concurrency/genmc/run.rs | 10 +++++----- .../tests/genmc/fail/data_race/mpu2_rels_rlx.stderr | 3 ++- .../genmc/fail/data_race/weak_orderings.rel_rlx.stderr | 3 ++- .../genmc/fail/data_race/weak_orderings.rlx_acq.stderr | 3 ++- .../genmc/fail/data_race/weak_orderings.rlx_rlx.stderr | 3 ++- src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr | 3 ++- .../tests/genmc/fail/loom/store_buffering.genmc.stderr | 3 ++- .../tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr | 3 ++- .../tests/genmc/fail/simple/2w2w_weak.release4.stderr | 3 ++- .../tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr | 3 ++- 10 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs index bc2f5f7b79ec4..33c5b6b0a005f 100644 --- a/src/tools/miri/src/concurrency/genmc/run.rs +++ b/src/tools/miri/src/concurrency/genmc/run.rs @@ -70,7 +70,7 @@ fn run_genmc_mode_impl<'tcx>( // Execute the program until completion to get the return value, or return if an error happens: let Some(return_code) = eval_entry(genmc_ctx.clone()) else { - genmc_ctx.print_genmc_output(genmc_config); + genmc_ctx.print_genmc_output(genmc_config, tcx); return None; }; @@ -97,7 +97,7 @@ fn run_genmc_mode_impl<'tcx>( // Since we don't have any span information for the error at this point, // we just print GenMC's error string, and the full GenMC output if requested. eprintln!("(GenMC) Error detected: {error}"); - genmc_ctx.print_genmc_output(genmc_config); + genmc_ctx.print_genmc_output(genmc_config, tcx); return None; } } @@ -110,13 +110,13 @@ impl GenmcCtx { /// /// This message can be very verbose and is likely not useful for the average user. /// This function should be called *after* Miri has printed all of its output. - fn print_genmc_output(&self, genmc_config: &GenmcConfig) { + fn print_genmc_output(&self, genmc_config: &GenmcConfig, tcx: TyCtxt<'_>) { if genmc_config.print_genmc_output { eprintln!("GenMC error report:"); eprintln!("{}", self.get_result_message()); } else { - eprintln!( - "(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.)" + tcx.dcx().note( + "add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report" ); } } diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr index 00de74009d9b8..1ffb55f22e6e0 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -16,6 +16,7 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr index 501957a90d3ac..b0037c211c69d 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -16,6 +16,7 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr index 501957a90d3ac..b0037c211c69d 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -16,6 +16,7 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr index 501957a90d3ac..b0037c211c69d 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -16,6 +16,7 @@ note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/f LL | f(); | ^^^ -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr index 9c3ba1d4c5924..290cdf90a0847 100644 --- a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr @@ -10,6 +10,7 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr index db92d0573fad2..7742790e33307 100644 --- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr @@ -10,6 +10,7 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr index 773f86a975967..80ac7206644c6 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr @@ -10,6 +10,7 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr index 773f86a975967..80ac7206644c6 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr @@ -10,6 +10,7 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr index 773f86a975967..80ac7206644c6 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr @@ -10,6 +10,7 @@ LL | std::process::abort(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -(Add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report.) +note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report + error: aborting due to 1 previous error From 01cd04f78d86cdc1a60441fd9d6d08aa2fe05a2f Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 19 Sep 2025 04:20:24 +0900 Subject: [PATCH 242/251] fix: Fix one more thing in `in-rust-tree` --- .../rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs index f9d0aa99cf4f3..128135d8debe8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs @@ -1,4 +1,4 @@ -pub use ra_ap_rustc_next_trait_solver::solve::inspect::*; +pub use rustc_next_trait_solver::solve::inspect::*; use rustc_ast_ir::try_visit; use rustc_next_trait_solver::{ From f19b560fa96ca8dd4352db6372f662fa32942a9f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Sep 2025 22:02:46 +0200 Subject: [PATCH 243/251] implement sqrt for f16 and f128 --- src/tools/miri/src/intrinsics/math.rs | 16 ++++++++++ src/tools/miri/tests/pass/float.rs | 44 ++++++++++++++++++--------- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index 21d4a92e7d288..ca81454a98c08 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -20,6 +20,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match intrinsic_name { // Operations we can do with soft-floats. + "sqrtf16" => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f16()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } "sqrtf32" => { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -36,6 +44,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } + "sqrtf128" => { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?.to_f128()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } "fmaf32" => { let [a, b, c] = check_intrinsic_arg_count(args)?; diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 9f1b3f612b2d2..3ce5ea8356bd5 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -281,6 +281,35 @@ fn basic() { assert_eq!(34.2f64.abs(), 34.2f64); assert_eq!((-1.0f128).abs(), 1.0f128); assert_eq!(34.2f128.abs(), 34.2f128); + + assert_eq!(64_f16.sqrt(), 8_f16); + assert_eq!(64_f32.sqrt(), 8_f32); + assert_eq!(64_f64.sqrt(), 8_f64); + assert_eq!(64_f128.sqrt(), 8_f128); + assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); + assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); + assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); + assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); + assert_eq!(0.0_f16.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); + assert_eq!(0.0_f32.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); + assert_eq!(0.0_f64.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); + assert_eq!(0.0_f128.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); + assert_eq!((-0.0_f16).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); + assert_eq!((-0.0_f32).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); + assert_eq!((-0.0_f64).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); + assert_eq!((-0.0_f128).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); + assert!((-5.0_f16).sqrt().is_nan()); + assert!((-5.0_f32).sqrt().is_nan()); + assert!((-5.0_f64).sqrt().is_nan()); + assert!((-5.0_f128).sqrt().is_nan()); + assert!(f16::NEG_INFINITY.sqrt().is_nan()); + assert!(f32::NEG_INFINITY.sqrt().is_nan()); + assert!(f64::NEG_INFINITY.sqrt().is_nan()); + assert!(f128::NEG_INFINITY.sqrt().is_nan()); + assert!(f16::NAN.sqrt().is_nan()); + assert!(f32::NAN.sqrt().is_nan()); + assert!(f64::NAN.sqrt().is_nan()); + assert!(f128::NAN.sqrt().is_nan()); } /// Test casts from floats to ints and back @@ -1012,21 +1041,6 @@ pub fn libm() { unsafe { ldexp(a, b) } } - assert_eq!(64_f32.sqrt(), 8_f32); - assert_eq!(64_f64.sqrt(), 8_f64); - assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); - assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); - assert_eq!(0.0_f32.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); - assert_eq!(0.0_f64.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal); - assert_eq!((-0.0_f32).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); - assert_eq!((-0.0_f64).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal); - assert!((-5.0_f32).sqrt().is_nan()); - assert!((-5.0_f64).sqrt().is_nan()); - assert!(f32::NEG_INFINITY.sqrt().is_nan()); - assert!(f64::NEG_INFINITY.sqrt().is_nan()); - assert!(f32::NAN.sqrt().is_nan()); - assert!(f64::NAN.sqrt().is_nan()); - assert_approx_eq!(25f32.powi(-2), 0.0016f32); assert_approx_eq!(23.2f64.powi(2), 538.24f64); From 77f2d865549e8f2e1ad656c8202de9bfa6d2e354 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Sep 2025 22:13:15 +0200 Subject: [PATCH 244/251] share sqrt implemention across float types --- src/tools/miri/src/intrinsics/math.rs | 52 ++++++++++----------------- src/tools/miri/src/math.rs | 12 +++---- 2 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index ca81454a98c08..b9c99f2859468 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -1,5 +1,5 @@ use rand::Rng; -use rustc_apfloat::{self, Float, Round}; +use rustc_apfloat::{self, Float, FloatConvert, Round}; use rustc_middle::mir; use rustc_middle::ty::{self, FloatTy}; @@ -7,6 +7,20 @@ use self::helpers::{ToHost, ToSoft}; use super::check_intrinsic_arg_count; use crate::*; +fn sqrt<'tcx, F: Float + FloatConvert + Into>( + this: &mut MiriInterpCx<'tcx>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + let [f] = check_intrinsic_arg_count(args)?; + let f = this.read_scalar(f)?; + let f: F = f.to_float()?; + // Sqrt is specified to be fully precise. + let res = math::sqrt(f); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest) +} + impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_math_intrinsic( @@ -20,38 +34,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match intrinsic_name { // Operations we can do with soft-floats. - "sqrtf16" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f16()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "sqrtf32" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "sqrtf64" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } - "sqrtf128" => { - let [f] = check_intrinsic_arg_count(args)?; - let f = this.read_scalar(f)?.to_f128()?; - // Sqrt is specified to be fully precise. - let res = math::sqrt(f); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; - } + "sqrtf16" => sqrt::(this, args, dest)?, + "sqrtf32" => sqrt::(this, args, dest)?, + "sqrtf64" => sqrt::(this, args, dest)?, + "sqrtf128" => sqrt::(this, args, dest)?, "fmaf32" => { let [a, b, c] = check_intrinsic_arg_count(args)?; diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index 401e6dd7aab84..50472ed3638e9 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -2,7 +2,7 @@ use std::ops::Neg; use std::{f32, f64}; use rand::Rng as _; -use rustc_apfloat::Float as _; +use rustc_apfloat::Float; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, Semantics, SingleS}; use rustc_middle::ty::{self, FloatTy, ScalarInt}; @@ -317,19 +317,19 @@ where } } -pub(crate) fn sqrt(x: IeeeFloat) -> IeeeFloat { +pub(crate) fn sqrt(x: F) -> F { match x.category() { // preserve zero sign rustc_apfloat::Category::Zero => x, // propagate NaN rustc_apfloat::Category::NaN => x, // sqrt of negative number is NaN - _ if x.is_negative() => IeeeFloat::NAN, + _ if x.is_negative() => F::NAN, // sqrt(∞) = ∞ - rustc_apfloat::Category::Infinity => IeeeFloat::INFINITY, + rustc_apfloat::Category::Infinity => F::INFINITY, rustc_apfloat::Category::Normal => { // Floating point precision, excluding the integer bit - let prec = i32::try_from(S::PRECISION).unwrap() - 1; + let prec = i32::try_from(F::PRECISION).unwrap() - 1; // x = 2^(exp - prec) * mant // where mant is an integer with prec+1 bits @@ -394,7 +394,7 @@ pub(crate) fn sqrt(x: IeeeFloat) -> IeeeFl res = (res + 1) >> 1; // Build resulting value with res as mantissa and exp/2 as exponent - IeeeFloat::from_u128(res).value.scalbn(exp / 2 - prec) + F::from_u128(res).value.scalbn(exp / 2 - prec) } } } From 45e5c765c660463179128c5deaf6f56ff24f3578 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:17:39 -0700 Subject: [PATCH 245/251] fix tidy spellchecking on windows --- src/tools/tidy/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 2a9c3963d2d86..f7920e3205ab2 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -237,7 +237,7 @@ pub fn ensure_version_or_cargo_install( if !cargo_exit_code.success() { return Err(io::Error::other("cargo install failed")); } - let bin_path = tool_bin_dir.join(bin_name); + let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); assert!( matches!(bin_path.try_exists(), Ok(true)), "cargo install did not produce the expected binary" From 7af6e590a4d1f66770b49698bd01d88cca98f18f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Sep 2025 23:33:38 +0200 Subject: [PATCH 246/251] update lockfile --- Cargo.lock | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d39cfefea0c77..910a03eaffca2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width 0.2.1", ] [[package]] @@ -937,23 +937,24 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.168" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa144b12f11741f0dab5b4182896afad46faa0598b6a061f7b9d17a21837ba7" +checksum = "2f81de88da10862f22b5b3a60f18f6f42bbe7cb8faa24845dd7b1e4e22190e77" dependencies = [ "cc", + "cxx-build", "cxxbridge-cmd", "cxxbridge-flags", "cxxbridge-macro", - "foldhash", + "foldhash 0.2.0", "link-cplusplus", ] [[package]] name = "cxx-build" -version = "1.0.168" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d3cbb84fb003242941c231b45ca9417e786e66e94baa39584bd99df3a270b6" +checksum = "5edd58bf75c3fdfc80d79806403af626570662f7b6cc782a7fabe156166bd6d6" dependencies = [ "cc", "codespan-reporting", @@ -966,9 +967,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.168" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa36b7b249d43f67a3f54bd65788e35e7afe64bbc671396387a48b3e8aaea94" +checksum = "fd46bf2b541a4e0c2d5abba76607379ee05d68e714868e3cb406dc8d591ce2d2" dependencies = [ "clap", "codespan-reporting", @@ -980,15 +981,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.168" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77707c70f6563edc5429618ca34a07241b75ebab35bd01d46697c75d58f8ddfe" +checksum = "2c79b68f6a3a8f809d39b38ae8af61305a6113819b19b262643b9c21353b92d9" [[package]] name = "cxxbridge-macro" -version = "1.0.168" +version = "1.0.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede6c0fb7e318f0a11799b86ee29dcf17b9be2960bd379a6c38e1a96a6010fff" +checksum = "862b7fdb048ff9ef0779a0d0a03affd09746c4c875543746b640756be9cff2af" dependencies = [ "indexmap", "proc-macro2", @@ -1388,6 +1389,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1567,7 +1574,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -2160,9 +2167,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" dependencies = [ "cc", ] From a08e6499e6a215021684681448ed0f3ce60c827a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 16 Sep 2025 15:18:42 +0200 Subject: [PATCH 247/251] move `mod canonical` out of `eval_ctxt` --- .../src/{ => canonical}/canonicalizer.rs | 0 .../canonical.rs => canonical/mod.rs} | 226 ++---------------- compiler/rustc_next_trait_solver/src/lib.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 202 +++++++++++++++- .../src/solve/inspect/build.rs | 2 +- .../src/solve/inspect/mod.rs | 2 - .../rustc_next_trait_solver/src/solve/mod.rs | 19 -- .../src/solve/search_graph.rs | 3 +- .../src/solve/inspect/analyse.rs | 4 +- 9 files changed, 229 insertions(+), 231 deletions(-) rename compiler/rustc_next_trait_solver/src/{ => canonical}/canonicalizer.rs (100%) rename compiler/rustc_next_trait_solver/src/{solve/eval_ctxt/canonical.rs => canonical/mod.rs} (58%) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs similarity index 100% rename from compiler/rustc_next_trait_solver/src/canonicalizer.rs rename to compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs similarity index 58% rename from compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs rename to compiler/rustc_next_trait_solver/src/canonical/mod.rs index 889588afe61ff..35881acf0c753 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -11,27 +11,25 @@ use std::iter; +use canonicalizer::Canonicalizer; use rustc_index::IndexVec; -use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::solve::OpaqueTypesJank; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, }; -use tracing::{debug, instrument, trace}; +use tracing::instrument; -use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; -use crate::solve::eval_ctxt::CurrentGoalKind; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, - MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, - QueryResult, Response, inspect, response_no_constraints_raw, + NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect, }; +pub mod canonicalizer; + trait ResponseT { fn var_values(&self) -> CanonicalVarValues; } @@ -78,199 +76,6 @@ where (orig_values, query_input) } - /// To return the constraints of a canonical query to the caller, we canonicalize: - /// - /// - `var_values`: a map from bound variables in the canonical goal to - /// the values inferred while solving the instantiated goal. - /// - `external_constraints`: additional constraints which aren't expressible - /// using simple unification of inference variables. - /// - /// This takes the `shallow_certainty` which represents whether we're confident - /// that the final result of the current goal only depends on the nested goals. - /// - /// In case this is `Certainty::Maybe`, there may still be additional nested goals - /// or inference constraints required for this candidate to be hold. The candidate - /// always requires all already added constraints and nested goals. - #[instrument(level = "trace", skip(self), ret)] - pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( - &mut self, - shallow_certainty: Certainty, - ) -> QueryResult { - self.inspect.make_canonical_response(shallow_certainty); - - let goals_certainty = self.try_evaluate_added_goals()?; - assert_eq!( - self.tainted, - Ok(()), - "EvalCtxt is tainted -- nested goals may have been dropped in a \ - previous call to `try_evaluate_added_goals!`" - ); - - // We only check for leaks from universes which were entered inside - // of the query. - self.delegate.leak_check(self.max_input_universe).map_err(|NoSolution| { - trace!("failed the leak check"); - NoSolution - })?; - - let (certainty, normalization_nested_goals) = - match (self.current_goal_kind, shallow_certainty) { - // When normalizing, we've replaced the expected term with an unconstrained - // inference variable. This means that we dropped information which could - // have been important. We handle this by instead returning the nested goals - // to the caller, where they are then handled. We only do so if we do not - // need to recompute the `NormalizesTo` goal afterwards to avoid repeatedly - // uplifting its nested goals. This is the case if the `shallow_certainty` is - // `Certainty::Yes`. - (CurrentGoalKind::NormalizesTo, Certainty::Yes) => { - let goals = std::mem::take(&mut self.nested_goals); - // As we return all ambiguous nested goals, we can ignore the certainty - // returned by `self.try_evaluate_added_goals()`. - if goals.is_empty() { - assert!(matches!(goals_certainty, Certainty::Yes)); - } - ( - Certainty::Yes, - NestedNormalizationGoals( - goals.into_iter().map(|(s, g, _)| (s, g)).collect(), - ), - ) - } - _ => { - let certainty = shallow_certainty.and(goals_certainty); - (certainty, NestedNormalizationGoals::empty()) - } - }; - - if let Certainty::Maybe { - cause: cause @ MaybeCause::Overflow { keep_constraints: false, .. }, - opaque_types_jank, - } = certainty - { - // If we have overflow, it's probable that we're substituting a type - // into itself infinitely and any partial substitutions in the query - // response are probably not useful anyways, so just return an empty - // query response. - // - // This may prevent us from potentially useful inference, e.g. - // 2 candidates, one ambiguous and one overflow, which both - // have the same inference constraints. - // - // Changing this to retain some constraints in the future - // won't be a breaking change, so this is good enough for now. - return Ok(self.make_ambiguous_response_no_constraints(cause, opaque_types_jank)); - } - - let external_constraints = - self.compute_external_query_constraints(certainty, normalization_nested_goals); - let (var_values, mut external_constraints) = - eager_resolve_vars(self.delegate, (self.var_values, external_constraints)); - - // Remove any trivial or duplicated region constraints once we've resolved regions - let mut unique = HashSet::default(); - external_constraints.region_constraints.retain(|outlives| { - outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) - }); - - let canonical = Canonicalizer::canonicalize_response( - self.delegate, - self.max_input_universe, - &mut Default::default(), - Response { - var_values, - certainty, - external_constraints: self.cx().mk_external_constraints(external_constraints), - }, - ); - - // HACK: We bail with overflow if the response would have too many non-region - // inference variables. This tends to only happen if we encounter a lot of - // ambiguous alias types which get replaced with fresh inference variables - // during generalization. This prevents hangs caused by an exponential blowup, - // see tests/ui/traits/next-solver/coherence-alias-hang.rs. - match self.current_goal_kind { - // We don't do so for `NormalizesTo` goals as we erased the expected term and - // bailing with overflow here would prevent us from detecting a type-mismatch, - // causing a coherence error in diesel, see #131969. We still bail with overflow - // when later returning from the parent AliasRelate goal. - CurrentGoalKind::NormalizesTo => {} - CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { - let num_non_region_vars = canonical - .variables - .iter() - .filter(|c| !c.is_region() && c.is_existential()) - .count(); - if num_non_region_vars > self.cx().recursion_limit() { - debug!(?num_non_region_vars, "too many inference variables -> overflow"); - return Ok(self.make_ambiguous_response_no_constraints( - MaybeCause::Overflow { - suggest_increasing_limit: true, - keep_constraints: false, - }, - OpaqueTypesJank::AllGood, - )); - } - } - } - - Ok(canonical) - } - - /// Constructs a totally unconstrained, ambiguous response to a goal. - /// - /// Take care when using this, since often it's useful to respond with - /// ambiguity but return constrained variables to guide inference. - pub(in crate::solve) fn make_ambiguous_response_no_constraints( - &self, - cause: MaybeCause, - opaque_types_jank: OpaqueTypesJank, - ) -> CanonicalResponse { - response_no_constraints_raw( - self.cx(), - self.max_input_universe, - self.variables, - Certainty::Maybe { cause, opaque_types_jank }, - ) - } - - /// Computes the region constraints and *new* opaque types registered when - /// proving a goal. - /// - /// If an opaque was already constrained before proving this goal, then the - /// external constraints do not need to record that opaque, since if it is - /// further constrained by inference, that will be passed back in the var - /// values. - #[instrument(level = "trace", skip(self), ret)] - fn compute_external_query_constraints( - &self, - certainty: Certainty, - normalization_nested_goals: NestedNormalizationGoals, - ) -> ExternalConstraintsData { - // We only return region constraints once the certainty is `Yes`. This - // is necessary as we may drop nested goals on ambiguity, which may result - // in unconstrained inference variables in the region constraints. It also - // prevents us from emitting duplicate region constraints, avoiding some - // unnecessary work. This slightly weakens the leak check in case it uses - // region constraints from an ambiguous nested goal. This is tested in both - // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and - // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. - let region_constraints = if certainty == Certainty::Yes { - self.delegate.make_deduplicated_outlives_constraints() - } else { - Default::default() - }; - - // We only return *newly defined* opaque types from canonical queries. - // - // Constraints for any existing opaque types are already tracked by changes - // to the `var_values`. - let opaque_types = self - .delegate - .clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries); - - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } - } - /// After calling a canonical query, we apply the constraints returned /// by the query using this function. /// @@ -469,7 +274,7 @@ where /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub(in crate::solve) fn make_canonical_state( +pub fn make_canonical_state( delegate: &D, var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, @@ -515,3 +320,22 @@ where EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values, span); data } + +pub fn response_no_constraints_raw( + cx: I, + max_universe: ty::UniverseIndex, + variables: I::CanonicalVarKinds, + certainty: Certainty, +) -> CanonicalResponse { + ty::Canonical { + max_universe, + variables, + value: Response { + var_values: ty::CanonicalVarValues::make_identity(cx, variables), + // FIXME: maybe we should store the "no response" version in cx, like + // we do for cx.types and stuff. + external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), + certainty, + }, + } +} diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index d3965e14c68a8..5fa29b7d9f813 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -10,7 +10,7 @@ #![allow(rustc::usage_of_type_ir_traits)] // tidy-alphabetical-end -pub mod canonicalizer; +pub mod canonical; pub mod coherence; pub mod delegate; pub mod placeholder; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 5df7c92d88145..8f9b68dbac4f4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -17,6 +17,8 @@ use rustc_type_ir::{ use tracing::{debug, instrument, trace}; use super::has_only_region_constraints; +use crate::canonical::canonicalizer::Canonicalizer; +use crate::canonical::response_no_constraints_raw; use crate::coherence; use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; @@ -24,12 +26,11 @@ use crate::resolve::eager_resolve_vars; use crate::solve::search_graph::SearchGraph; use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ - CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, - GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, - inspect, + CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT, + Goal, GoalEvaluation, GoalSource, GoalStalledOn, HasChanged, MaybeCause, + NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, inspect, }; -pub(super) mod canonical; mod probe; /// The kind of goal we're currently proving. @@ -1223,6 +1224,199 @@ where vec![] } } + + /// To return the constraints of a canonical query to the caller, we canonicalize: + /// + /// - `var_values`: a map from bound variables in the canonical goal to + /// the values inferred while solving the instantiated goal. + /// - `external_constraints`: additional constraints which aren't expressible + /// using simple unification of inference variables. + /// + /// This takes the `shallow_certainty` which represents whether we're confident + /// that the final result of the current goal only depends on the nested goals. + /// + /// In case this is `Certainty::Maybe`, there may still be additional nested goals + /// or inference constraints required for this candidate to be hold. The candidate + /// always requires all already added constraints and nested goals. + #[instrument(level = "trace", skip(self), ret)] + pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( + &mut self, + shallow_certainty: Certainty, + ) -> QueryResult { + self.inspect.make_canonical_response(shallow_certainty); + + let goals_certainty = self.try_evaluate_added_goals()?; + assert_eq!( + self.tainted, + Ok(()), + "EvalCtxt is tainted -- nested goals may have been dropped in a \ + previous call to `try_evaluate_added_goals!`" + ); + + // We only check for leaks from universes which were entered inside + // of the query. + self.delegate.leak_check(self.max_input_universe).map_err(|NoSolution| { + trace!("failed the leak check"); + NoSolution + })?; + + let (certainty, normalization_nested_goals) = + match (self.current_goal_kind, shallow_certainty) { + // When normalizing, we've replaced the expected term with an unconstrained + // inference variable. This means that we dropped information which could + // have been important. We handle this by instead returning the nested goals + // to the caller, where they are then handled. We only do so if we do not + // need to recompute the `NormalizesTo` goal afterwards to avoid repeatedly + // uplifting its nested goals. This is the case if the `shallow_certainty` is + // `Certainty::Yes`. + (CurrentGoalKind::NormalizesTo, Certainty::Yes) => { + let goals = std::mem::take(&mut self.nested_goals); + // As we return all ambiguous nested goals, we can ignore the certainty + // returned by `self.try_evaluate_added_goals()`. + if goals.is_empty() { + assert!(matches!(goals_certainty, Certainty::Yes)); + } + ( + Certainty::Yes, + NestedNormalizationGoals( + goals.into_iter().map(|(s, g, _)| (s, g)).collect(), + ), + ) + } + _ => { + let certainty = shallow_certainty.and(goals_certainty); + (certainty, NestedNormalizationGoals::empty()) + } + }; + + if let Certainty::Maybe { + cause: cause @ MaybeCause::Overflow { keep_constraints: false, .. }, + opaque_types_jank, + } = certainty + { + // If we have overflow, it's probable that we're substituting a type + // into itself infinitely and any partial substitutions in the query + // response are probably not useful anyways, so just return an empty + // query response. + // + // This may prevent us from potentially useful inference, e.g. + // 2 candidates, one ambiguous and one overflow, which both + // have the same inference constraints. + // + // Changing this to retain some constraints in the future + // won't be a breaking change, so this is good enough for now. + return Ok(self.make_ambiguous_response_no_constraints(cause, opaque_types_jank)); + } + + let external_constraints = + self.compute_external_query_constraints(certainty, normalization_nested_goals); + let (var_values, mut external_constraints) = + eager_resolve_vars(self.delegate, (self.var_values, external_constraints)); + + // Remove any trivial or duplicated region constraints once we've resolved regions + let mut unique = HashSet::default(); + external_constraints.region_constraints.retain(|outlives| { + outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) + }); + + let canonical = Canonicalizer::canonicalize_response( + self.delegate, + self.max_input_universe, + &mut Default::default(), + Response { + var_values, + certainty, + external_constraints: self.cx().mk_external_constraints(external_constraints), + }, + ); + + // HACK: We bail with overflow if the response would have too many non-region + // inference variables. This tends to only happen if we encounter a lot of + // ambiguous alias types which get replaced with fresh inference variables + // during generalization. This prevents hangs caused by an exponential blowup, + // see tests/ui/traits/next-solver/coherence-alias-hang.rs. + match self.current_goal_kind { + // We don't do so for `NormalizesTo` goals as we erased the expected term and + // bailing with overflow here would prevent us from detecting a type-mismatch, + // causing a coherence error in diesel, see #131969. We still bail with overflow + // when later returning from the parent AliasRelate goal. + CurrentGoalKind::NormalizesTo => {} + CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { + let num_non_region_vars = canonical + .variables + .iter() + .filter(|c| !c.is_region() && c.is_existential()) + .count(); + if num_non_region_vars > self.cx().recursion_limit() { + debug!(?num_non_region_vars, "too many inference variables -> overflow"); + return Ok(self.make_ambiguous_response_no_constraints( + MaybeCause::Overflow { + suggest_increasing_limit: true, + keep_constraints: false, + }, + OpaqueTypesJank::AllGood, + )); + } + } + } + + Ok(canonical) + } + + /// Constructs a totally unconstrained, ambiguous response to a goal. + /// + /// Take care when using this, since often it's useful to respond with + /// ambiguity but return constrained variables to guide inference. + pub(in crate::solve) fn make_ambiguous_response_no_constraints( + &self, + cause: MaybeCause, + opaque_types_jank: OpaqueTypesJank, + ) -> CanonicalResponse { + response_no_constraints_raw( + self.cx(), + self.max_input_universe, + self.variables, + Certainty::Maybe { cause, opaque_types_jank }, + ) + } + + /// Computes the region constraints and *new* opaque types registered when + /// proving a goal. + /// + /// If an opaque was already constrained before proving this goal, then the + /// external constraints do not need to record that opaque, since if it is + /// further constrained by inference, that will be passed back in the var + /// values. + #[instrument(level = "trace", skip(self), ret)] + fn compute_external_query_constraints( + &self, + certainty: Certainty, + normalization_nested_goals: NestedNormalizationGoals, + ) -> ExternalConstraintsData { + // We only return region constraints once the certainty is `Yes`. This + // is necessary as we may drop nested goals on ambiguity, which may result + // in unconstrained inference variables in the region constraints. It also + // prevents us from emitting duplicate region constraints, avoiding some + // unnecessary work. This slightly weakens the leak check in case it uses + // region constraints from an ambiguous nested goal. This is tested in both + // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and + // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. + let region_constraints = if certainty == Certainty::Yes { + self.delegate.make_deduplicated_outlives_constraints() + } else { + Default::default() + }; + + // We only return *newly defined* opaque types from canonical queries. + // + // Constraints for any existing opaque types are already tracked by changes + // to the `var_values`. + let opaque_types = self + .delegate + .clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries); + + ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 2675ed0d0da65..4369148baf91d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -10,8 +10,8 @@ use derive_where::derive_where; use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; +use crate::canonical; use crate::delegate::SolverDelegate; -use crate::solve::eval_ctxt::canonical; use crate::solve::{Certainty, Goal, GoalSource, QueryResult, inspect}; /// We need to know whether to build a prove tree while evaluating. We diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs index 0d8c00601269b..65f32f1947fef 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs @@ -2,5 +2,3 @@ pub use rustc_type_ir::solve::inspect::*; mod build; pub(in crate::solve) use build::*; - -pub use crate::solve::eval_ctxt::canonical::instantiate_canonical_state; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index fb900b592d13b..afb86aaf8ab21 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -380,25 +380,6 @@ where } } -fn response_no_constraints_raw( - cx: I, - max_universe: ty::UniverseIndex, - variables: I::CanonicalVarKinds, - certainty: Certainty, -) -> CanonicalResponse { - ty::Canonical { - max_universe, - variables, - value: Response { - var_values: ty::CanonicalVarValues::make_identity(cx, variables), - // FIXME: maybe we should store the "no response" version in cx, like - // we do for cx.types and stuff. - external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), - certainty, - }, - } -} - /// The result of evaluating a goal. pub struct GoalEvaluation { /// The goal we've evaluated. This is the input goal, but potentially with its diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 289325d70550c..aa9dfc9a9a265 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -6,6 +6,7 @@ use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; use rustc_type_ir::{Interner, TypingMode}; +use crate::canonical::response_no_constraints_raw; use crate::delegate::SolverDelegate; use crate::solve::{ EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints, inspect, @@ -127,7 +128,7 @@ fn response_no_constraints( input: CanonicalInput, certainty: Certainty, ) -> QueryResult { - Ok(super::response_no_constraints_raw( + Ok(response_no_constraints_raw( cx, input.canonical.max_universe, input.canonical.variables, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 086a7a44786d6..c010add0fc50f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,9 +18,9 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; +use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::resolve::eager_resolve_vars; -use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; -use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _, inspect}; use rustc_span::Span; use tracing::instrument; From b83c0f0e94592d1a7eae1124e4e951f331ccf6c8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 16 Sep 2025 15:30:25 +0200 Subject: [PATCH 248/251] canonical: yeet `EvalCtxt`, mk `Canonicalizer` private --- .../src/canonical/canonicalizer.rs | 7 +- .../src/canonical/mod.rs | 419 +++++++++--------- .../src/solve/eval_ctxt/mod.rs | 18 +- 3 files changed, 233 insertions(+), 211 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 4b4ec4956eb88..b25671d676b9c 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -57,7 +57,7 @@ enum CanonicalizeMode { }, } -pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { +pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { delegate: &'a D, // Immutable field. @@ -83,7 +83,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { - pub fn canonicalize_response>( + pub(super) fn canonicalize_response>( delegate: &'a D, max_input_universe: ty::UniverseIndex, variables: &'a mut Vec, @@ -112,7 +112,6 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let (max_universe, variables) = canonicalizer.finalize(); Canonical { max_universe, variables, value } } - fn canonicalize_param_env( delegate: &'a D, variables: &'a mut Vec, @@ -195,7 +194,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// /// We want to keep the option of canonicalizing `'static` to an existential /// variable in the future by changing the way we detect global where-bounds. - pub fn canonicalize_input>( + pub(super) fn canonicalize_input>( delegate: &'a D, variables: &'a mut Vec, input: QueryInput, diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 35881acf0c753..e3520e238ed37 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -24,7 +24,7 @@ use tracing::instrument; use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; use crate::solve::{ - CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, + CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect, }; @@ -46,226 +46,248 @@ impl ResponseT for inspect::State { } } -impl EvalCtxt<'_, D> +/// Canonicalizes the goal remembering the original values +/// for each bound variable. +/// +/// This expects `goal` and `opaque_types` to be eager resolved. +pub(super) fn canonicalize_goal( + delegate: &D, + goal: Goal, + opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, +) -> (Vec, CanonicalInput) where D: SolverDelegate, I: Interner, { - /// Canonicalizes the goal remembering the original values - /// for each bound variable. - /// - /// This expects `goal` and `opaque_types` to be eager resolved. - pub(super) fn canonicalize_goal( - delegate: &D, - goal: Goal, - opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, - ) -> (Vec, CanonicalInput) { - let mut orig_values = Default::default(); - let canonical = Canonicalizer::canonicalize_input( - delegate, - &mut orig_values, - QueryInput { - goal, - predefined_opaques_in_body: delegate - .cx() - .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), - }, - ); - let query_input = - ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() }; - (orig_values, query_input) - } + let mut orig_values = Default::default(); + let canonical = Canonicalizer::canonicalize_input( + delegate, + &mut orig_values, + QueryInput { + goal, + predefined_opaques_in_body: delegate + .cx() + .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), + }, + ); + let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() }; + (orig_values, query_input) +} - /// After calling a canonical query, we apply the constraints returned - /// by the query using this function. - /// - /// This happens in three steps: - /// - we instantiate the bound variables of the query response - /// - we unify the `var_values` of the response with the `original_values` - /// - we apply the `external_constraints` returned by the query, returning - /// the `normalization_nested_goals` - pub(super) fn instantiate_and_apply_query_response( - delegate: &D, - param_env: I::ParamEnv, - original_values: &[I::GenericArg], - response: CanonicalResponse, - span: I::Span, - ) -> (NestedNormalizationGoals, Certainty) { - let instantiation = Self::compute_query_response_instantiation_values( - delegate, - &original_values, - &response, - span, - ); +pub(super) fn canonicalize_response( + delegate: &D, + max_input_universe: ty::UniverseIndex, + value: T, +) -> ty::Canonical +where + D: SolverDelegate, + I: Interner, + T: TypeFoldable, +{ + let mut orig_values = Default::default(); + let canonical = + Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut orig_values, value); + canonical +} - let Response { var_values, external_constraints, certainty } = - delegate.instantiate_canonical(response, instantiation); +/// After calling a canonical query, we apply the constraints returned +/// by the query using this function. +/// +/// This happens in three steps: +/// - we instantiate the bound variables of the query response +/// - we unify the `var_values` of the response with the `original_values` +/// - we apply the `external_constraints` returned by the query, returning +/// the `normalization_nested_goals` +pub(super) fn instantiate_and_apply_query_response( + delegate: &D, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + response: CanonicalResponse, + span: I::Span, +) -> (NestedNormalizationGoals, Certainty) +where + D: SolverDelegate, + I: Interner, +{ + let instantiation = + compute_query_response_instantiation_values(delegate, &original_values, &response, span); - Self::unify_query_var_values(delegate, param_env, &original_values, var_values, span); + let Response { var_values, external_constraints, certainty } = + delegate.instantiate_canonical(response, instantiation); - let ExternalConstraintsData { - region_constraints, - opaque_types, - normalization_nested_goals, - } = &*external_constraints; + unify_query_var_values(delegate, param_env, &original_values, var_values, span); - Self::register_region_constraints(delegate, region_constraints, span); - Self::register_new_opaque_types(delegate, opaque_types, span); + let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = + &*external_constraints; - (normalization_nested_goals.clone(), certainty) - } + register_region_constraints(delegate, region_constraints, span); + register_new_opaque_types(delegate, opaque_types, span); - /// This returns the canonical variable values to instantiate the bound variables of - /// the canonical response. This depends on the `original_values` for the - /// bound variables. - fn compute_query_response_instantiation_values>( - delegate: &D, - original_values: &[I::GenericArg], - response: &Canonical, - span: I::Span, - ) -> CanonicalVarValues { - // FIXME: Longterm canonical queries should deal with all placeholders - // created inside of the query directly instead of returning them to the - // caller. - let prev_universe = delegate.universe(); - let universes_created_in_query = response.max_universe.index(); - for _ in 0..universes_created_in_query { - delegate.create_next_universe(); - } + (normalization_nested_goals.clone(), certainty) +} + +/// This returns the canonical variable values to instantiate the bound variables of +/// the canonical response. This depends on the `original_values` for the +/// bound variables. +fn compute_query_response_instantiation_values( + delegate: &D, + original_values: &[I::GenericArg], + response: &Canonical, + span: I::Span, +) -> CanonicalVarValues +where + D: SolverDelegate, + I: Interner, + T: ResponseT, +{ + // FIXME: Longterm canonical queries should deal with all placeholders + // created inside of the query directly instead of returning them to the + // caller. + let prev_universe = delegate.universe(); + let universes_created_in_query = response.max_universe.index(); + for _ in 0..universes_created_in_query { + delegate.create_next_universe(); + } - let var_values = response.value.var_values(); - assert_eq!(original_values.len(), var_values.len()); + let var_values = response.value.var_values(); + assert_eq!(original_values.len(), var_values.len()); - // If the query did not make progress with constraining inference variables, - // we would normally create a new inference variables for bound existential variables - // only then unify this new inference variable with the inference variable from - // the input. - // - // We therefore instantiate the existential variable in the canonical response with the - // inference variable of the input right away, which is more performant. - let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); - for (original_value, result_value) in - iter::zip(original_values, var_values.var_values.iter()) - { - match result_value.kind() { - ty::GenericArgKind::Type(t) => { - // We disable the instantiation guess for inference variables - // and only use it for placeholders. We need to handle the - // `sub_root` of type inference variables which would make this - // more involved. They are also a lot rarer than region variables. - if let ty::Bound(debruijn, b) = t.kind() - && !matches!( - response.variables.get(b.var().as_usize()).unwrap(), - CanonicalVarKind::Ty { .. } - ) - { - assert_eq!(debruijn, ty::INNERMOST); - opt_values[b.var()] = Some(*original_value); - } + // If the query did not make progress with constraining inference variables, + // we would normally create a new inference variables for bound existential variables + // only then unify this new inference variable with the inference variable from + // the input. + // + // We therefore instantiate the existential variable in the canonical response with the + // inference variable of the input right away, which is more performant. + let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); + for (original_value, result_value) in iter::zip(original_values, var_values.var_values.iter()) { + match result_value.kind() { + ty::GenericArgKind::Type(t) => { + // We disable the instantiation guess for inference variables + // and only use it for placeholders. We need to handle the + // `sub_root` of type inference variables which would make this + // more involved. They are also a lot rarer than region variables. + if let ty::Bound(debruijn, b) = t.kind() + && !matches!( + response.variables.get(b.var().as_usize()).unwrap(), + CanonicalVarKind::Ty { .. } + ) + { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[b.var()] = Some(*original_value); } - ty::GenericArgKind::Lifetime(r) => { - if let ty::ReBound(debruijn, br) = r.kind() { - assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var()] = Some(*original_value); - } + } + ty::GenericArgKind::Lifetime(r) => { + if let ty::ReBound(debruijn, br) = r.kind() { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[br.var()] = Some(*original_value); } - ty::GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { - assert_eq!(debruijn, ty::INNERMOST); - opt_values[bv.var()] = Some(*original_value); - } + } + ty::GenericArgKind::Const(c) => { + if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[bv.var()] = Some(*original_value); } } } - CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| { - if kind.universe() != ty::UniverseIndex::ROOT { - // A variable from inside a binder of the query. While ideally these shouldn't - // exist at all (see the FIXME at the start of this method), we have to deal with - // them for now. - delegate.instantiate_canonical_var(kind, span, &var_values, |idx| { - prev_universe + idx.index() - }) - } else if kind.is_existential() { - // As an optimization we sometimes avoid creating a new inference variable here. - // - // All new inference variables we create start out in the current universe of the caller. - // This is conceptually wrong as these inference variables would be able to name - // more placeholders then they should be able to. However the inference variables have - // to "come from somewhere", so by equating them with the original values of the caller - // later on, we pull them down into their correct universe again. - if let Some(v) = opt_values[ty::BoundVar::from_usize(var_values.len())] { - v - } else { - delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe) - } + } + CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| { + if kind.universe() != ty::UniverseIndex::ROOT { + // A variable from inside a binder of the query. While ideally these shouldn't + // exist at all (see the FIXME at the start of this method), we have to deal with + // them for now. + delegate.instantiate_canonical_var(kind, span, &var_values, |idx| { + prev_universe + idx.index() + }) + } else if kind.is_existential() { + // As an optimization we sometimes avoid creating a new inference variable here. + // + // All new inference variables we create start out in the current universe of the caller. + // This is conceptually wrong as these inference variables would be able to name + // more placeholders then they should be able to. However the inference variables have + // to "come from somewhere", so by equating them with the original values of the caller + // later on, we pull them down into their correct universe again. + if let Some(v) = opt_values[ty::BoundVar::from_usize(var_values.len())] { + v } else { - // For placeholders which were already part of the input, we simply map this - // universal bound variable back the placeholder of the input. - original_values[kind.expect_placeholder_index()] + delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe) } - }) - } + } else { + // For placeholders which were already part of the input, we simply map this + // universal bound variable back the placeholder of the input. + original_values[kind.expect_placeholder_index()] + } + }) +} - /// Unify the `original_values` with the `var_values` returned by the canonical query.. - /// - /// This assumes that this unification will always succeed. This is the case when - /// applying a query response right away. However, calling a canonical query, doing any - /// other kind of trait solving, and only then instantiating the result of the query - /// can cause the instantiation to fail. This is not supported and we ICE in this case. - /// - /// We always structurally instantiate aliases. Relating aliases needs to be different - /// depending on whether the alias is *rigid* or not. We're only really able to tell - /// whether an alias is rigid by using the trait solver. When instantiating a response - /// from the solver we assume that the solver correctly handled aliases and therefore - /// always relate them structurally here. - #[instrument(level = "trace", skip(delegate))] - fn unify_query_var_values( - delegate: &D, - param_env: I::ParamEnv, - original_values: &[I::GenericArg], - var_values: CanonicalVarValues, - span: I::Span, - ) { - assert_eq!(original_values.len(), var_values.len()); +/// Unify the `original_values` with the `var_values` returned by the canonical query.. +/// +/// This assumes that this unification will always succeed. This is the case when +/// applying a query response right away. However, calling a canonical query, doing any +/// other kind of trait solving, and only then instantiating the result of the query +/// can cause the instantiation to fail. This is not supported and we ICE in this case. +/// +/// We always structurally instantiate aliases. Relating aliases needs to be different +/// depending on whether the alias is *rigid* or not. We're only really able to tell +/// whether an alias is rigid by using the trait solver. When instantiating a response +/// from the solver we assume that the solver correctly handled aliases and therefore +/// always relate them structurally here. +#[instrument(level = "trace", skip(delegate))] +fn unify_query_var_values( + delegate: &D, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + var_values: CanonicalVarValues, + span: I::Span, +) where + D: SolverDelegate, + I: Interner, +{ + assert_eq!(original_values.len(), var_values.len()); - for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { - let goals = - delegate.eq_structurally_relating_aliases(param_env, orig, response, span).unwrap(); - assert!(goals.is_empty()); - } + for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { + let goals = + delegate.eq_structurally_relating_aliases(param_env, orig, response, span).unwrap(); + assert!(goals.is_empty()); } +} - fn register_region_constraints( - delegate: &D, - outlives: &[ty::OutlivesPredicate], - span: I::Span, - ) { - for &ty::OutlivesPredicate(lhs, rhs) in outlives { - match lhs.kind() { - ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span), - ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span), - ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), - } +fn register_region_constraints( + delegate: &D, + outlives: &[ty::OutlivesPredicate], + span: I::Span, +) where + D: SolverDelegate, + I: Interner, +{ + for &ty::OutlivesPredicate(lhs, rhs) in outlives { + match lhs.kind() { + ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span), + ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span), + ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), } } +} - fn register_new_opaque_types( - delegate: &D, - opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], - span: I::Span, - ) { - for &(key, ty) in opaque_types { - let prev = delegate.register_hidden_type_in_storage(key, ty, span); - // We eagerly resolve inference variables when computing the query response. - // This can cause previously distinct opaque type keys to now be structurally equal. - // - // To handle this, we store any duplicate entries in a separate list to check them - // at the end of typeck/borrowck. We could alternatively eagerly equate the hidden - // types here. However, doing so is difficult as it may result in nested goals and - // any errors may make it harder to track the control flow for diagnostics. - if let Some(prev) = prev { - delegate.add_duplicate_opaque_type(key, prev, span); - } +fn register_new_opaque_types( + delegate: &D, + opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], + span: I::Span, +) where + D: SolverDelegate, + I: Interner, +{ + for &(key, ty) in opaque_types { + let prev = delegate.register_hidden_type_in_storage(key, ty, span); + // We eagerly resolve inference variables when computing the query response. + // This can cause previously distinct opaque type keys to now be structurally equal. + // + // To handle this, we store any duplicate entries in a separate list to check them + // at the end of typeck/borrowck. We could alternatively eagerly equate the hidden + // types here. However, doing so is difficult as it may result in nested goals and + // any errors may make it harder to track the control flow for diagnostics. + if let Some(prev) = prev { + delegate.add_duplicate_opaque_type(key, prev, span); } } } @@ -274,7 +296,7 @@ where /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub fn make_canonical_state( +pub fn make_canonical_state( delegate: &D, var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, @@ -293,7 +315,7 @@ where // FIXME: needs to be pub to be accessed by downstream // `rustc_trait_selection::solve::inspect::analyse`. -pub fn instantiate_canonical_state>( +pub fn instantiate_canonical_state( delegate: &D, span: I::Span, param_env: I::ParamEnv, @@ -303,6 +325,7 @@ pub fn instantiate_canonical_state>( where D: SolverDelegate, I: Interner, + T: TypeFoldable, { // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. @@ -313,11 +336,11 @@ where ); let instantiation = - EvalCtxt::compute_query_response_instantiation_values(delegate, orig_values, &state, span); + compute_query_response_instantiation_values(delegate, orig_values, &state, span); let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values, span); + unify_query_var_values(delegate, param_env, orig_values, var_values, span); data } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8f9b68dbac4f4..bb86357a85f8a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -17,8 +17,10 @@ use rustc_type_ir::{ use tracing::{debug, instrument, trace}; use super::has_only_region_constraints; -use crate::canonical::canonicalizer::Canonicalizer; -use crate::canonical::response_no_constraints_raw; +use crate::canonical::{ + canonicalize_goal, canonicalize_response, instantiate_and_apply_query_response, + response_no_constraints_raw, +}; use crate::coherence; use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; @@ -465,8 +467,7 @@ where let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = - Self::canonicalize_goal(self.delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, opaque_types); let canonical_result = self.search_graph.evaluate_goal( self.cx(), canonical_goal, @@ -481,7 +482,7 @@ where let has_changed = if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; - let (normalization_nested_goals, certainty) = Self::instantiate_and_apply_query_response( + let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, goal.param_env, &orig_values, @@ -1319,10 +1320,9 @@ where outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) }); - let canonical = Canonicalizer::canonicalize_response( + let canonical = canonicalize_response( self.delegate, self.max_input_universe, - &mut Default::default(), Response { var_values, certainty, @@ -1557,7 +1557,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let opaque_types = delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = EvalCtxt::canonicalize_goal(delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, opaque_types); let (canonical_result, final_revision) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); @@ -1574,7 +1574,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, Ok(response) => response, }; - let (normalization_nested_goals, _certainty) = EvalCtxt::instantiate_and_apply_query_response( + let (normalization_nested_goals, _certainty) = instantiate_and_apply_query_response( delegate, goal.param_env, &proof_tree.orig_values, From 6870e24fdbd9dc1770101457ebdcf9d5837f0b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 19 Sep 2025 08:08:23 +0300 Subject: [PATCH 249/251] Set WithCachedTypeInfo::stable_hash when in-tree --- src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs | 2 ++ .../rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs | 2 ++ src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 0b3582051bc07..7ebefa76ed029 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -36,6 +36,8 @@ impl<'db> Const<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, + #[cfg(feature = "in-rust-tree")] + stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Const::new_(interner.db(), InternedWrapperNoDebug(cached)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index 99b1354b6335f..86545415009a0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -227,6 +227,8 @@ impl<'db> Predicate<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, + #[cfg(feature = "in-rust-tree")] + stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Predicate::new_(interner.db(), InternedWrapperNoDebug(cached)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 70139e8666948..c7a747ade3e76 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -60,6 +60,8 @@ impl<'db> Ty<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, + #[cfg(feature = "in-rust-tree")] + stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Ty::new_(interner.db(), InternedWrapperNoDebug(cached)) } From 1db74d4845ed18b63e0c683f7a13714c3653a268 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Sep 2025 09:02:03 +0200 Subject: [PATCH 250/251] fix miri bootstrap build --- src/tools/miri/src/clock.rs | 16 +++++++++++++++- src/tools/miri/src/lib.rs | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index 47608f873a481..dbbe741a0714d 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -46,7 +46,21 @@ impl Instant { InstantKind::Virtual { nanoseconds: earlier }, ) => { let duration = nanoseconds.saturating_sub(earlier); - Duration::from_nanos_u128(duration) + cfg_select! { + bootstrap => { + // `Duration` does not provide a nice constructor from a `u128` of nanoseconds, + // so we have to implement this ourselves. + // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9). + // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX. + let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX); + // It is impossible for nanosecond to overflow because u32::MAX > 1e9. + let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap(); + Duration::new(seconds, nanosecond) + } + _ => { + Duration::from_nanos_u128(duration) + } + } } _ => panic!("all `Instant` must be of the same kind"), } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index dbc2a99593d2c..7f5f25b9f66b2 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -18,7 +18,7 @@ #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] -#![feature(duration_from_nanos_u128)] +#![cfg_attr(not(bootstrap), feature(duration_from_nanos_u128))] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, From 09d3120a99fee8d839e502bdb54f8117c0623c5d Mon Sep 17 00:00:00 2001 From: joboet Date: Sun, 14 Sep 2025 15:30:44 +0200 Subject: [PATCH 251/251] std: simplify host lookup --- library/std/src/net/socket_addr.rs | 41 +++++++------ library/std/src/sys/net/connection/sgx.rs | 29 ++-------- .../std/src/sys/net/connection/socket/mod.rs | 58 +++++-------------- .../src/sys/net/connection/socket/tests.rs | 2 +- .../std/src/sys/net/connection/uefi/mod.rs | 22 +------ .../std/src/sys/net/connection/unsupported.rs | 22 +------ library/std/src/sys/net/connection/wasip1.rs | 22 +------ .../std/src/sys/net/connection/xous/dns.rs | 45 +------------- .../std/src/sys/net/connection/xous/mod.rs | 2 +- tests/ui/inference/issue-72616.rs | 1 - tests/ui/inference/issue-72616.stderr | 19 +----- 11 files changed, 51 insertions(+), 212 deletions(-) diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index 41e623e79ce27..5b56dd3f74472 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -6,7 +6,6 @@ mod tests; pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use crate::sys::net::LookupHost; use crate::{io, iter, option, slice, vec}; /// A trait for objects which can be converted or resolved to one or more @@ -188,15 +187,9 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } -fn resolve_socket_addr(lh: LookupHost) -> io::Result> { - let p = lh.port(); - let v: Vec<_> = lh - .map(|mut a| { - a.set_port(p); - a - }) - .collect(); - Ok(v.into_iter()) +fn lookup_host(host: &str, port: u16) -> io::Result> { + let addrs = crate::sys::net::lookup_host(host, port)?; + Ok(Vec::from_iter(addrs).into_iter()) } #[stable(feature = "rust1", since = "1.0.0")] @@ -205,17 +198,14 @@ impl ToSocketAddrs for (&str, u16) { fn to_socket_addrs(&self) -> io::Result> { let (host, port) = *self; - // try to parse the host as a regular IP address first - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV4::new(addr, port); - return Ok(vec![SocketAddr::V4(addr)].into_iter()); - } - if let Ok(addr) = host.parse::() { - let addr = SocketAddrV6::new(addr, port, 0, 0); - return Ok(vec![SocketAddr::V6(addr)].into_iter()); + // Try to parse the host as a regular IP address first + if let Ok(addr) = host.parse::() { + let addr = SocketAddr::new(addr, port); + return Ok(vec![addr].into_iter()); } - resolve_socket_addr((host, port).try_into()?) + // Otherwise, make the system look it up. + lookup_host(host, port) } } @@ -232,12 +222,21 @@ impl ToSocketAddrs for (String, u16) { impl ToSocketAddrs for str { type Iter = vec::IntoIter; fn to_socket_addrs(&self) -> io::Result> { - // try to parse as a regular SocketAddr first + // Try to parse as a regular SocketAddr first if let Ok(addr) = self.parse() { return Ok(vec![addr].into_iter()); } - resolve_socket_addr(self.try_into()?) + // Otherwise, split the string by ':' and convert the second part to u16... + let Some((host, port_str)) = self.rsplit_once(':') else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid socket address")); + }; + let Ok(port) = port_str.parse::() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid port value")); + }; + + // ... and make the system look up the host. + lookup_host(host, port) } } diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 9b54571997d0b..8c9c17d3f1714 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -499,16 +499,6 @@ impl fmt::Display for NonIpSockAddr { pub struct LookupHost(!); -impl LookupHost { - fn new(host: String) -> io::Result { - Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host })) - } - - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -516,18 +506,9 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(v: &str) -> io::Result { - LookupHost::new(v.to_owned()) - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from((host, port): (&'a str, u16)) -> io::Result { - LookupHost::new(format!("{host}:{port}")) - } +pub fn lookup_host(host: &str, port: u16) -> io::Result { + Err(io::Error::new( + io::ErrorKind::Uncategorized, + NonIpSockAddr { host: format!("{host}:{port}") }, + )) } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 564f2e3a01f3b..1dd06e97bbabd 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -258,7 +258,7 @@ fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint { } //////////////////////////////////////////////////////////////////////////////// -// get_host_addresses +// lookup_host //////////////////////////////////////////////////////////////////////////////// pub struct LookupHost { @@ -267,12 +267,6 @@ pub struct LookupHost { port: u16, } -impl LookupHost { - pub fn port(&self) -> u16 { - self.port - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -281,7 +275,10 @@ impl Iterator for LookupHost { let cur = self.cur.as_ref()?; self.cur = cur.ai_next; match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) { - Ok(addr) => return Some(addr), + Ok(mut addr) => { + addr.set_port(self.port); + return Some(addr); + } Err(_) => continue, } } @@ -298,42 +295,17 @@ impl Drop for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(s: &str) -> io::Result { - macro_rules! try_opt { - ($e:expr, $msg:expr) => { - match $e { - Some(r) => r, - None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)), - } - }; +pub fn lookup_host(host: &str, port: u16) -> io::Result { + init(); + run_with_cstr(host.as_bytes(), &|c_host| { + let mut hints: c::addrinfo = unsafe { mem::zeroed() }; + hints.ai_socktype = c::SOCK_STREAM; + let mut res = ptr::null_mut(); + unsafe { + cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) + .map(|_| LookupHost { original: res, cur: res, port }) } - - // split the string by ':' and convert the second part to u16 - let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from((host, port): (&'a str, u16)) -> io::Result { - init(); - - run_with_cstr(host.as_bytes(), &|c_host| { - let mut hints: c::addrinfo = unsafe { mem::zeroed() }; - hints.ai_socktype = c::SOCK_STREAM; - let mut res = ptr::null_mut(); - unsafe { - cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) - .map(|_| LookupHost { original: res, cur: res, port }) - } - }) - } + }) } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/net/connection/socket/tests.rs b/library/std/src/sys/net/connection/socket/tests.rs index fc236b8027b67..049355afca7ac 100644 --- a/library/std/src/sys/net/connection/socket/tests.rs +++ b/library/std/src/sys/net/connection/socket/tests.rs @@ -4,7 +4,7 @@ use crate::collections::HashMap; #[test] fn no_lookup_host_duplicates() { let mut addrs = HashMap::new(); - let lh = match LookupHost::try_from(("localhost", 0)) { + let lh = match lookup_host("localhost", 0) { Ok(lh) => lh, Err(e) => panic!("couldn't resolve `localhost`: {e}"), }; diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 0036804287352..004f6d413a1f3 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -333,12 +333,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -346,18 +340,6 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result { + unsupported() } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index fbc86343272fc..fb18e8dec557c 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -304,12 +304,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -317,18 +311,6 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result { + unsupported() } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index cdfa25c8a4407..048dafdcd7f7c 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -477,12 +477,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -490,18 +484,6 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &'a str) -> io::Result { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result { + unsupported() } diff --git a/library/std/src/sys/net/connection/xous/dns.rs b/library/std/src/sys/net/connection/xous/dns.rs index bb29d211fad56..b139376f59768 100644 --- a/library/std/src/sys/net/connection/xous/dns.rs +++ b/library/std/src/sys/net/connection/xous/dns.rs @@ -1,15 +1,8 @@ -use core::convert::{TryFrom, TryInto}; - use crate::io; use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::os::xous::ffi::lend_mut; use crate::os::xous::services::{DnsLendMut, dns_server}; -pub struct DnsError { - #[allow(dead_code)] - pub code: u8, -} - #[repr(C, align(4096))] struct LookupHostQuery([u8; 4096]); @@ -20,12 +13,6 @@ pub struct LookupHost { count: usize, } -impl LookupHost { - pub fn port(&self) -> u16 { - self.port - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { @@ -72,7 +59,7 @@ impl Iterator for LookupHost { } } -pub fn lookup(query: &str, port: u16) -> Result { +pub fn lookup_host(query: &str, port: u16) -> io::Result { let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port }; // Copy the query into the message that gets sent to the DNS server @@ -89,7 +76,7 @@ pub fn lookup(query: &str, port: u16) -> Result { ) .unwrap(); if result.data.0[0] != 0 { - return Err(DnsError { code: result.data.0[1] }); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "DNS failure")); } assert_eq!(result.offset, 0); result.count = result.data.0[1] as usize; @@ -98,31 +85,3 @@ pub fn lookup(query: &str, port: u16) -> Result { result.offset = 2; Ok(result) } - -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(s: &str) -> io::Result { - macro_rules! try_opt { - ($e:expr, $msg:expr) => { - match $e { - Some(r) => r, - None => return Err(io::const_error!(io::ErrorKind::InvalidInput, &$msg)), - } - }; - } - - // split the string by ':' and convert the second part to u16 - let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() - } -} - -impl TryFrom<(&str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(v: (&str, u16)) -> io::Result { - lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, "DNS failure")) - } -} diff --git a/library/std/src/sys/net/connection/xous/mod.rs b/library/std/src/sys/net/connection/xous/mod.rs index e44a375b9e3c5..0f77be5c3fac8 100644 --- a/library/std/src/sys/net/connection/xous/mod.rs +++ b/library/std/src/sys/net/connection/xous/mod.rs @@ -45,4 +45,4 @@ pub struct GetAddress { raw: [u8; 4096], } -pub use dns::LookupHost; +pub use dns::lookup_host; diff --git a/tests/ui/inference/issue-72616.rs b/tests/ui/inference/issue-72616.rs index 71e095cc6fc02..ba18575a57156 100644 --- a/tests/ui/inference/issue-72616.rs +++ b/tests/ui/inference/issue-72616.rs @@ -21,7 +21,6 @@ pub fn main() { { if String::from("a") == "a".try_into().unwrap() {} //~^ ERROR type annotations needed - //~| ERROR type annotations needed } { let _: String = match "_".try_into() { diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr index a271639996fd2..6b47d56881134 100644 --- a/tests/ui/inference/issue-72616.stderr +++ b/tests/ui/inference/issue-72616.stderr @@ -16,23 +16,6 @@ LL - if String::from("a") == "a".try_into().unwrap() {} LL + if String::from("a") == <&str as TryInto>::try_into("a").unwrap() {} | -error[E0283]: type annotations needed - --> $DIR/issue-72616.rs:22:37 - | -LL | if String::from("a") == "a".try_into().unwrap() {} - | ^^^^^^^^ - | - = note: multiple `impl`s satisfying `_: TryFrom<&str>` found in the following crates: `core`, `std`: - - impl TryFrom<&str> for std::sys::net::connection::socket::LookupHost; - - impl TryFrom for T - where U: Into; - = note: required for `&str` to implement `TryInto<_>` -help: try using a fully qualified path to specify the expected types - | -LL - if String::from("a") == "a".try_into().unwrap() {} -LL + if String::from("a") == <&str as TryInto>::try_into("a").unwrap() {} - | - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0283`.

::Pointer) { ); } -// FIXME(next-solver): Was `&'a T` but now getting error lifetime. -// This might be fixed once we migrate into next-solver fully without chalk-ir in lowering. #[test] fn gats_with_impl_trait() { // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot @@ -4215,21 +4213,21 @@ fn f(v: impl Trait) { } fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); - //^ &'? T + //^ &'a T let a = v.get::<()>(); //^ = &'a T> as Trait>::Assoc<()> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); - //^ &'? i32 + //^ &'a i32 let a = v.get::(); - //^ &'? i64 + //^ &'a i64 } fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { let a = v.get::(); - //^ &'? i32 + //^ &'a i32 let a = v.get::(); - //^ &'? i64 + //^ &'a i64 } "#, ); @@ -4259,8 +4257,8 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { 127..128 'v': &'? (dyn Trait = &'a i32> + '?) 164..195 '{ ...f(); }': () 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': = &'a i32> + '? as Trait>::Assoc - 170..192 'v.get:...eref()': {unknown} + 170..184 'v.get::()': {unknown} + 170..192 'v.get:...eref()': &'? {unknown} "#]], ); } @@ -4953,7 +4951,7 @@ where "#, expect![[r#" 84..86 'de': D - 135..138 '{ }': >::Error + 135..138 '{ }': >::Error "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 52ab808d22841..888392b0ff207 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -76,7 +76,7 @@ use hir_expand::{ }; use hir_ty::{ AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, - GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, + GenericArgData, Interner, ParamKind, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic, ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules, consteval::{ConstExt, try_const_usize, unknown_const_as_generic}, @@ -4973,6 +4973,7 @@ impl<'db> Type<'db> { | TyKind::Tuple(_, substitution) | TyKind::OpaqueType(_, substitution) | TyKind::AssociatedType(_, substitution) + | TyKind::Alias(AliasTy::Projection(ProjectionTy { substitution, .. })) | TyKind::FnDef(_, substitution) => { substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty)) } @@ -5819,7 +5820,11 @@ impl<'db> Type<'db> { cb(type_.derived(ty.clone())); walk_substs(db, type_, substs, cb); } - TyKind::AssociatedType(_, substs) => { + TyKind::AssociatedType(_, substs) + | TyKind::Alias(AliasTy::Projection(hir_ty::ProjectionTy { + substitution: substs, + .. + })) => { if ty.associated_type_parent_trait(db).is_some() { cb(type_.derived(ty.clone())); } From b2b33f9faab81507abda08d025c0680eb8d4995d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 10 Sep 2025 04:51:33 +0300 Subject: [PATCH 182/251] Always coerce in a cast, even when there are unknown types This cause the relationships between inference vars to get recorded. --- .../crates/hir-ty/src/infer/cast.rs | 13 +++++++------ .../hir-ty/src/tests/regression/new_solver.rs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 43364963eb054..bc3ee3c4c54d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -106,6 +106,13 @@ impl CastCheck { self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone()); self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone()); + // This should always come first so that we apply the coercion, which impacts infer vars. + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty, CoerceNever::Yes) { + apply_adjustments(self.source_expr, adj); + set_coercion_cast(self.source_expr); + return Ok(()); + } + if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() { return Ok(()); } @@ -126,12 +133,6 @@ impl CastCheck { return Ok(()); } - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty, CoerceNever::Yes) { - apply_adjustments(self.source_expr, adj); - set_coercion_cast(self.source_expr); - return Ok(()); - } - self.do_check(table, apply_adjustments) .map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone())) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 6d6c56696a30d..4df788638a315 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -98,3 +98,21 @@ fn main() { "#, ); } + +#[test] +fn cast_error_type() { + check_infer( + r#" +fn main() { + let foo: [_; _] = [false] as _; +} + "#, + expect![[r#" + 10..47 '{ le...s _; }': () + 18..21 'foo': [bool; 1] + 32..39 '[false]': [bool; 1] + 32..44 '[false] as _': [bool; 1] + 33..38 'false': bool + "#]], + ); +} From edbc0a08fb8bafbb80b4522ae0050244bb21e4f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 16:09:28 +0200 Subject: [PATCH 183/251] weak memory tests: add more info on where they come from --- .../tests/pass/0weak_memory_consistency.rs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index e4ed9675de822..16969d9649c94 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -14,13 +14,6 @@ // To mitigate this, each test is ran enough times such that the chance // of spurious success is very low. These tests never spuriously fail. -// Test cases and their consistent outcomes are from -// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ -// Based on -// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, -// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. -// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. - use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicBool, AtomicI32, Ordering, fence}; use std::thread::spawn; @@ -56,6 +49,7 @@ fn spin_until_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { val } +/// Test matching https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf, Figure 7 fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -75,19 +69,25 @@ fn test_corr() { let j3 = spawn(move || { // | | spin_until_i32(&y, Acquire, 1); // <---------+ | x.load(Relaxed) // <----------------------------------------------+ - // The two reads on x are ordered by hb, so they cannot observe values - // differently from the modification order. If the first read observed - // 2, then the second read must observe 2 as well. }); j1.join().unwrap(); let r2 = j2.join().unwrap(); let r3 = j3.join().unwrap(); + // The two reads on x are ordered by hb, so they cannot observe values + // differently from the modification order. If the first read observed + // 2, then the second read must observe 2 as well. if r2 == 2 { assert_eq!(r3, 2); } } +/// This test case is from: +/// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/, "WRC" +/// Based on +/// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, +/// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. +/// Available: https://www.cl.cam.ac.uk/~pes20/cpp/popl085ap-sewell.pdf. fn test_wrc() { let x = static_atomic(0); let y = static_atomic(0); @@ -114,6 +114,8 @@ fn test_wrc() { assert_eq!(r3, 1); } +/// Another test from http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/: +/// MP (na_rel+acq_na) fn test_message_passing() { let mut var = 0u32; let ptr = &mut var as *mut u32; @@ -139,7 +141,8 @@ fn test_message_passing() { assert_eq!(r2, 1); } -// LB+acq_rel+acq_rel +/// Another test from http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/: +/// LB+acq_rel+acq_rel fn test_load_buffering_acq_rel() { let x = static_atomic(0); let y = static_atomic(0); From 0e0b254df9b6f7abe4aa0efa8617ac97baa2bea7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 16:16:49 +0200 Subject: [PATCH 184/251] ensure we do not see the inconsistent execution from Figure 8 --- src/tools/miri/tests/pass/0weak_memory_consistency.rs | 3 ++- src/tools/miri/tests/pass/weak_memory/weak.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index 16969d9649c94..142080c1372d7 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -49,7 +49,8 @@ fn spin_until_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { val } -/// Test matching https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf, Figure 7 +/// Test matching https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf, Figure 7. +/// (The Figure 8 test is in `weak_memory/weak.rs`.) fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 199f83f052860..6794b43bfb37b 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -69,6 +69,9 @@ fn seq_cst() -> bool { j2.join().unwrap(); let r3 = j3.join().unwrap(); + // Even though we force t3 to run last, it can still see the value 1. + // And it can *never* see the value 2! + assert!(r3 == 1 || r3 == 3); r3 == 1 } @@ -148,4 +151,9 @@ pub fn main() { assert_once(|| initialization_write(false)); assert_once(|| initialization_write(true)); assert_once(faa_replaced_by_load); + + // Run seq_cst a few more times since it has an assertion we want to ensure holds always. + for _ in 0..50 { + seq_cst(); + } } From 21e3111ef90f670b85eebf4a1ed9cc8be2f21061 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 16:31:29 +0200 Subject: [PATCH 185/251] refactor weak-mem test to list all expected executions --- .../tests/pass/0weak_memory_consistency.rs | 3 +- .../tests/pass/0weak_memory_consistency_sc.rs | 3 +- src/tools/miri/tests/pass/weak_memory/weak.rs | 211 +++++++++--------- 3 files changed, 114 insertions(+), 103 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index 142080c1372d7..f1d5a56c2b02c 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -1,6 +1,7 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -Zmiri-provenance-gc=10000 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we // override it internally back to the default frequency. +//@compile-flags: -Zmiri-provenance-gc=10000 // The following tests check whether our weak memory emulation produces // any inconsistent execution outcomes diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs index 937c2a8cf282c..43675a8b5e165 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs @@ -1,6 +1,7 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -Zmiri-provenance-gc=10000 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we // override it internally back to the default frequency. +//@compile-flags: -Zmiri-provenance-gc=10000 // The following tests check whether our weak memory emulation produces // any inconsistent execution outcomes diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 6794b43bfb37b..f39ef0ed98da9 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -1,9 +1,11 @@ //@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule +// This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we +// override it internally back to the default frequency. +//@compile-flags: -Zmiri-provenance-gc=10000 + +// Tests showing weak memory behaviours are exhibited, even with a fixed scheule. +// We run all tests a number of times and then check that we see the desired list of outcomes. -// Tests showing weak memory behaviours are exhibited. All tests -// return true when the desired behaviour is seen. -// This is scheduler and pseudo-RNG dependent, so each test is -// run multiple times until one try returns true. // Spurious failure is possible, if you are really unlucky with // the RNG and always read the latest value from the store buffer. @@ -31,129 +33,136 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize { val } -fn relaxed(initial_read: bool) -> bool { - let x = static_atomic(0); - let j1 = spawn(move || { - x.store(1, Relaxed); - // Preemption is disabled, so the store above will never be the - // latest store visible to another thread. - x.store(2, Relaxed); - }); +/// Check that the function produces the intended set of outcomes. +#[track_caller] +fn check_all_outcomes( + expected: impl IntoIterator, + generate: impl Fn() -> T, +) { + use std::collections::HashSet; + + let expected: HashSet = HashSet::from_iter(expected); + let mut seen = HashSet::new(); + // Let's give it N times as many tries as we are expecting values. + let tries = expected.len() * 8; + for _ in 0..tries { + let val = generate(); + assert!(expected.contains(&val), "got an unexpected value: {val}"); + seen.insert(val); + } + // Let's see if we saw them all. + for val in expected { + if !seen.contains(&val) { + panic!("did not get value that should be possible: {val}"); + } + } +} - let j2 = spawn(move || x.load(Relaxed)); +fn relaxed() { + check_all_outcomes([0, 1, 2], || { + let x = static_atomic(0); + let j1 = spawn(move || { + x.store(1, Relaxed); + // Preemption is disabled, so the store above will never be the + // latest store visible to another thread. + x.store(2, Relaxed); + }); - j1.join().unwrap(); - let r2 = j2.join().unwrap(); + let j2 = spawn(move || x.load(Relaxed)); - // There are three possible values here: 0 (from the initial read), 1 (from the first relaxed - // read), and 2 (the last read). The last case is boring and we cover the other two. - r2 == if initial_read { 0 } else { 1 } + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + // There are three possible values here: 0 (from the initial read), 1 (from the first relaxed + // read), and 2 (the last read). + r2 + }); } // https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf Figure 8 -fn seq_cst() -> bool { - let x = static_atomic(0); +fn seq_cst() { + check_all_outcomes([1, 3], || { + let x = static_atomic(0); - let j1 = spawn(move || { - x.store(1, Relaxed); - }); + let j1 = spawn(move || { + x.store(1, Relaxed); + }); - let j2 = spawn(move || { - x.store(2, SeqCst); - x.store(3, SeqCst); - }); + let j2 = spawn(move || { + x.store(2, SeqCst); + x.store(3, SeqCst); + }); - let j3 = spawn(move || x.load(SeqCst)); + let j3 = spawn(move || x.load(SeqCst)); - j1.join().unwrap(); - j2.join().unwrap(); - let r3 = j3.join().unwrap(); + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); - // Even though we force t3 to run last, it can still see the value 1. - // And it can *never* see the value 2! - assert!(r3 == 1 || r3 == 3); - r3 == 1 + // Even though we force t3 to run last, it can still see the value 1. + // And it can *never* see the value 2! + r3 + }); } -fn initialization_write(add_fence: bool) -> bool { - let x = static_atomic(11); +fn initialization_write(add_fence: bool) { + check_all_outcomes([11, 22], || { + let x = static_atomic(11); - let wait = static_atomic(0); + let wait = static_atomic(0); - let j1 = spawn(move || { - x.store(22, Relaxed); - // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write - // after a relaxed write - wait.store(1, Relaxed); - }); + let j1 = spawn(move || { + x.store(22, Relaxed); + // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write + // after a relaxed write + wait.store(1, Relaxed); + }); - let j2 = spawn(move || { - spin_until(wait, 1); - if add_fence { - fence(AcqRel); - } - x.load(Relaxed) - }); + let j2 = spawn(move || { + spin_until(wait, 1); + if add_fence { + fence(AcqRel); + } + x.load(Relaxed) + }); - j1.join().unwrap(); - let r2 = j2.join().unwrap(); + j1.join().unwrap(); + let r2 = j2.join().unwrap(); - r2 == 11 + r2 + }); } -fn faa_replaced_by_load() -> bool { - // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 - #[no_mangle] - pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize { - storing.store(1, Relaxed); - fence(Release); - // sync.fetch_add(0, Relaxed); - sync.load(Relaxed); - fence(Acquire); - loading.load(Relaxed) - } +fn faa_replaced_by_load() { + check_all_outcomes([true, false], || { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize { + storing.store(1, Relaxed); + fence(Release); + // sync.fetch_add(0, Relaxed); + sync.load(Relaxed); + fence(Acquire); + loading.load(Relaxed) + } - let x = static_atomic(0); - let y = static_atomic(0); - let z = static_atomic(0); + let x = static_atomic(0); + let y = static_atomic(0); + let z = static_atomic(0); - // Since each thread is so short, we need to make sure that they truely run at the same time - // Otherwise t1 will finish before t2 even starts - let go = static_atomic(0); + let t1 = spawn(move || rdmw(y, x, z)); - let t1 = spawn(move || { - spin_until(go, 1); - rdmw(y, x, z) - }); + let t2 = spawn(move || rdmw(z, x, y)); - let t2 = spawn(move || { - spin_until(go, 1); - rdmw(z, x, y) + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + (a, b) == (0, 0) }); - - go.store(1, Relaxed); - - let a = t1.join().unwrap(); - let b = t2.join().unwrap(); - (a, b) == (0, 0) -} - -/// Asserts that the function returns true at least once in 100 runs -#[track_caller] -fn assert_once(f: fn() -> bool) { - assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); } pub fn main() { - assert_once(|| relaxed(false)); - assert_once(|| relaxed(true)); - assert_once(seq_cst); - assert_once(|| initialization_write(false)); - assert_once(|| initialization_write(true)); - assert_once(faa_replaced_by_load); - - // Run seq_cst a few more times since it has an assertion we want to ensure holds always. - for _ in 0..50 { - seq_cst(); - } + relaxed(); + seq_cst(); + initialization_write(false); + initialization_write(true); + faa_replaced_by_load(); } From 614dab3ed2e61acd32a572c37e5480538b547da8 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 10 Sep 2025 23:02:49 +0800 Subject: [PATCH 186/251] loongarch: Align intrinsic signatures with LLVM --- .../crates/core_arch/src/loongarch32/mod.rs | 7 ++++--- .../crates/core_arch/src/loongarch64/mod.rs | 17 ++++++++++------- .../core_arch/src/loongarch_shared/mod.rs | 12 ++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/loongarch32/mod.rs b/library/stdarch/crates/core_arch/src/loongarch32/mod.rs index fb05450373c28..4e3f3d27182e4 100644 --- a/library/stdarch/crates/core_arch/src/loongarch32/mod.rs +++ b/library/stdarch/crates/core_arch/src/loongarch32/mod.rs @@ -17,9 +17,10 @@ unsafe extern "unadjusted" { /// Generates the cache operation instruction #[inline] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn cacop(a: i32, b: i32) { - static_assert_simm_bits!(IMM12, 12); - __cacop(a, b, IMM12); +pub unsafe fn cacop(b: i32) { + static_assert_uimm_bits!(IMM5, 5); + static_assert_simm_bits!(IMM_S12, 12); + __cacop(IMM5, b, IMM_S12); } /// Reads the CSR diff --git a/library/stdarch/crates/core_arch/src/loongarch64/mod.rs b/library/stdarch/crates/core_arch/src/loongarch64/mod.rs index e8249805eae26..ab968aff20bbe 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/mod.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/mod.rs @@ -64,9 +64,10 @@ pub fn crcc_w_d_w(a: i64, b: i32) -> i32 { /// Generates the cache operation instruction #[inline] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn cacop(a: i64, b: i64) { - static_assert_simm_bits!(IMM12, 12); - __cacop(a, b, IMM12); +pub unsafe fn cacop(b: i64) { + static_assert_uimm_bits!(IMM5, 5); + static_assert_simm_bits!(IMM_S12, 12); + __cacop(IMM5, b, IMM_S12); } /// Reads the CSR @@ -125,14 +126,16 @@ pub unsafe fn asrtgt(a: i64, b: i64) { #[inline] #[rustc_legacy_const_generics(1)] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lddir(a: i64) -> i64 { - __lddir(a, B) +pub unsafe fn lddir(a: i64) -> i64 { + static_assert_uimm_bits!(IMM8, 8); + __lddir(a, IMM8) } /// Loads the page table entry #[inline] #[rustc_legacy_const_generics(1)] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn ldpte(a: i64) { - __ldpte(a, B) +pub unsafe fn ldpte(a: i64) { + static_assert_uimm_bits!(IMM8, 8); + __ldpte(a, IMM8) } diff --git a/library/stdarch/crates/core_arch/src/loongarch_shared/mod.rs b/library/stdarch/crates/core_arch/src/loongarch_shared/mod.rs index 710b926f8df4f..8991fe857682b 100644 --- a/library/stdarch/crates/core_arch/src/loongarch_shared/mod.rs +++ b/library/stdarch/crates/core_arch/src/loongarch_shared/mod.rs @@ -131,17 +131,17 @@ pub fn ibar() { /// Moves data from a GPR to the FCSR #[inline] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn movgr2fcsr(a: i32) { - static_assert_uimm_bits!(IMM5, 5); - __movgr2fcsr(IMM5, a); +pub unsafe fn movgr2fcsr(a: i32) { + static_assert_uimm_bits!(IMM2, 2); + __movgr2fcsr(IMM2, a); } /// Moves data from a FCSR to the GPR #[inline] #[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn movfcsr2gr() -> i32 { - static_assert_uimm_bits!(IMM5, 5); - unsafe { __movfcsr2gr(IMM5) } +pub fn movfcsr2gr() -> i32 { + static_assert_uimm_bits!(IMM2, 2); + unsafe { __movfcsr2gr(IMM2) } } /// Reads the 8-bit IO-CSR From 655b8474348a087acbcec498d48fd705160ee080 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 16:35:07 +0200 Subject: [PATCH 187/251] also use nicer check_all_outcomes in float_nan --- src/tools/miri/tests/pass/float_nan.rs | 319 +++++++++++-------------- 1 file changed, 142 insertions(+), 177 deletions(-) diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 3ffdb6868ac0a..f0a2b8e9ee060 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -1,7 +1,8 @@ +// This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we +// override it internally back to the default frequency. +//@compile-flags: -Zmiri-provenance-gc=10000 #![feature(float_gamma, portable_simd, core_intrinsics)] -use std::collections::HashSet; use std::fmt; -use std::hash::Hash; use std::hint::black_box; fn ldexp(a: f64, b: i32) -> f64 { @@ -25,11 +26,18 @@ enum NaNKind { } use NaNKind::*; +/// Check that the function produces the intended set of outcomes. #[track_caller] -fn check_all_outcomes(expected: HashSet, generate: impl Fn() -> T) { +fn check_all_outcomes( + expected: impl IntoIterator, + generate: impl Fn() -> T, +) { + use std::collections::HashSet; + + let expected: HashSet = HashSet::from_iter(expected); let mut seen = HashSet::new(); - // Let's give it sixteen times as many tries as we are expecting values. - let tries = expected.len() * 16; + // Let's give it N times as many tries as we are expecting values. + let tries = expected.len() * 12; for _ in 0..tries { let val = generate(); assert!(expected.contains(&val), "got an unexpected value: {val}"); @@ -193,51 +201,50 @@ impl F64 { fn test_f32() { // Freshly generated NaNs can have either sign. - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(0.0 / black_box(0.0)), - ); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(0.0 / black_box(0.0)) + }); // When there are NaN inputs, their payload can be propagated, with any sign. let all1_payload = u32_ones(22); let all1 = F32::nan(Pos, Quiet, all1_payload).as_f32(); check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, all1_payload), F32::nan(Neg, Quiet, all1_payload), - ]), + ], || F32::from(0.0 + all1), ); // When there are two NaN inputs, the output can be either one, or the preferred NaN. let just1 = F32::nan(Neg, Quiet, 1).as_f32(); check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, 1), F32::nan(Neg, Quiet, 1), F32::nan(Pos, Quiet, all1_payload), F32::nan(Neg, Quiet, all1_payload), - ]), + ], || F32::from(just1 - all1), ); // When there are *signaling* NaN inputs, they might be quieted or not. let all1_snan = F32::nan(Pos, Signaling, all1_payload).as_f32(); check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, all1_payload), F32::nan(Neg, Quiet, all1_payload), F32::nan(Pos, Signaling, all1_payload), F32::nan(Neg, Signaling, all1_payload), - ]), + ], || F32::from(0.0 * all1_snan), ); // Mix signaling and non-signaling NaN. check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, 1), @@ -246,35 +253,26 @@ fn test_f32() { F32::nan(Neg, Quiet, all1_payload), F32::nan(Pos, Signaling, all1_payload), F32::nan(Neg, Signaling, all1_payload), - ]), + ], || F32::from(just1 % all1_snan), ); // Unary `-` must preserve payloads exactly. - check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Quiet, all1_payload)]), || { - F32::from(-all1) - }); - check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Signaling, all1_payload)]), || { - F32::from(-all1_snan) - }); + check_all_outcomes([F32::nan(Neg, Quiet, all1_payload)], || F32::from(-all1)); + check_all_outcomes([F32::nan(Neg, Signaling, all1_payload)], || F32::from(-all1_snan)); // Intrinsics let nan = F32::nan(Neg, Quiet, 0).as_f32(); let snan = F32::nan(Neg, Signaling, 1).as_f32(); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(f32::min(nan, nan)) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.floor()) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || F32::from(nan.sin())); check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(f32::min(nan, nan)), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.floor()), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.sin()), - ); - check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, 1), @@ -285,37 +283,32 @@ fn test_f32() { F32::nan(Neg, Quiet, all1_payload), F32::nan(Pos, Signaling, all1_payload), F32::nan(Neg, Signaling, all1_payload), - ]), + ], || F32::from(just1.mul_add(F32::nan(Neg, Quiet, 2).as_f32(), all1_snan)), ); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.powf(nan)) + }); check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.powf(nan)), - ); - check_all_outcomes( - HashSet::from_iter([1.0f32.into()]), + [1.0f32.into()], || F32::from(1.0f32.powf(nan)), // special `pow` rule ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.powi(1)), - ); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.powi(1)) + }); // libm functions + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.sinh()) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.atan2(nan)) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(nan.ln_gamma().0) + }); check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.sinh()), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.atan2(nan)), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(nan.ln_gamma().0), - ); - check_all_outcomes( - HashSet::from_iter([ + [ F32::from(1.0), F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), @@ -323,58 +316,57 @@ fn test_f32() { F32::nan(Neg, Quiet, 1), F32::nan(Pos, Signaling, 1), F32::nan(Neg, Signaling, 1), - ]), + ], || F32::from(snan.powf(0.0)), ); } fn test_f64() { // Freshly generated NaNs can have either sign. - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(0.0 / black_box(0.0)), - ); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(0.0 / black_box(0.0)) + }); // When there are NaN inputs, their payload can be propagated, with any sign. let all1_payload = u64_ones(51); let all1 = F64::nan(Pos, Quiet, all1_payload).as_f64(); check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, all1_payload), F64::nan(Neg, Quiet, all1_payload), - ]), + ], || F64::from(0.0 + all1), ); // When there are two NaN inputs, the output can be either one, or the preferred NaN. let just1 = F64::nan(Neg, Quiet, 1).as_f64(); check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, 1), F64::nan(Neg, Quiet, 1), F64::nan(Pos, Quiet, all1_payload), F64::nan(Neg, Quiet, all1_payload), - ]), + ], || F64::from(just1 - all1), ); // When there are *signaling* NaN inputs, they might be quieted or not. let all1_snan = F64::nan(Pos, Signaling, all1_payload).as_f64(); check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, all1_payload), F64::nan(Neg, Quiet, all1_payload), F64::nan(Pos, Signaling, all1_payload), F64::nan(Neg, Signaling, all1_payload), - ]), + ], || F64::from(0.0 * all1_snan), ); // Mix signaling and non-signaling NaN. check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, 1), @@ -383,27 +375,22 @@ fn test_f64() { F64::nan(Neg, Quiet, all1_payload), F64::nan(Pos, Signaling, all1_payload), F64::nan(Neg, Signaling, all1_payload), - ]), + ], || F64::from(just1 % all1_snan), ); // Intrinsics let nan = F64::nan(Neg, Quiet, 0).as_f64(); let snan = F64::nan(Neg, Signaling, 1).as_f64(); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(f64::min(nan, nan)) + }); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.floor()) + }); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || F64::from(nan.sin())); check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(f64::min(nan, nan)), - ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.floor()), - ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.sin()), - ); - check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, 1), @@ -414,41 +401,35 @@ fn test_f64() { F64::nan(Neg, Quiet, all1_payload), F64::nan(Pos, Signaling, all1_payload), F64::nan(Neg, Signaling, all1_payload), - ]), + ], || F64::from(just1.mul_add(F64::nan(Neg, Quiet, 2).as_f64(), all1_snan)), ); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.powf(nan)) + }); check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.powf(nan)), - ); - check_all_outcomes( - HashSet::from_iter([1.0f64.into()]), + [1.0f64.into()], || F64::from(1.0f64.powf(nan)), // special `pow` rule ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.powi(1)), - ); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.powi(1)) + }); // libm functions + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.sinh()) + }); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.atan2(nan)) + }); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(ldexp(nan, 1)) + }); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(nan.ln_gamma().0) + }); check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.sinh()), - ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.atan2(nan)), - ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(ldexp(nan, 1)), - ); - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(nan.ln_gamma().0), - ); - check_all_outcomes( - HashSet::from_iter([ + [ F64::from(1.0), F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), @@ -456,7 +437,7 @@ fn test_f64() { F64::nan(Neg, Quiet, 1), F64::nan(Pos, Signaling, 1), F64::nan(Neg, Signaling, 1), - ]), + ], || F64::from(snan.powf(0.0)), ); } @@ -467,82 +448,79 @@ fn test_casts() { let left1_payload_64 = (all1_payload_32 as u64) << (51 - 22); // 64-to-32 - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(F64::nan(Pos, Quiet, 0).as_f64() as f32), - ); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(F64::nan(Pos, Quiet, 0).as_f64() as f32) + }); // The preferred payload is always a possibility. check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, all1_payload_32), F32::nan(Neg, Quiet, all1_payload_32), - ]), + ], || F32::from(F64::nan(Pos, Quiet, all1_payload_64).as_f64() as f32), ); // If the input is signaling, then the output *may* also be signaling. check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, all1_payload_32), F32::nan(Neg, Quiet, all1_payload_32), F32::nan(Pos, Signaling, all1_payload_32), F32::nan(Neg, Signaling, all1_payload_32), - ]), + ], || F32::from(F64::nan(Pos, Signaling, all1_payload_64).as_f64() as f32), ); // Check that the low bits are gone (not the high bits). + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(F64::nan(Pos, Quiet, 1).as_f64() as f32) + }); check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(F64::nan(Pos, Quiet, 1).as_f64() as f32), - ); - check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), F32::nan(Pos, Quiet, 1), F32::nan(Neg, Quiet, 1), - ]), + ], || F32::from(F64::nan(Pos, Quiet, 1 << (51 - 22)).as_f64() as f32), ); check_all_outcomes( - HashSet::from_iter([ + [ F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0), // The `1` payload becomes `0`, and the `0` payload cannot be signaling, // so these are the only options. - ]), + ], || F32::from(F64::nan(Pos, Signaling, 1).as_f64() as f32), ); // 32-to-64 - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(F32::nan(Pos, Quiet, 0).as_f32() as f64), - ); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(F32::nan(Pos, Quiet, 0).as_f32() as f64) + }); // The preferred payload is always a possibility. // Also checks that 0s are added on the right. check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, left1_payload_64), F64::nan(Neg, Quiet, left1_payload_64), - ]), + ], || F64::from(F32::nan(Pos, Quiet, all1_payload_32).as_f32() as f64), ); // If the input is signaling, then the output *may* also be signaling. check_all_outcomes( - HashSet::from_iter([ + [ F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0), F64::nan(Pos, Quiet, left1_payload_64), F64::nan(Neg, Quiet, left1_payload_64), F64::nan(Pos, Signaling, left1_payload_64), F64::nan(Neg, Signaling, left1_payload_64), - ]), + ], || F64::from(F32::nan(Pos, Signaling, all1_payload_32).as_f32() as f64), ); } @@ -552,48 +530,35 @@ fn test_simd() { use std::simd::*; let nan = F32::nan(Neg, Quiet, 0).as_f32(); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_div(f32x4::splat(0.0), f32x4::splat(0.0)) }[0]), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_fmin(f32x4::splat(nan), f32x4::splat(nan)) }[0]), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_fmax(f32x4::splat(nan), f32x4::splat(nan)) }[0]), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || { - F32::from( - unsafe { simd_fma(f32x4::splat(nan), f32x4::splat(nan), f32x4::splat(nan)) }[0], - ) - }, - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_reduce_add_ordered::<_, f32>(f32x4::splat(nan), nan) }), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_reduce_max::<_, f32>(f32x4::splat(nan)) }), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_fsqrt(f32x4::splat(nan)) }[0]), - ); - check_all_outcomes( - HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), - || F32::from(unsafe { simd_ceil(f32x4::splat(nan)) }[0]), - ); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_div(f32x4::splat(0.0), f32x4::splat(0.0)) }[0]) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_fmin(f32x4::splat(nan), f32x4::splat(nan)) }[0]) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_fmax(f32x4::splat(nan), f32x4::splat(nan)) }[0]) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_fma(f32x4::splat(nan), f32x4::splat(nan), f32x4::splat(nan)) }[0]) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_reduce_add_ordered::<_, f32>(f32x4::splat(nan), nan) }) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_reduce_max::<_, f32>(f32x4::splat(nan)) }) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_fsqrt(f32x4::splat(nan)) }[0]) + }); + check_all_outcomes([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)], || { + F32::from(unsafe { simd_ceil(f32x4::splat(nan)) }[0]) + }); // Casts - check_all_outcomes( - HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), - || F64::from(unsafe { simd_cast::(f32x4::splat(nan)) }[0]), - ); + check_all_outcomes([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)], || { + F64::from(unsafe { simd_cast::(f32x4::splat(nan)) }[0]) + }); } fn main() { From 827a6541e6a9e02fee35f1cc94f61e3ded4c258f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 16:40:48 +0200 Subject: [PATCH 188/251] move all weak memory tests into their folder --- .../consistency.rs} | 2 +- .../consistency_sc.rs} | 2 +- .../miri/tests/pass/{weak_memory => 0weak_memory}/extra_cpp.rs | 0 src/tools/miri/tests/pass/{weak_memory => 0weak_memory}/weak.rs | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename src/tools/miri/tests/pass/{0weak_memory_consistency.rs => 0weak_memory/consistency.rs} (99%) rename src/tools/miri/tests/pass/{0weak_memory_consistency_sc.rs => 0weak_memory/consistency_sc.rs} (99%) rename src/tools/miri/tests/pass/{weak_memory => 0weak_memory}/extra_cpp.rs (100%) rename src/tools/miri/tests/pass/{weak_memory => 0weak_memory}/weak.rs (100%) diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory/consistency.rs similarity index 99% rename from src/tools/miri/tests/pass/0weak_memory_consistency.rs rename to src/tools/miri/tests/pass/0weak_memory/consistency.rs index f1d5a56c2b02c..16a38ebd9d4da 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory/consistency.rs @@ -51,7 +51,7 @@ fn spin_until_bool(loc: &AtomicBool, ord: Ordering, val: bool) -> bool { } /// Test matching https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf, Figure 7. -/// (The Figure 8 test is in `weak_memory/weak.rs`.) +/// (The Figure 8 test is in `weak.rs`.) fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs b/src/tools/miri/tests/pass/0weak_memory/consistency_sc.rs similarity index 99% rename from src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs rename to src/tools/miri/tests/pass/0weak_memory/consistency_sc.rs index 43675a8b5e165..cb8535b8ad74b 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency_sc.rs +++ b/src/tools/miri/tests/pass/0weak_memory/consistency_sc.rs @@ -349,7 +349,7 @@ fn test_sc_relaxed() { } pub fn main() { - for _ in 0..50 { + for _ in 0..32 { test_sc_store_buffering(); test_iriw_sc_rlx(); test_cpp20_sc_fence_fix(); diff --git a/src/tools/miri/tests/pass/weak_memory/extra_cpp.rs b/src/tools/miri/tests/pass/0weak_memory/extra_cpp.rs similarity index 100% rename from src/tools/miri/tests/pass/weak_memory/extra_cpp.rs rename to src/tools/miri/tests/pass/0weak_memory/extra_cpp.rs diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs similarity index 100% rename from src/tools/miri/tests/pass/weak_memory/weak.rs rename to src/tools/miri/tests/pass/0weak_memory/weak.rs From 7d5413bd17ede225bc3c2ac9a7f640885628edc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 17:55:44 +0200 Subject: [PATCH 189/251] this apparently needs more test rounds --- src/tools/miri/tests/pass/0weak_memory/weak.rs | 8 ++++++-- src/tools/miri/tests/pass/float_nan.rs | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index f39ef0ed98da9..0dd661d3e9b4b 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -44,11 +44,15 @@ fn check_all_outcomes( let expected: HashSet = HashSet::from_iter(expected); let mut seen = HashSet::new(); // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 8; - for _ in 0..tries { + let tries = expected.len() * 12; + for i in 0..tries { let val = generate(); assert!(expected.contains(&val), "got an unexpected value: {val}"); seen.insert(val); + if i > tries / 2 && expected.len() == seen.len() { + // We saw everything and we did quite a few tries, let's avoid wasting time. + return; + } } // Let's see if we saw them all. for val in expected { diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index f0a2b8e9ee060..902816307403a 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -38,10 +38,14 @@ fn check_all_outcomes( let mut seen = HashSet::new(); // Let's give it N times as many tries as we are expecting values. let tries = expected.len() * 12; - for _ in 0..tries { + for i in 0..tries { let val = generate(); assert!(expected.contains(&val), "got an unexpected value: {val}"); seen.insert(val); + if i > tries / 2 && expected.len() == seen.len() { + // We saw everything and we did quite a few tries, let's avoid wasting time. + return; + } } // Let's see if we saw them all. for val in expected { From f8302a7c15d69b91ff20080ddcf8c44c81ec32ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Sep 2025 23:01:15 +0200 Subject: [PATCH 190/251] add release sequence test --- .../miri/tests/pass/0weak_memory/weak.rs | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index 0dd661d3e9b4b..75c6e8f1a8793 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -35,7 +35,7 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize { /// Check that the function produces the intended set of outcomes. #[track_caller] -fn check_all_outcomes( +fn check_all_outcomes( expected: impl IntoIterator, generate: impl Fn() -> T, ) { @@ -47,7 +47,7 @@ fn check_all_outcomes( let tries = expected.len() * 12; for i in 0..tries { let val = generate(); - assert!(expected.contains(&val), "got an unexpected value: {val}"); + assert!(expected.contains(&val), "got an unexpected value: {val:?}"); seen.insert(val); if i > tries / 2 && expected.len() == seen.len() { // We saw everything and we did quite a few tries, let's avoid wasting time. @@ -57,7 +57,7 @@ fn check_all_outcomes( // Let's see if we saw them all. for val in expected { if !seen.contains(&val) { - panic!("did not get value that should be possible: {val}"); + panic!("did not get value that should be possible: {val:?}"); } } } @@ -163,10 +163,46 @@ fn faa_replaced_by_load() { }); } +/// Checking that the weaker release sequence example from +/// can actually produce the +/// new behavior (`Some(0)` in our version). +fn weaker_release_sequences() { + check_all_outcomes([None, Some(0), Some(1)], || { + let x = static_atomic(0); + let y = static_atomic(0); + + let t1 = spawn(move || { + x.store(2, Relaxed); + }); + let t2 = spawn(move || { + y.store(1, Relaxed); + x.store(1, Release); + x.store(3, Relaxed); + }); + let t3 = spawn(move || { + if x.load(Acquire) == 3 { + // In C++11, if we read the 3 here, and if the store of 1 was just before the store + // of 3 in mo order (which it is because we fix the schedule), this forms a release + // sequence, meaning we acquire the release store of 1, and we can thus never see + // the value 0. + // In C++20, this is no longer a release sequence, so 0 can now be observed. + Some(y.load(Relaxed)) + } else { + None + } + }); + + t1.join().unwrap(); + t2.join().unwrap(); + t3.join().unwrap() + }); +} + pub fn main() { relaxed(); seq_cst(); initialization_write(false); initialization_write(true); faa_replaced_by_load(); + weaker_release_sequences(); } From 2d87bc3e6bfc9e6ccda01a5898980b1e0a706708 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 11 Sep 2025 10:23:02 +0800 Subject: [PATCH 191/251] Fix empty generic param list for generate_function Example --- ```rust struct Foo(S); impl Foo { fn foo(&self) { self.bar()$0; } } ``` **Before this PR**: ```rust struct Foo(S); impl Foo { fn foo(&self) { self.bar(); } fn bar<>(&self) ${0:-> _} { todo!() } } ``` **After this PR**: ```rust struct Foo(S); impl Foo { fn foo(&self) { self.bar(); } fn bar(&self) ${0:-> _} { todo!() } } ``` --- .../src/handlers/generate_function.rs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 88ed6f9ce124d..a9cf2c1bae1a4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -364,11 +364,13 @@ impl FunctionBuilder { Visibility::Crate => Some(make::visibility_pub_crate()), Visibility::Pub => Some(make::visibility_pub()), }; + let type_params = + self.generic_param_list.filter(|list| list.generic_params().next().is_some()); let fn_def = make::fn_( None, visibility, self.fn_name, - self.generic_param_list, + type_params, self.where_clause, self.params, self.fn_body, @@ -2415,6 +2417,33 @@ impl Foo { ) } + #[test] + fn create_method_with_unused_generics() { + check_assist( + generate_function, + r#" +struct Foo(S); +impl Foo { + fn foo(&self) { + self.bar()$0; + } +} +"#, + r#" +struct Foo(S); +impl Foo { + fn foo(&self) { + self.bar(); + } + + fn bar(&self) ${0:-> _} { + todo!() + } +} +"#, + ) + } + #[test] fn create_function_with_async() { check_assist( From 68bff8cb9db58d7006f609971e6961646b44dbe9 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 11 Sep 2025 04:53:20 +0000 Subject: [PATCH 192/251] Prepare for merging from rust-lang/rust This updates the rust-version file to f4665ab8368ad2e8a86d4390ae35c28bdd9561bb. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5b3139b25092b..b71a0d219d778 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a09fbe2c8372643a27a8082236120f95ed4e6bba +f4665ab8368ad2e8a86d4390ae35c28bdd9561bb From e54cc43867efe10c73a6063ef36fcc5aa8570ffb Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Thu, 11 Sep 2025 06:26:51 +0000 Subject: [PATCH 193/251] RISC-V: "Lower" requirements of `aes64im` This instruction is incorrectly categorized as the same one as `aes64ks1i` and `aes64ks2` (that should require `zkne || zknd` but currently require `zkne && zknd`) but `aes64im` only requires the Zknd extension. This commit fixes the category of this intrinsic (lowering the requirements from the Rust perspective but it does not actually lower it from the RISC-V perspective). --- library/stdarch/crates/core_arch/src/riscv64/zk.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/crates/core_arch/src/riscv64/zk.rs b/library/stdarch/crates/core_arch/src/riscv64/zk.rs index c6af750bbc570..a30653cbe0885 100644 --- a/library/stdarch/crates/core_arch/src/riscv64/zk.rs +++ b/library/stdarch/crates/core_arch/src/riscv64/zk.rs @@ -176,7 +176,7 @@ pub fn aes64ks2(rs1: u64, rs2: u64) -> u64 { /// Version: v1.0.1 /// /// Section: 3.9 -#[target_feature(enable = "zkne", enable = "zknd")] +#[target_feature(enable = "zknd")] #[cfg_attr(test, assert_instr(aes64im))] #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] From ad6004d95343031f3ac0898fe3582410fcc28f0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Sep 2025 11:11:40 +0200 Subject: [PATCH 194/251] add release sequence test --- src/tools/miri/src/concurrency/data_race.rs | 9 +++-- src/tools/miri/src/concurrency/weak_memory.rs | 8 +++-- .../miri/tests/pass/0weak_memory/weak.rs | 33 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index de60e80b9f7eb..16cac7e6d04c1 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -276,7 +276,7 @@ struct MemoryCellClocks { /// zero on each write operation. read: VClock, - /// Atomic access, acquire, release sequence tracking clocks. + /// Atomic access tracking clocks. /// For non-atomic memory this value is set to None. /// For atomic memory, each byte carries this information. atomic_ops: Option>, @@ -555,7 +555,8 @@ impl MemoryCellClocks { // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed // stores block release sequences. The exception for same-thread - // relaxed stores has been removed. + // relaxed stores has been removed. We always overwrite the `sync_vector`, + // meaning the previous release sequence is broken. let atomic = self.atomic_mut_unwrap(); atomic.sync_vector.clone_from(&thread_clocks.fence_release); Ok(()) @@ -571,6 +572,8 @@ impl MemoryCellClocks { ) -> Result<(), DataRace> { self.atomic_write_detect(thread_clocks, index, access_size)?; let atomic = self.atomic_mut_unwrap(); + // This *joining* of `sync_vector` implements release sequences: future + // reads of this location will acquire our clock *and* what was here before. atomic.sync_vector.join(&thread_clocks.clock); Ok(()) } @@ -585,6 +588,8 @@ impl MemoryCellClocks { ) -> Result<(), DataRace> { self.atomic_write_detect(thread_clocks, index, access_size)?; let atomic = self.atomic_mut_unwrap(); + // This *joining* of `sync_vector` implements release sequences: future + // reads of this location will acquire our fence clock *and* what was here before. atomic.sync_vector.join(&thread_clocks.fence_release); Ok(()) } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index a752ef7e45480..caa27422d2f26 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -159,9 +159,12 @@ struct StoreElement { #[derive(Debug, Clone, PartialEq, Eq, Default)] struct LoadInfo { - /// Timestamp of first loads from this store element by each thread + /// Timestamp of first loads from this store element by each thread. timestamps: FxHashMap, - /// Whether this store element has been read by an SC load + /// Whether this store element has been read by an SC load. + /// This is crucial to ensure we respect coherence-ordered-before. Concretely we use + /// this to ensure that if a store element is seen by an SC load, then all later SC loads + /// cannot see `mo`-earlier store elements. sc_loaded: bool, } @@ -476,6 +479,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, Some(init))?; + // The RMW always reads from the most recent store. buffer.read_from_last_store(global, threads, atomic == AtomicRwOrd::SeqCst); buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; } diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index 75c6e8f1a8793..44791d7cd7c50 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -198,11 +198,44 @@ fn weaker_release_sequences() { }); } +/// Ensuring normal release sequences (with RMWs) still work correctly. +fn release_sequence() { + check_all_outcomes([None, Some(1)], || { + let x = static_atomic(0); + let y = static_atomic(0); + + let t1 = spawn(move || { + x.store(2, Relaxed); + }); + let t2 = spawn(move || { + y.store(1, Relaxed); + x.store(1, Release); + x.swap(3, Relaxed); + }); + let t3 = spawn(move || { + if x.load(Acquire) == 3 { + // If we read 3 here, we are seeing the result of the `x.swap` above, which + // was relaxed but forms a release sequence with the `x.store` (since we know + // `t1` will not be scheduled in between). This means there is a release sequence, + // so we acquire the `y.store` and cannot see the original value `0` any more. + Some(y.load(Relaxed)) + } else { + None + } + }); + + t1.join().unwrap(); + t2.join().unwrap(); + t3.join().unwrap() + }); +} + pub fn main() { relaxed(); seq_cst(); initialization_write(false); initialization_write(true); faa_replaced_by_load(); + release_sequence(); weaker_release_sequences(); } From 24d195bc07da61a0ab74ac166d659f1924a604ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Sep 2025 15:03:53 +0200 Subject: [PATCH 195/251] weak_memory: fix sync clock handling when loading from old store elements --- src/tools/miri/src/concurrency/data_race.rs | 40 ++++++--- src/tools/miri/src/concurrency/weak_memory.rs | 87 +++++++++++++------ .../miri/tests/pass/0weak_memory/weak.rs | 44 +++++++--- 3 files changed, 121 insertions(+), 50 deletions(-) diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 16cac7e6d04c1..1ad9ace1b5d1a 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -183,6 +183,9 @@ struct AtomicMemoryCellClocks { /// contains the vector of timestamps that will /// happen-before a thread if an acquire-load is /// performed on the data. + /// + /// With weak memory emulation, this is the clock of the most recent write. It is then only used + /// for release sequences, to integrate the most recent clock into the next one for RMWs. sync_vector: VClock, /// The size of accesses to this atomic location. @@ -504,10 +507,11 @@ impl MemoryCellClocks { thread_clocks: &mut ThreadClockSet, index: VectorIdx, access_size: Size, + sync_clock: Option<&VClock>, ) -> Result<(), DataRace> { self.atomic_read_detect(thread_clocks, index, access_size)?; - if let Some(atomic) = self.atomic() { - thread_clocks.clock.join(&atomic.sync_vector); + if let Some(sync_clock) = sync_clock.or_else(|| self.atomic().map(|a| &a.sync_vector)) { + thread_clocks.clock.join(sync_clock); } Ok(()) } @@ -520,10 +524,11 @@ impl MemoryCellClocks { thread_clocks: &mut ThreadClockSet, index: VectorIdx, access_size: Size, + sync_clock: Option<&VClock>, ) -> Result<(), DataRace> { self.atomic_read_detect(thread_clocks, index, access_size)?; - if let Some(atomic) = self.atomic() { - thread_clocks.fence_acquire.join(&atomic.sync_vector); + if let Some(sync_clock) = sync_clock.or_else(|| self.atomic().map(|a| &a.sync_vector)) { + thread_clocks.fence_acquire.join(sync_clock); } Ok(()) } @@ -736,8 +741,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { } let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?; - let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || { - this.validate_atomic_load(place, atomic) + let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, |sync_clock| { + this.validate_atomic_load(place, atomic, sync_clock) })?; interp_ok(buffered_scalar.ok_or_else(|| err_ub!(InvalidUninitBytes(None)))?) } @@ -935,7 +940,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.validate_atomic_rmw(place, success)?; this.buffered_atomic_rmw(new, place, success, old.to_scalar())?; } else { - this.validate_atomic_load(place, fail)?; + this.validate_atomic_load(place, fail, /* can use latest sync clock */ None)?; // A failed compare exchange is equivalent to a load, reading from the latest store // in the modification order. // Since `old` is only a value and not the store element, we need to separately @@ -1177,6 +1182,18 @@ impl VClockAlloc { }))? } + /// Return the release/acquire synchronization clock for the given memory range. + pub(super) fn sync_clock(&self, access_range: AllocRange) -> VClock { + let alloc_ranges = self.alloc_ranges.borrow(); + let mut clock = VClock::default(); + for (_, mem_clocks) in alloc_ranges.iter(access_range.start, access_range.size) { + if let Some(atomic) = mem_clocks.atomic() { + clock.join(&atomic.sync_vector); + } + } + clock + } + /// Detect data-races for an unsynchronized read operation. It will not perform /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write @@ -1453,6 +1470,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { &self, place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, + sync_clock: Option<&VClock>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_atomic_op( @@ -1461,9 +1479,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { AccessType::AtomicLoad, move |memory, clocks, index, atomic| { if atomic == AtomicReadOrd::Relaxed { - memory.load_relaxed(&mut *clocks, index, place.layout.size) + memory.load_relaxed(&mut *clocks, index, place.layout.size, sync_clock) } else { - memory.load_acquire(&mut *clocks, index, place.layout.size) + memory.load_acquire(&mut *clocks, index, place.layout.size, sync_clock) } }, ) @@ -1508,9 +1526,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { AccessType::AtomicRmw, move |memory, clocks, index, _| { if acquire { - memory.load_acquire(clocks, index, place.layout.size)?; + memory.load_acquire(clocks, index, place.layout.size, None)?; } else { - memory.load_relaxed(clocks, index, place.layout.size)?; + memory.load_relaxed(clocks, index, place.layout.size, None)?; } if release { memory.rmw_release(clocks, index, place.layout.size) diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index caa27422d2f26..6ebade6a568a2 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -62,8 +62,11 @@ //! You can refer to test cases in weak_memory/extra_cpp.rs and weak_memory/extra_cpp_unsafe.rs for examples of these operations. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: -// 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), -// but this is not used anywhere so it's omitted here. +// 1. In the operational semantics, loads acquire the vector clock of the atomic location +// irrespective of which store buffer element is loaded. That's incorrect; the synchronization clock +// needs to be tracked per-store-buffer-element. (The paper has a field "clocks" for that purpose, +// but it is not actuallt used.) tsan11 does this correctly +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L305). // // 2. In the operational semantics, each store element keeps the timestamp of a thread when it loads from the store. // If the same thread loads from the same store element multiple times, then the timestamps at all loads are saved in a list of load elements. @@ -138,16 +141,17 @@ enum LoadRecency { #[derive(Debug, Clone, PartialEq, Eq)] struct StoreElement { - /// The identifier of the vector index, corresponding to a thread - /// that performed the store. - store_index: VectorIdx, + /// The thread that performed the store. + store_thread: VectorIdx, + /// The timestamp of the storing thread when it performed the store + store_timestamp: VTimestamp, + + /// The vector clock that can be acquired by loading this store. + sync_clock: VClock, /// Whether this store is SC. is_seqcst: bool, - /// The timestamp of the storing thread when it performed the store - timestamp: VTimestamp, - /// The value of this store. `None` means uninitialized. // FIXME: Currently, we cannot represent partial initialization. val: Option, @@ -246,8 +250,10 @@ impl<'tcx> StoreBuffer { let store_elem = StoreElement { // The thread index and timestamp of the initialisation write // are never meaningfully used, so it's fine to leave them as 0 - store_index: VectorIdx::from(0), - timestamp: VTimestamp::ZERO, + store_thread: VectorIdx::from(0), + store_timestamp: VTimestamp::ZERO, + // The initialization write is non-atomic so nothing can be acquired. + sync_clock: VClock::default(), val: init, is_seqcst: false, load_info: RefCell::new(LoadInfo::default()), @@ -276,7 +282,7 @@ impl<'tcx> StoreBuffer { thread_mgr: &ThreadManager<'_>, is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), - validate: impl FnOnce() -> InterpResult<'tcx>, + validate: impl FnOnce(Option<&VClock>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx, (Option, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -293,7 +299,7 @@ impl<'tcx> StoreBuffer { // after we've picked a store element from the store buffer, as presented // in ATOMIC LOAD rule of the paper. This is because fetch_store // requires access to ThreadClockSet.clock, which is updated by the race detector - validate()?; + validate(Some(&store_elem.sync_clock))?; let (index, clocks) = global.active_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks, is_seqcst); @@ -306,10 +312,11 @@ impl<'tcx> StoreBuffer { global: &DataRaceState, thread_mgr: &ThreadManager<'_>, is_seqcst: bool, + sync_clock: VClock, ) -> InterpResult<'tcx> { let (index, clocks) = global.active_thread_state(thread_mgr); - self.store_impl(val, index, &clocks.clock, is_seqcst); + self.store_impl(val, index, &clocks.clock, is_seqcst, sync_clock); interp_ok(()) } @@ -336,7 +343,9 @@ impl<'tcx> StoreBuffer { return false; } - keep_searching = if store_elem.timestamp <= clocks.clock[store_elem.store_index] { + keep_searching = if store_elem.store_timestamp + <= clocks.clock[store_elem.store_thread] + { // CoWR: if a store happens-before the current load, // then we can't read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 18 @@ -348,7 +357,7 @@ impl<'tcx> StoreBuffer { // then we cannot read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 16 false - } else if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] + } else if store_elem.store_timestamp <= clocks.write_seqcst[store_elem.store_thread] && store_elem.is_seqcst { // The current non-SC load, which may be sequenced-after an SC fence, @@ -356,7 +365,7 @@ impl<'tcx> StoreBuffer { // C++17 §32.4 [atomics.order] paragraph 4 false } else if is_seqcst - && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] + && store_elem.store_timestamp <= clocks.read_seqcst[store_elem.store_thread] { // The current SC load cannot read-before the last store sequenced-before // the last SC fence. @@ -394,17 +403,19 @@ impl<'tcx> StoreBuffer { } } - /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) + /// ATOMIC STORE IMPL in the paper fn store_impl( &mut self, val: Scalar, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, + sync_clock: VClock, ) { let store_elem = StoreElement { - store_index: index, - timestamp: thread_clock[index], + store_thread: index, + store_timestamp: thread_clock[index], + sync_clock, // In the language provided in the paper, an atomic store takes the value from a // non-atomic memory location. // But we already have the immediate value here so we don't need to do the memory @@ -422,7 +433,7 @@ impl<'tcx> StoreBuffer { // so that in a later SC load, only the last SC store (i.e. this one) or stores that // aren't ordered by hb with the last SC is picked. self.buffer.iter_mut().rev().for_each(|elem| { - if elem.timestamp <= thread_clock[elem.store_index] { + if elem.store_timestamp <= thread_clock[elem.store_thread] { elem.is_seqcst = true; } }) @@ -465,7 +476,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; if let ( crate::AllocExtra { - data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + data_race: AllocDataRaceHandler::Vclocks(data_race_clocks, Some(alloc_buffers)), .. }, crate::MiriMachine { @@ -478,20 +489,29 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { global.sc_write(threads); } let range = alloc_range(base_offset, place.layout.size); + let sync_clock = data_race_clocks.sync_clock(range); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, Some(init))?; // The RMW always reads from the most recent store. buffer.read_from_last_store(global, threads, atomic == AtomicRwOrd::SeqCst); - buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; + buffer.buffered_write( + new_val, + global, + threads, + atomic == AtomicRwOrd::SeqCst, + sync_clock, + )?; } interp_ok(()) } + /// The argument to `validate` is the synchronization clock of the memory that is being read, + /// if we are reading from a store buffer element. fn buffered_atomic_read( &self, place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, latest_in_mo: Scalar, - validate: impl FnOnce() -> InterpResult<'tcx>, + validate: impl FnOnce(Option<&VClock>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); 'fallback: { @@ -529,7 +549,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Race detector or weak memory disabled, simply read the latest value - validate()?; + validate(None)?; interp_ok(Some(latest_in_mo)) } @@ -537,6 +557,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// /// `init` says with which value to initialize the store buffer in case there wasn't a store /// buffer for this memory range before. + /// + /// Must be called *after* `validate_atomic_store` to ensure that `sync_clock` is up-to-date. fn buffered_atomic_write( &mut self, val: Scalar, @@ -548,7 +570,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?; if let ( crate::AllocExtra { - data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + data_race: AllocDataRaceHandler::Vclocks(data_race_clocks, Some(alloc_buffers)), .. }, crate::MiriMachine { @@ -560,9 +582,18 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { global.sc_write(threads); } - let buffer = alloc_buffers - .get_or_create_store_buffer_mut(alloc_range(base_offset, dest.layout.size), init)?; - buffer.buffered_write(val, global, threads, atomic == AtomicWriteOrd::SeqCst)?; + let range = alloc_range(base_offset, dest.layout.size); + // It's a bit annoying that we have to go back to the data race part to get the clock... + // but it does make things a lot simpler. + let sync_clock = data_race_clocks.sync_clock(range); + let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; + buffer.buffered_write( + val, + global, + threads, + atomic == AtomicWriteOrd::SeqCst, + sync_clock, + )?; } // Caller should've written to dest with the vanilla scalar write, we do nothing here diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index 44791d7cd7c50..c752fc114ba57 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -44,7 +44,7 @@ fn check_all_outcomes( let expected: HashSet = HashSet::from_iter(expected); let mut seen = HashSet::new(); // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 12; + let tries = expected.len() * 16; for i in 0..tries { let val = generate(); assert!(expected.contains(&val), "got an unexpected value: {val:?}"); @@ -205,19 +205,16 @@ fn release_sequence() { let y = static_atomic(0); let t1 = spawn(move || { - x.store(2, Relaxed); - }); - let t2 = spawn(move || { y.store(1, Relaxed); x.store(1, Release); x.swap(3, Relaxed); }); - let t3 = spawn(move || { + let t2 = spawn(move || { if x.load(Acquire) == 3 { - // If we read 3 here, we are seeing the result of the `x.swap` above, which - // was relaxed but forms a release sequence with the `x.store` (since we know - // `t1` will not be scheduled in between). This means there is a release sequence, - // so we acquire the `y.store` and cannot see the original value `0` any more. + // If we read 3 here, we are seeing the result of the `x.swap` above, which was + // relaxed but forms a release sequence with the `x.store`. This means there is a + // release sequence, so we acquire the `y.store` and cannot see the original value + // `0` any more. Some(y.load(Relaxed)) } else { None @@ -225,8 +222,32 @@ fn release_sequence() { }); t1.join().unwrap(); - t2.join().unwrap(); - t3.join().unwrap() + t2.join().unwrap() + }); +} + +/// Ensure that when we read from an outdated release store, we acquire its clock. +fn old_release_store() { + check_all_outcomes([None, Some(1)], || { + let x = static_atomic(0); + let y = static_atomic(0); + + let t1 = spawn(move || { + y.store(1, Relaxed); + x.store(1, Release); // this is what we want to read from + x.store(3, Relaxed); + }); + let t2 = spawn(move || { + if x.load(Acquire) == 1 { + // We must have acquired the `y.store` so we cannot see the initial value any more. + Some(y.load(Relaxed)) + } else { + None + } + }); + + t1.join().unwrap(); + t2.join().unwrap() }); } @@ -238,4 +259,5 @@ pub fn main() { faa_replaced_by_load(); release_sequence(); weaker_release_sequences(); + old_release_store(); } From 2b5b191965571142cff8fab04aad9f243041ca19 Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Thu, 11 Sep 2025 17:00:59 +0200 Subject: [PATCH 196/251] Fix miri issue 4579 by checking if the strong protector is actually "active". Where "active" means that the accessed bit is set. This also reverts miri PR 3831. --- .../src/borrow_tracker/tree_borrows/tree.rs | 2 ++ .../zero-sized-protected.stack.stderr | 15 --------- .../zero-sized-protected.tree.stderr | 32 ------------------- .../both_borrows/zero-sized-protected.rs | 7 ++-- 4 files changed, 4 insertions(+), 52 deletions(-) delete mode 100644 src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr delete mode 100644 src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr rename src/tools/miri/tests/{fail => pass}/both_borrows/zero-sized-protected.rs (53%) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 1f29bcfc2b035..22bd63bd6b6f4 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -756,6 +756,8 @@ impl<'tcx> Tree { // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). // Related to https://github.com/rust-lang/rust/issues/55005. && !perm.permission().is_cell() + // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. + && perm.is_accessed() { Err(TransitionError::ProtectedDealloc) } else { diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr deleted file mode 100644 index 3e4a7ccac363d..0000000000000 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr deleted file mode 100644 index 66a7d7794e968..0000000000000 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: Undefined Behavior: deallocation through (root of the allocation) at ALLOC[0x0] is forbidden - --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - | -LL | unsafe { dealloc(ptr, l) }; - | ^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information - = help: the allocation of the accessed tag (root of the allocation) also contains the strongly protected tag - = help: the strongly protected tag disallows deallocations -help: the accessed tag was created here - --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - | -LL | let ptr = unsafe { alloc(l) }; - | ^^^^^^^^ -help: the strongly protected tag was created here, in the initial state Reserved - --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - | -LL | fn test(_x: &mut (), ptr: *mut u8, l: Layout) { - | ^^ - = note: BACKTRACE (of the first span): - = note: inside `test` at tests/fail/both_borrows/zero-sized-protected.rs:LL:CC -note: inside `main` - --> tests/fail/both_borrows/zero-sized-protected.rs:LL:CC - | -LL | unsafe { test(&mut *ptr.cast::<()>(), ptr, l) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs b/src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs similarity index 53% rename from src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs rename to src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs index df9a73a444eda..23d283ff4a19c 100644 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs +++ b/src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs @@ -3,16 +3,13 @@ use std::alloc::{Layout, alloc, dealloc}; // `x` is strongly protected but covers zero bytes. -// Let's see if deallocating the allocation x points to is UB: -// in TB, it is UB, but in SB it is not. +// This should never be UB. fn test(_x: &mut (), ptr: *mut u8, l: Layout) { - unsafe { dealloc(ptr, l) }; //~[tree] ERROR: /deallocation .* is forbidden/ + unsafe { dealloc(ptr, l) }; } fn main() { let l = Layout::from_size_align(1, 1).unwrap(); let ptr = unsafe { alloc(l) }; unsafe { test(&mut *ptr.cast::<()>(), ptr, l) }; - // In SB the test would pass if it weren't for this line. - unsafe { std::hint::unreachable_unchecked() }; //~[stack] ERROR: unreachable } From 68217c79b246bceecca23d8d3862af71b97bff0d Mon Sep 17 00:00:00 2001 From: Ifeanyi Orizu Date: Mon, 8 Sep 2025 16:09:59 -0500 Subject: [PATCH 197/251] Minor refactoring --- .../crates/rust-analyzer/src/flycheck.rs | 8 +- .../src/handlers/notification.rs | 282 ++++++++++-------- .../crates/rust-analyzer/src/reload.rs | 20 +- 3 files changed, 170 insertions(+), 140 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 01ac75c09aee6..315c45d5b6392 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -104,11 +104,11 @@ pub(crate) enum FlycheckConfig { } impl FlycheckConfig { - pub(crate) fn invocation_strategy_once(&self) -> bool { + pub(crate) fn invocation_strategy(&self) -> InvocationStrategy { match self { - FlycheckConfig::CargoCommand { .. } => false, + FlycheckConfig::CargoCommand { .. } => InvocationStrategy::PerWorkspace, FlycheckConfig::CustomCommand { invocation_strategy, .. } => { - *invocation_strategy == InvocationStrategy::Once + invocation_strategy.clone() } } } @@ -529,7 +529,7 @@ impl FlycheckActor { if let Some(command_handle) = self.command_handle.take() { tracing::debug!( command = ?command_handle, - "did cancel flycheck" + "did cancel flycheck" ); command_handle.cancel(); self.command_receiver.take(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index fb743e73c74a4..68c91a653940b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -1,9 +1,11 @@ //! This module is responsible for implementing handlers for Language Server //! Protocol. This module specifically handles notifications. -use std::ops::{Deref, Not as _}; +use std::{ + ops::{Deref, Not as _}, + panic::UnwindSafe, +}; -use ide_db::base_db::salsa::Cancelled; use itertools::Itertools; use lsp_types::{ CancelParams, DidChangeConfigurationParams, DidChangeTextDocumentParams, @@ -16,7 +18,7 @@ use vfs::{AbsPathBuf, ChangeKind, VfsPath}; use crate::{ config::{Config, ConfigChange}, - flycheck::Target, + flycheck::{InvocationStrategy, Target}, global_state::{FetchWorkspaceRequest, GlobalState}, lsp::{from_proto, utils::apply_document_changes}, lsp_ext::{self, RunFlycheckParams}, @@ -301,131 +303,165 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let file_id = state.vfs.read().0.file_id(&vfs_path); if let Some((file_id, vfs::FileExcluded::No)) = file_id { let world = state.snapshot(); - let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once(); + let invocation_strategy = state.config.flycheck(None).invocation_strategy(); let may_flycheck_workspace = state.config.flycheck_workspace(None); - let mut workspace_check_triggered = false; - let task = move || -> std::result::Result<(), Cancelled> { - let saved_file = vfs_path.as_path().map(|p| p.to_owned()); - if invocation_strategy_once { - world.flycheck[0].restart_workspace(saved_file.clone()); - } - let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { - let tgt_kind = it.target_kind(); - let (tgt_name, root, package) = match it { - TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package), - _ => return None, - }; - - let tgt = match tgt_kind { - project_model::TargetKind::Bin => Target::Bin(tgt_name), - project_model::TargetKind::Example => Target::Example(tgt_name), - project_model::TargetKind::Test => Target::Test(tgt_name), - project_model::TargetKind::Bench => Target::Benchmark(tgt_name), - _ => return Some((None, root, package)), - }; - - Some((Some(tgt), root, package)) - }); - tracing::debug!(?target, "flycheck target"); - // we have a specific non-library target, attempt to only check that target, nothing - // else will be affected - let mut package_workspace_idx = None; - if let Some((target, root, package)) = target { - // trigger a package check if we have a non-library target as that can't affect - // anything else in the workspace OR if we're not allowed to check the workspace as - // the user opted into package checks then - let package_check_allowed = target.is_some() || !may_flycheck_workspace; - if package_check_allowed { - let workspace = world.workspaces.iter().position(|ws| match &ws.kind { - project_model::ProjectWorkspaceKind::Cargo { cargo, .. } - | project_model::ProjectWorkspaceKind::DetachedFile { - cargo: Some((cargo, _, _)), - .. - } => *cargo.workspace_root() == root, - _ => false, - }); - if let Some(idx) = workspace { - package_workspace_idx = Some(idx); - world.flycheck[idx].restart_for_package(package, target); - } + let task: Box ide::Cancellable<()> + Send + UnwindSafe> = + match invocation_strategy { + InvocationStrategy::Once => { + Box::new(move || { + // FIXME: Because triomphe::Arc's auto UnwindSafe impl requires that the inner type + // be UnwindSafe, and FlycheckHandle is not UnwindSafe, `word.flycheck` cannot + // be captured directly. std::sync::Arc has an UnwindSafe impl that only requires + // that the inner type be RefUnwindSafe, so if we were using that one we wouldn't + // have this problem. Remove the line below when triomphe::Arc has an UnwindSafe impl + // like std::sync::Arc's. + let world = world; + stdx::always!( + world.flycheck.len() == 1, + "should have exactly one flycheck handle when invocation strategy is once" + ); + let saved_file = vfs_path.as_path().map(ToOwned::to_owned); + world.flycheck[0].restart_workspace(saved_file); + Ok(()) + }) } - } - - if !may_flycheck_workspace { - return Ok(()); - } - - // Trigger flychecks for all workspaces that depend on the saved file - // Crates containing or depending on the saved file - let crate_ids = world - .analysis - .crates_for(file_id)? - .into_iter() - .flat_map(|id| world.analysis.transitive_rev_deps(id)) - .flatten() - .unique() - .collect::>(); - tracing::debug!(?crate_ids, "flycheck crate ids"); - let crate_root_paths: Vec<_> = crate_ids - .iter() - .filter_map(|&crate_id| { - world - .analysis - .crate_root(crate_id) - .map(|file_id| { - world.file_id_to_file_path(file_id).as_path().map(ToOwned::to_owned) - }) - .transpose() - }) - .collect::>()?; - let crate_root_paths: Vec<_> = crate_root_paths.iter().map(Deref::deref).collect(); - tracing::debug!(?crate_root_paths, "flycheck crate roots"); - - // Find all workspaces that have at least one target containing the saved file - let workspace_ids = world - .workspaces - .iter() - .enumerate() - .filter(|&(idx, _)| match package_workspace_idx { - Some(pkg_idx) => idx != pkg_idx, - None => true, - }) - .filter(|&(_, ws)| match &ws.kind { - project_model::ProjectWorkspaceKind::Cargo { cargo, .. } - | project_model::ProjectWorkspaceKind::DetachedFile { - cargo: Some((cargo, _, _)), - .. - } => cargo.packages().any(|pkg| { - cargo[pkg] - .targets + InvocationStrategy::PerWorkspace => { + Box::new(move || { + let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { + let tgt_kind = it.target_kind(); + let (tgt_name, root, package) = match it { + TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package), + _ => return None, + }; + + let tgt = match tgt_kind { + project_model::TargetKind::Bin => Target::Bin(tgt_name), + project_model::TargetKind::Example => Target::Example(tgt_name), + project_model::TargetKind::Test => Target::Test(tgt_name), + project_model::TargetKind::Bench => Target::Benchmark(tgt_name), + _ => return Some((None, root, package)), + }; + + Some((Some(tgt), root, package)) + }); + tracing::debug!(?target, "flycheck target"); + // we have a specific non-library target, attempt to only check that target, nothing + // else will be affected + let mut package_workspace_idx = None; + if let Some((target, root, package)) = target { + // trigger a package check if we have a non-library target as that can't affect + // anything else in the workspace OR if we're not allowed to check the workspace as + // the user opted into package checks then + let package_check_allowed = target.is_some() || !may_flycheck_workspace; + if package_check_allowed { + package_workspace_idx = + world.workspaces.iter().position(|ws| match &ws.kind { + project_model::ProjectWorkspaceKind::Cargo { + cargo, + .. + } + | project_model::ProjectWorkspaceKind::DetachedFile { + cargo: Some((cargo, _, _)), + .. + } => *cargo.workspace_root() == root, + _ => false, + }); + if let Some(idx) = package_workspace_idx { + world.flycheck[idx].restart_for_package(package, target); + } + } + } + + if !may_flycheck_workspace { + return Ok(()); + } + + // Trigger flychecks for all workspaces that depend on the saved file + // Crates containing or depending on the saved file + let crate_ids: Vec<_> = world + .analysis + .crates_for(file_id)? + .into_iter() + .flat_map(|id| world.analysis.transitive_rev_deps(id)) + .flatten() + .unique() + .collect(); + tracing::debug!(?crate_ids, "flycheck crate ids"); + let crate_root_paths: Vec<_> = crate_ids .iter() - .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path())) - }), - project_model::ProjectWorkspaceKind::Json(project) => project - .crates() - .any(|(_, krate)| crate_root_paths.contains(&krate.root_module.as_path())), - project_model::ProjectWorkspaceKind::DetachedFile { .. } => false, - }); - - // Find and trigger corresponding flychecks - 'flychecks: for flycheck in world.flycheck.iter() { - for (id, _) in workspace_ids.clone() { - if id == flycheck.id() { - workspace_check_triggered = true; - flycheck.restart_workspace(saved_file.clone()); - continue 'flychecks; - } - } - } - // No specific flycheck was triggered, so let's trigger all of them. - if !workspace_check_triggered && package_workspace_idx.is_none() { - for flycheck in world.flycheck.iter() { - flycheck.restart_workspace(saved_file.clone()); + .filter_map(|&crate_id| { + world + .analysis + .crate_root(crate_id) + .map(|file_id| { + world + .file_id_to_file_path(file_id) + .as_path() + .map(ToOwned::to_owned) + }) + .transpose() + }) + .collect::>()?; + let crate_root_paths: Vec<_> = + crate_root_paths.iter().map(Deref::deref).collect(); + tracing::debug!(?crate_root_paths, "flycheck crate roots"); + + // Find all workspaces that have at least one target containing the saved file + let workspace_ids = + world.workspaces.iter().enumerate().filter(|&(idx, ws)| { + let ws_contains_file = match &ws.kind { + project_model::ProjectWorkspaceKind::Cargo { + cargo, .. + } + | project_model::ProjectWorkspaceKind::DetachedFile { + cargo: Some((cargo, _, _)), + .. + } => cargo.packages().any(|pkg| { + cargo[pkg].targets.iter().any(|&it| { + crate_root_paths.contains(&cargo[it].root.as_path()) + }) + }), + project_model::ProjectWorkspaceKind::Json(project) => { + project.crates().any(|(_, krate)| { + crate_root_paths.contains(&krate.root_module.as_path()) + }) + } + project_model::ProjectWorkspaceKind::DetachedFile { + .. + } => false, + }; + let is_pkg_ws = match package_workspace_idx { + Some(pkg_idx) => pkg_idx == idx, + None => false, + }; + ws_contains_file && !is_pkg_ws + }); + + let saved_file = vfs_path.as_path().map(ToOwned::to_owned); + let mut workspace_check_triggered = false; + // Find and trigger corresponding flychecks + 'flychecks: for flycheck in world.flycheck.iter() { + for (id, _) in workspace_ids.clone() { + if id == flycheck.id() { + workspace_check_triggered = true; + flycheck.restart_workspace(saved_file.clone()); + continue 'flychecks; + } + } + } + + // No specific flycheck was triggered, so let's trigger all of them. + if !workspace_check_triggered && package_workspace_idx.is_none() { + for flycheck in world.flycheck.iter() { + flycheck.restart_workspace(saved_file.clone()); + } + } + Ok(()) + }) } - } - Ok(()) - }; + }; + state.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, move |_| { if let Err(e) = std::panic::catch_unwind(task) { tracing::error!("flycheck task panicked: {e:?}") diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index a8a54930c6e5e..27738fee51407 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -318,7 +318,7 @@ impl GlobalState { } } - let mut workspaces = linked_projects + let mut workspaces: Vec<_> = linked_projects .iter() .map(|project| match project { LinkedProject::ProjectManifest(manifest) => { @@ -339,7 +339,7 @@ impl GlobalState { Ok(workspace) } }) - .collect::>(); + .collect(); let mut i = 0; while i < workspaces.len() { @@ -848,23 +848,17 @@ impl GlobalState { fn reload_flycheck(&mut self) { let _p = tracing::info_span!("GlobalState::reload_flycheck").entered(); let config = self.config.flycheck(None); - let sender = self.flycheck_sender.clone(); - let invocation_strategy = match config { - FlycheckConfig::CargoCommand { .. } => { - crate::flycheck::InvocationStrategy::PerWorkspace - } - FlycheckConfig::CustomCommand { ref invocation_strategy, .. } => { - invocation_strategy.clone() - } - }; - let next_gen = self.flycheck.iter().map(|f| f.generation() + 1).max().unwrap_or_default(); + let sender = &self.flycheck_sender; + let invocation_strategy = config.invocation_strategy(); + let next_gen = + self.flycheck.iter().map(FlycheckHandle::generation).max().unwrap_or_default() + 1; self.flycheck = match invocation_strategy { crate::flycheck::InvocationStrategy::Once => { vec![FlycheckHandle::spawn( 0, next_gen, - sender, + sender.clone(), config, None, self.config.root_path().clone(), From 16b34c6f7056701bbe66892e2d5300d80eae0830 Mon Sep 17 00:00:00 2001 From: Johannes Hostert Date: Thu, 11 Sep 2025 19:15:50 +0200 Subject: [PATCH 198/251] move zero-sized protector dealloc test --- .../pass/both_borrows/basic_aliasing_model.rs | 10 ++++++++++ .../pass/both_borrows/zero-sized-protected.rs | 15 --------------- 2 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs index 82976326a8df3..115e232dde4c2 100644 --- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs +++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs @@ -1,6 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows #![feature(allocator_api)] +use std::alloc::{Layout, alloc, dealloc}; use std::cell::Cell; use std::ptr; @@ -305,5 +306,14 @@ fn zst() { let ptr = &raw mut *b as *mut (); drop(b); let _ref = &mut *ptr; + + // zero-sized protectors do not affect deallocation + fn with_protector(_x: &mut (), ptr: *mut u8, l: Layout) { + // `_x` here is strongly protected but covers zero bytes. + unsafe { dealloc(ptr, l) }; + } + let l = Layout::from_size_align(1, 1).unwrap(); + let ptr = alloc(l); + with_protector(&mut *ptr.cast::<()>(), ptr, l); } } diff --git a/src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs b/src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs deleted file mode 100644 index 23d283ff4a19c..0000000000000 --- a/src/tools/miri/tests/pass/both_borrows/zero-sized-protected.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows -use std::alloc::{Layout, alloc, dealloc}; - -// `x` is strongly protected but covers zero bytes. -// This should never be UB. -fn test(_x: &mut (), ptr: *mut u8, l: Layout) { - unsafe { dealloc(ptr, l) }; -} - -fn main() { - let l = Layout::from_size_align(1, 1).unwrap(); - let ptr = unsafe { alloc(l) }; - unsafe { test(&mut *ptr.cast::<()>(), ptr, l) }; -} From bb31725e679c48e75e54c8ec88c7e654c5509d37 Mon Sep 17 00:00:00 2001 From: sayantn Date: Fri, 12 Sep 2025 01:20:34 +0530 Subject: [PATCH 199/251] Remove big-endian swizzles from `vreinterpret` --- .../core_arch/src/aarch64/neon/generated.rs | 971 +- .../src/arm_shared/neon/generated.rs | 10279 ++-------------- .../spec/neon/aarch64.spec.yml | 2 + .../spec/neon/arm_shared.spec.yml | 4 + 4 files changed, 988 insertions(+), 10268 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs index 554a809db8db2..855261aaecfd0 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs @@ -21477,172 +21477,73 @@ pub fn vrecpxh_f16(a: f16) -> f16 { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_f16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_f16)"] -#[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_f16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_f16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f16_f64(a: float64x2_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f16_f64(a: float64x2_t) -> float16x8_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p128)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p128(a: p128) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f64_p128(a: p128) -> float64x2_t { - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_f32(a: float32x2_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f64_f32(a: float32x2_t) -> float64x1_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_p64_f32(a: float32x2_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_p64_f32(a: float32x2_t) -> poly64x1_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21650,23 +21551,8 @@ pub fn vreinterpretq_f64_f32(a: float32x4_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_f32(a: float32x4_t) -> float64x2_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21674,23 +21560,8 @@ pub fn vreinterpretq_p64_f32(a: float32x4_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_f32(a: float32x4_t) -> poly64x2_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21698,22 +21569,8 @@ pub fn vreinterpret_f32_f64(a: float64x1_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f32_f64(a: float64x1_t) -> float32x2_t { - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21721,22 +21578,8 @@ pub fn vreinterpret_s8_f64(a: float64x1_t) -> int8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_s8_f64(a: float64x1_t) -> int8x8_t { - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21744,22 +21587,8 @@ pub fn vreinterpret_s16_f64(a: float64x1_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_s16_f64(a: float64x1_t) -> int16x4_t { - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21767,19 +21596,6 @@ pub fn vreinterpret_s32_f64(a: float64x1_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_s32_f64(a: float64x1_t) -> int32x2_t { - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f64)"] #[inline] #[target_feature(enable = "neon")] @@ -21791,7 +21607,6 @@ pub fn vreinterpret_s64_f64(a: float64x1_t) -> int64x1_t { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21799,22 +21614,8 @@ pub fn vreinterpret_u8_f64(a: float64x1_t) -> uint8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_u8_f64(a: float64x1_t) -> uint8x8_t { - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21822,22 +21623,8 @@ pub fn vreinterpret_u16_f64(a: float64x1_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_u16_f64(a: float64x1_t) -> uint16x4_t { - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21845,19 +21632,6 @@ pub fn vreinterpret_u32_f64(a: float64x1_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_u32_f64(a: float64x1_t) -> uint32x2_t { - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f64)"] #[inline] #[target_feature(enable = "neon")] @@ -21869,7 +21643,6 @@ pub fn vreinterpret_u64_f64(a: float64x1_t) -> uint64x1_t { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21877,22 +21650,8 @@ pub fn vreinterpret_p8_f64(a: float64x1_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_p8_f64(a: float64x1_t) -> poly8x8_t { - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21900,19 +21659,6 @@ pub fn vreinterpret_p16_f64(a: float64x1_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_p16_f64(a: float64x1_t) -> poly16x4_t { - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f64)"] #[inline] #[target_feature(enable = "neon")] @@ -21924,7 +21670,6 @@ pub fn vreinterpret_p64_f64(a: float64x1_t) -> poly64x1_t { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -21932,96 +21677,35 @@ pub fn vreinterpretq_p128_f64(a: float64x2_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p128_f64(a: float64x2_t) -> p128 { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpretq_f32_f64(a: float64x2_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f32_f64(a: float64x2_t) -> float32x4_t { +pub fn vreinterpretq_s8_f64(a: float64x2_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f32_f64(a: float64x2_t) -> float32x4_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s16_f64(a: float64x2_t) -> int16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s8_f64(a: float64x2_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s8_f64(a: float64x2_t) -> int8x16_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s16_f64(a: float64x2_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s16_f64(a: float64x2_t) -> int16x8_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f64)"] -#[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -22029,736 +21713,301 @@ pub fn vreinterpretq_s32_f64(a: float64x2_t) -> int32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s32_f64(a: float64x2_t) -> int32x4_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s64_f64(a: float64x2_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_s64_f64(a: float64x2_t) -> int64x2_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u8_f64(a: float64x2_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u8_f64(a: float64x2_t) -> uint8x16_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u16_f64(a: float64x2_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u16_f64(a: float64x2_t) -> uint16x8_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u32_f64(a: float64x2_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u32_f64(a: float64x2_t) -> uint32x4_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u64_f64(a: float64x2_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u64_f64(a: float64x2_t) -> uint64x2_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p8_f64(a: float64x2_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p8_f64(a: float64x2_t) -> poly8x16_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p16_f64(a: float64x2_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p16_f64(a: float64x2_t) -> poly16x8_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_f64(a: float64x2_t) -> poly64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_f64(a: float64x2_t) -> poly64x2_t { - let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s8(a: int8x8_t) -> float64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s8(a: int8x8_t) -> float64x1_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s8(a: int8x16_t) -> float64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s8(a: int8x16_t) -> float64x2_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s16(a: int16x4_t) -> float64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s16(a: int16x4_t) -> float64x1_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s16(a: int16x8_t) -> float64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s16(a: int16x8_t) -> float64x2_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s32(a: int32x2_t) -> float64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s32(a: int32x2_t) -> float64x1_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s32(a: int32x4_t) -> float64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s32(a: int32x4_t) -> float64x2_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s64)"] -#[inline] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_s64(a: int64x1_t) -> float64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s64)"] -#[inline] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_p64_s64(a: int64x1_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s64(a: int64x2_t) -> float64x2_t { +pub fn vreinterpretq_u8_f64(a: float64x2_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_s64(a: int64x2_t) -> float64x2_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u16_f64(a: float64x2_t) -> uint16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_s64(a: int64x2_t) -> poly64x2_t { +pub fn vreinterpretq_u32_f64(a: float64x2_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_s64(a: int64x2_t) -> poly64x2_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u64_f64(a: float64x2_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u8(a: uint8x8_t) -> float64x1_t { +pub fn vreinterpretq_p8_f64(a: float64x2_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u8(a: uint8x8_t) -> float64x1_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_p16_f64(a: float64x2_t) -> poly16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u8(a: uint8x16_t) -> float64x2_t { +pub fn vreinterpretq_p64_f64(a: float64x2_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u8(a: uint8x16_t) -> float64x2_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_f64_s8(a: int8x8_t) -> float64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u16(a: uint16x4_t) -> float64x1_t { +pub fn vreinterpretq_f64_s8(a: int8x16_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u16(a: uint16x4_t) -> float64x1_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpret_f64_s16(a: int16x4_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u16(a: uint16x8_t) -> float64x2_t { +pub fn vreinterpretq_f64_s16(a: int16x8_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u16(a: uint16x8_t) -> float64x2_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_f64_s32(a: int32x2_t) -> float64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u32(a: uint32x2_t) -> float64x1_t { +pub fn vreinterpretq_f64_s32(a: int32x4_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u32(a: uint32x2_t) -> float64x1_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpret_f64_s64(a: int64x1_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u32(a: uint32x4_t) -> float64x2_t { +pub fn vreinterpret_p64_s64(a: int64x1_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u32(a: uint32x4_t) -> float64x2_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_f64_s64(a: int64x2_t) -> float64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s64)"] #[inline] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_u64(a: uint64x1_t) -> float64x1_t { +pub fn vreinterpretq_p64_s64(a: int64x2_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u8)"] #[inline] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_p64_u64(a: uint64x1_t) -> poly64x1_t { +pub fn vreinterpret_f64_u8(a: uint8x8_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u64(a: uint64x2_t) -> float64x2_t { +pub fn vreinterpretq_f64_u8(a: uint8x16_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_u64(a: uint64x2_t) -> float64x2_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_f64_u16(a: uint16x4_t) -> float64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_u64(a: uint64x2_t) -> poly64x2_t { +pub fn vreinterpretq_f64_u16(a: uint16x8_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_p64_u64(a: uint64x2_t) -> poly64x2_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_f64_u32(a: uint32x2_t) -> float64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_p8(a: poly8x8_t) -> float64x1_t { +pub fn vreinterpretq_f64_u32(a: uint32x4_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_u64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_p8(a: poly8x8_t) -> float64x1_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_f64_u64(a: uint64x1_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p8(a: poly8x16_t) -> float64x2_t { +pub fn vreinterpret_p64_u64(a: uint64x1_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_u64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p8(a: poly8x16_t) -> float64x2_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_f64_u64(a: uint64x2_t) -> float64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_p16(a: poly16x4_t) -> float64x1_t { +pub fn vreinterpretq_p64_u64(a: uint64x2_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f64_p16(a: poly16x4_t) -> float64x1_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpret_f64_p8(a: poly8x8_t) -> float64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p16(a: poly16x8_t) -> float64x2_t { +pub fn vreinterpretq_f64_p8(a: poly8x16_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p16(a: poly16x8_t) -> float64x2_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_f64_p16(a: poly16x4_t) -> float64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpret_f32_p64(a: poly64x1_t) -> float32x2_t { +pub fn vreinterpretq_f64_p16(a: poly16x8_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f32_p64(a: poly64x1_t) -> float32x2_t { - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f64_p64)"] @@ -22790,7 +22039,6 @@ pub fn vreinterpret_u64_p64(a: poly64x1_t) -> uint64x1_t { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -22798,23 +22046,8 @@ pub fn vreinterpretq_f32_p64(a: poly64x2_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f32_p64(a: poly64x2_t) -> float32x4_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -22822,23 +22055,8 @@ pub fn vreinterpretq_f64_p64(a: poly64x2_t) -> float64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f64_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_f64_p64(a: poly64x2_t) -> float64x2_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] @@ -22846,43 +22064,14 @@ pub fn vreinterpretq_s64_p64(a: poly64x2_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_s64_p64(a: poly64x2_t) -> int64x2_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[stable(feature = "neon_intrinsics", since = "1.59.0")] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_u64_p64(a: poly64x2_t) -> uint64x2_t { unsafe { transmute(a) } } -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[stable(feature = "neon_intrinsics", since = "1.59.0")] -#[cfg_attr(test, assert_instr(nop))] -pub fn vreinterpretq_u64_p64(a: poly64x2_t) -> uint64x2_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} #[doc = "Floating-point round to 32-bit integer, using current rounding mode"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrnd32x_f32)"] #[inline] diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index b5ba792b18aec..e4e4e040f468d 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -42089,7 +42089,6 @@ pub fn vrecpsq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42103,9 +42102,8 @@ pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42115,17 +42113,12 @@ pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42135,13 +42128,12 @@ pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { +pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42151,17 +42143,12 @@ pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42171,13 +42158,12 @@ pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { +pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42187,17 +42173,12 @@ pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42207,13 +42188,12 @@ pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { +pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42223,17 +42203,12 @@ pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42243,13 +42218,12 @@ pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { +pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42259,14 +42233,12 @@ pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42276,13 +42248,12 @@ pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { +pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42292,17 +42263,12 @@ pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42312,13 +42278,12 @@ pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { +pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42328,17 +42293,12 @@ pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42348,13 +42308,12 @@ pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { +pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42364,17 +42323,12 @@ pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42384,13 +42338,12 @@ pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { +pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42400,14 +42353,12 @@ pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42417,13 +42368,12 @@ pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { +pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42433,17 +42383,12 @@ pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42453,13 +42398,12 @@ pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { +pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42469,17 +42413,12 @@ pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_f32)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42489,13 +42428,12 @@ pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { +pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_f32)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42505,17 +42443,12 @@ pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42525,13 +42458,12 @@ pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { +pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s8)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42541,21 +42473,12 @@ pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42565,13 +42488,12 @@ pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { +pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42581,17 +42503,12 @@ pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s32)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42601,13 +42518,12 @@ pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { +pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s32)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42617,17 +42533,12 @@ pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s64)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42637,13 +42548,12 @@ pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { +pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s64)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42653,17 +42563,12 @@ pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u8)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42673,13 +42578,12 @@ pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { +pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u8)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42689,21 +42593,12 @@ pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42713,13 +42608,12 @@ pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { +pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u16)"] #[inline] -#[cfg(target_endian = "big")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42729,53 +42623,12 @@ pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { +pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42785,33 +42638,12 @@ pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { +pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42821,37 +42653,12 @@ pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { +pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u64)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42861,33 +42668,12 @@ pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { +pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_f32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u64)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42897,33 +42683,12 @@ pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { +pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_f32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p8)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42933,33 +42698,12 @@ pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { +pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p8)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -42969,33 +42713,12 @@ pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { +pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -43005,34 +42728,12 @@ pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { +pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p16)"] #[inline] -#[cfg(target_endian = "little")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( @@ -43042,34 +42743,13 @@ pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { +pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p128)"] #[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -43078,14 +42758,13 @@ pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { +pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f16)"] #[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -43094,18 +42773,13 @@ pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f16)"] #[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -43114,7391 +42788,57 @@ pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { +pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u32)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u32)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u32)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_u64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_u64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p8)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p8)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p8)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p128)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p128)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { - let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f16)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f16)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { - let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { - unsafe { - let ret_val: float16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p64)"] -#[inline] -#[cfg(target_endian = "little")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p64)"] -#[inline] -#[cfg(target_endian = "big")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[target_feature(enable = "neon,fp16")] -#[unstable(feature = "stdarch_neon_f16", issue = "136306")] -#[cfg(not(target_arch = "arm64ec"))] -pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p128)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_p128(a: p128) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p128)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_p128(a: p128) -> float32x4_t { - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { - let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p128_f32(a: float32x4_t) -> p128 { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p128_f32(a: float32x4_t) -> p128 { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { - let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s32)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s32)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s64)"] -#[inline] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_s64(a: int64x1_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s64)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s64)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u8)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u8)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { - unsafe { transmute(a) } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u16)"] -#[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] -#[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), - assert_instr(nop) -)] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } -} -#[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u16)"] -#[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_f16)"] +#[inline] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), assert_instr(nop) )] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { +#[target_feature(enable = "neon,fp16")] +#[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] +pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f16_p64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), assert_instr(nop) )] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +#[target_feature(enable = "neon,fp16")] +#[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] +pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f16_p64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), assert_instr(nop) )] -#[cfg_attr( - not(target_arch = "arm"), - stable(feature = "neon_intrinsics", since = "1.59.0") -)] -#[cfg_attr( - target_arch = "arm", - unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") -)] -pub fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { +#[target_feature(enable = "neon,fp16")] +#[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] +pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50514,21 +42854,12 @@ pub fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_f32_p128(a: p128) -> float32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50544,13 +42875,12 @@ pub fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { +pub fn vreinterpret_s8_f32(a: float32x2_t) -> int8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50566,17 +42896,12 @@ pub fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_s16_f32(a: float32x2_t) -> int16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50592,13 +42917,12 @@ pub fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { +pub fn vreinterpret_s32_f32(a: float32x2_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50614,17 +42938,12 @@ pub fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s64_f32(a: float32x2_t) -> int64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50640,13 +42959,12 @@ pub fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { +pub fn vreinterpret_u8_f32(a: float32x2_t) -> uint8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50662,21 +42980,12 @@ pub fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_u16_f32(a: float32x2_t) -> uint16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50692,13 +43001,12 @@ pub fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { +pub fn vreinterpret_u32_f32(a: float32x2_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50714,17 +43022,12 @@ pub fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u64_f32(a: float32x2_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50740,13 +43043,12 @@ pub fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { +pub fn vreinterpret_p8_f32(a: float32x2_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50762,17 +43064,12 @@ pub fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_p16_f32(a: float32x2_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50788,13 +43085,12 @@ pub fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { +pub fn vreinterpretq_p128_f32(a: float32x4_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50810,17 +43106,12 @@ pub fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_f32(a: float32x4_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50836,13 +43127,12 @@ pub fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { +pub fn vreinterpretq_s16_f32(a: float32x4_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50858,17 +43148,12 @@ pub fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s32_f32(a: float32x4_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50884,13 +43169,12 @@ pub fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { +pub fn vreinterpretq_s64_f32(a: float32x4_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50906,17 +43190,12 @@ pub fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u8_f32(a: float32x4_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50932,13 +43211,12 @@ pub fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { +pub fn vreinterpretq_u16_f32(a: float32x4_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50954,14 +43232,12 @@ pub fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpretq_u32_f32(a: float32x4_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50977,13 +43253,12 @@ pub fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { +pub fn vreinterpretq_u64_f32(a: float32x4_t) -> uint64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_f32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -50999,17 +43274,12 @@ pub fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_p8_f32(a: float32x4_t) -> poly8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_f32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51025,13 +43295,12 @@ pub fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { +pub fn vreinterpretq_p16_f32(a: float32x4_t) -> poly16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51047,17 +43316,12 @@ pub fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_f32_s8(a: int8x8_t) -> float32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51073,13 +43337,12 @@ pub fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { +pub fn vreinterpret_s16_s8(a: int8x8_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51095,14 +43358,12 @@ pub fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpret_s32_s8(a: int8x8_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51118,13 +43379,12 @@ pub fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { +pub fn vreinterpret_s64_s8(a: int8x8_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51140,17 +43400,12 @@ pub fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u8_s8(a: int8x8_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51166,13 +43421,12 @@ pub fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { +pub fn vreinterpret_u16_s8(a: int8x8_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51188,17 +43442,12 @@ pub fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u32_s8(a: int8x8_t) -> uint32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51214,13 +43463,12 @@ pub fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { +pub fn vreinterpret_u64_s8(a: int8x8_t) -> uint64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51236,17 +43484,12 @@ pub fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_p8_s8(a: int8x8_t) -> poly8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51262,13 +43505,12 @@ pub fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { +pub fn vreinterpret_p16_s8(a: int8x8_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51284,21 +43526,12 @@ pub fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_f32_s8(a: int8x16_t) -> float32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51314,13 +43547,12 @@ pub fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { +pub fn vreinterpretq_s16_s8(a: int8x16_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51336,17 +43568,12 @@ pub fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s32_s8(a: int8x16_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51362,13 +43589,12 @@ pub fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { +pub fn vreinterpretq_s64_s8(a: int8x16_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51384,17 +43610,12 @@ pub fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_u8_s8(a: int8x16_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51410,13 +43631,12 @@ pub fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { +pub fn vreinterpretq_u16_s8(a: int8x16_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51432,17 +43652,12 @@ pub fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u32_s8(a: int8x16_t) -> uint32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51458,13 +43673,12 @@ pub fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { +pub fn vreinterpretq_u64_s8(a: int8x16_t) -> uint64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51480,21 +43694,12 @@ pub fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_p8_s8(a: int8x16_t) -> poly8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51510,13 +43715,12 @@ pub fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { +pub fn vreinterpretq_p16_s8(a: int8x16_t) -> poly16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51532,17 +43736,12 @@ pub fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_f32_s16(a: int16x4_t) -> float32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51558,13 +43757,12 @@ pub fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { +pub fn vreinterpret_s8_s16(a: int16x4_t) -> int8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51580,17 +43778,12 @@ pub fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s32_s16(a: int16x4_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51606,13 +43799,12 @@ pub fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { +pub fn vreinterpret_s64_s16(a: int16x4_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51628,21 +43820,12 @@ pub fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_u8_s16(a: int16x4_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51658,13 +43841,12 @@ pub fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { +pub fn vreinterpret_u16_s16(a: int16x4_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51680,17 +43862,12 @@ pub fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u32_s16(a: int16x4_t) -> uint32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51706,13 +43883,12 @@ pub fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { +pub fn vreinterpret_u64_s16(a: int16x4_t) -> uint64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51728,16 +43904,12 @@ pub fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_p8_s16(a: int16x4_t) -> poly8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51753,13 +43925,12 @@ pub fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { +pub fn vreinterpret_p16_s16(a: int16x4_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51775,16 +43946,12 @@ pub fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_f32_s16(a: int16x8_t) -> float32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51800,13 +43967,12 @@ pub fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { +pub fn vreinterpretq_s8_s16(a: int16x8_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51822,16 +43988,12 @@ pub fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s32_s16(a: int16x8_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51847,13 +44009,12 @@ pub fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { +pub fn vreinterpretq_s64_s16(a: int16x8_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51869,14 +44030,11 @@ pub fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u8_s16(a: int16x8_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s16)"] #[inline] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] @@ -51893,13 +44051,12 @@ pub fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { +pub fn vreinterpretq_u16_s16(a: int16x8_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51915,13 +44072,12 @@ pub fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { +pub fn vreinterpretq_u32_s16(a: int16x8_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51937,16 +44093,12 @@ pub fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_u64_s16(a: int16x8_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51962,13 +44114,12 @@ pub fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { +pub fn vreinterpretq_p8_s16(a: int16x8_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -51984,16 +44135,12 @@ pub fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_s16(a: int16x8_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52009,13 +44156,12 @@ pub fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { +pub fn vreinterpret_f32_s32(a: int32x2_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52031,16 +44177,12 @@ pub fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s8_s32(a: int32x2_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52056,13 +44198,12 @@ pub fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { +pub fn vreinterpret_s16_s32(a: int32x2_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52078,16 +44219,12 @@ pub fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_s64_s32(a: int32x2_t) -> int64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52103,13 +44240,12 @@ pub fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { +pub fn vreinterpret_u8_s32(a: int32x2_t) -> uint8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52125,16 +44261,12 @@ pub fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u16_s32(a: int32x2_t) -> uint16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52150,13 +44282,12 @@ pub fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { +pub fn vreinterpret_u32_s32(a: int32x2_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52172,17 +44303,12 @@ pub fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u64_s32(a: int32x2_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52198,13 +44324,12 @@ pub fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { +pub fn vreinterpret_p8_s32(a: int32x2_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52220,21 +44345,12 @@ pub fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_p16_s32(a: int32x2_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52250,13 +44366,12 @@ pub fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { +pub fn vreinterpretq_f32_s32(a: int32x4_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52272,17 +44387,12 @@ pub fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_s32(a: int32x4_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52298,13 +44408,12 @@ pub fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { +pub fn vreinterpretq_s16_s32(a: int32x4_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52320,17 +44429,12 @@ pub fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s64_s32(a: int32x4_t) -> int64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52346,13 +44450,12 @@ pub fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { +pub fn vreinterpretq_u8_s32(a: int32x4_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52368,17 +44471,12 @@ pub fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u16_s32(a: int32x4_t) -> uint16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52394,13 +44492,12 @@ pub fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { +pub fn vreinterpretq_u32_s32(a: int32x4_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52416,21 +44513,12 @@ pub fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_u64_s32(a: int32x4_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52446,13 +44534,12 @@ pub fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { +pub fn vreinterpretq_p8_s32(a: int32x4_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52468,17 +44555,12 @@ pub fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_s32(a: int32x4_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52494,13 +44576,12 @@ pub fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { +pub fn vreinterpret_f32_s64(a: int64x1_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52516,17 +44597,12 @@ pub fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_s8_s64(a: int64x1_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52542,13 +44618,12 @@ pub fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { +pub fn vreinterpret_s16_s64(a: int64x1_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52564,21 +44639,12 @@ pub fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_s32_s64(a: int64x1_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52594,13 +44660,12 @@ pub fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { +pub fn vreinterpret_u8_s64(a: int64x1_t) -> uint8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52616,17 +44681,12 @@ pub fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u16_s64(a: int64x1_t) -> uint16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52642,13 +44702,12 @@ pub fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { +pub fn vreinterpret_u32_s64(a: int64x1_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52664,17 +44723,12 @@ pub fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_u64_s64(a: int64x1_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52690,13 +44744,12 @@ pub fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { +pub fn vreinterpret_p8_s64(a: int64x1_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52712,17 +44765,12 @@ pub fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p16_s64(a: int64x1_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52738,13 +44786,12 @@ pub fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { +pub fn vreinterpretq_f32_s64(a: int64x2_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52760,17 +44807,12 @@ pub fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_s64(a: int64x2_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52786,13 +44828,12 @@ pub fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { +pub fn vreinterpretq_s16_s64(a: int64x2_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52808,17 +44849,12 @@ pub fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s32_s64(a: int64x2_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52834,13 +44870,12 @@ pub fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { +pub fn vreinterpretq_u8_s64(a: int64x2_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52856,14 +44891,12 @@ pub fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_u16_s64(a: int64x2_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52879,13 +44912,12 @@ pub fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { +pub fn vreinterpretq_u32_s64(a: int64x2_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52901,17 +44933,12 @@ pub fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_u64_s64(a: int64x2_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52927,13 +44954,12 @@ pub fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { +pub fn vreinterpretq_p8_s64(a: int64x2_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_s64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52949,17 +44975,12 @@ pub fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_s64(a: int64x2_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52975,13 +44996,12 @@ pub fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { +pub fn vreinterpret_f32_u8(a: uint8x8_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -52997,17 +45017,12 @@ pub fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s8_u8(a: uint8x8_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53023,13 +45038,12 @@ pub fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { +pub fn vreinterpret_s16_u8(a: uint8x8_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53045,14 +45059,12 @@ pub fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_s32_u8(a: uint8x8_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53068,13 +45080,12 @@ pub fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { +pub fn vreinterpret_s64_u8(a: uint8x8_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53090,17 +45101,12 @@ pub fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u16_u8(a: uint8x8_t) -> uint16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53116,13 +45122,12 @@ pub fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { +pub fn vreinterpret_u32_u8(a: uint8x8_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53138,18 +45143,12 @@ pub fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u64_u8(a: uint8x8_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53165,13 +45164,12 @@ pub fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { +pub fn vreinterpret_p8_u8(a: uint8x8_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53187,22 +45185,12 @@ pub fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_p16_u8(a: uint8x8_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53218,13 +45206,12 @@ pub fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { +pub fn vreinterpretq_f32_u8(a: uint8x16_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53240,18 +45227,12 @@ pub fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_u8(a: uint8x16_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53267,13 +45248,12 @@ pub fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { +pub fn vreinterpretq_s16_u8(a: uint8x16_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53289,18 +45269,12 @@ pub fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s32_u8(a: uint8x16_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53316,13 +45290,12 @@ pub fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { +pub fn vreinterpretq_s64_u8(a: uint8x16_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53338,18 +45311,12 @@ pub fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u16_u8(a: uint8x16_t) -> uint16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53365,13 +45332,12 @@ pub fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { +pub fn vreinterpretq_u32_u8(a: uint8x16_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53387,22 +45353,12 @@ pub fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_u64_u8(a: uint8x16_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53418,13 +45374,12 @@ pub fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { +pub fn vreinterpretq_p8_u8(a: uint8x16_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53440,18 +45395,12 @@ pub fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_u8(a: uint8x16_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53467,13 +45416,12 @@ pub fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { +pub fn vreinterpret_f32_u16(a: uint16x4_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53489,18 +45437,12 @@ pub fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_s8_u16(a: uint16x4_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53516,13 +45458,12 @@ pub fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { +pub fn vreinterpret_s16_u16(a: uint16x4_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53538,18 +45479,12 @@ pub fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s32_u16(a: uint16x4_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53565,13 +45500,12 @@ pub fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { +pub fn vreinterpret_s64_u16(a: uint16x4_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53587,18 +45521,12 @@ pub fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u8_u16(a: uint16x4_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53614,13 +45542,12 @@ pub fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { +pub fn vreinterpret_u32_u16(a: uint16x4_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53636,17 +45563,12 @@ pub fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_u64_u16(a: uint16x4_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53662,13 +45584,12 @@ pub fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { +pub fn vreinterpret_p8_u16(a: uint16x4_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53684,17 +45605,12 @@ pub fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p16_u16(a: uint16x4_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53710,13 +45626,12 @@ pub fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { +pub fn vreinterpretq_f32_u16(a: uint16x8_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53732,17 +45647,12 @@ pub fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_u16(a: uint16x8_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53758,13 +45668,12 @@ pub fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { +pub fn vreinterpretq_s16_u16(a: uint16x8_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53780,17 +45689,12 @@ pub fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s32_u16(a: uint16x8_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53806,13 +45710,12 @@ pub fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { +pub fn vreinterpretq_s64_u16(a: uint16x8_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53828,14 +45731,12 @@ pub fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_u8_u16(a: uint16x8_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53851,13 +45752,12 @@ pub fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { +pub fn vreinterpretq_u32_u16(a: uint16x8_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53873,17 +45773,12 @@ pub fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_u64_u16(a: uint16x8_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53899,13 +45794,12 @@ pub fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { +pub fn vreinterpretq_p8_u16(a: uint16x8_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53921,17 +45815,12 @@ pub fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_u16(a: uint16x8_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53947,13 +45836,12 @@ pub fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { +pub fn vreinterpret_f32_u32(a: uint32x2_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53969,17 +45857,12 @@ pub fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s8_u32(a: uint32x2_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -53995,13 +45878,12 @@ pub fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { +pub fn vreinterpret_s16_u32(a: uint32x2_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54017,14 +45899,12 @@ pub fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpret_s32_u32(a: uint32x2_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54040,13 +45920,12 @@ pub fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { +pub fn vreinterpret_s64_u32(a: uint32x2_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54062,17 +45941,12 @@ pub fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u8_u32(a: uint32x2_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54088,13 +45962,12 @@ pub fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { +pub fn vreinterpret_u16_u32(a: uint32x2_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54110,17 +45983,12 @@ pub fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: float32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_u64_u32(a: uint32x2_t) -> uint64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54136,13 +46004,12 @@ pub fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { +pub fn vreinterpret_p8_u32(a: uint32x2_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54158,21 +46025,12 @@ pub fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_p16_u32(a: uint32x2_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54188,13 +46046,12 @@ pub fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { +pub fn vreinterpretq_f32_u32(a: uint32x4_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54210,17 +46067,12 @@ pub fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_u32(a: uint32x4_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54236,13 +46088,12 @@ pub fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { +pub fn vreinterpretq_s16_u32(a: uint32x4_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54258,17 +46109,12 @@ pub fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s32_u32(a: uint32x4_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54284,13 +46130,12 @@ pub fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { +pub fn vreinterpretq_s64_u32(a: uint32x4_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54306,17 +46151,12 @@ pub fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u8_u32(a: uint32x4_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54332,13 +46172,12 @@ pub fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { +pub fn vreinterpretq_u16_u32(a: uint32x4_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54354,21 +46193,12 @@ pub fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_u64_u32(a: uint32x4_t) -> uint64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54384,13 +46214,12 @@ pub fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { +pub fn vreinterpretq_p8_u32(a: uint32x4_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54406,17 +46235,12 @@ pub fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_u32(a: uint32x4_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54432,13 +46256,12 @@ pub fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { +pub fn vreinterpret_f32_u64(a: uint64x1_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_u64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54454,17 +46277,12 @@ pub fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_s8_u64(a: uint64x1_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54480,13 +46298,12 @@ pub fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { +pub fn vreinterpret_s16_u64(a: uint64x1_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_u64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54502,17 +46319,12 @@ pub fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s32_u64(a: uint64x1_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54528,13 +46340,12 @@ pub fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { +pub fn vreinterpret_s64_u64(a: uint64x1_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_u64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -54550,23 +46361,14 @@ pub fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_u8_u64(a: uint64x1_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54580,15 +46382,14 @@ pub fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { +pub fn vreinterpret_u16_u64(a: uint64x1_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54602,22 +46403,14 @@ pub fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_u32_u64(a: uint64x1_t) -> uint32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54631,15 +46424,14 @@ pub fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { +pub fn vreinterpret_p8_u64(a: uint64x1_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54653,18 +46445,14 @@ pub fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p16_u64(a: uint64x1_t) -> poly16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54678,15 +46466,14 @@ pub fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { +pub fn vreinterpretq_f32_u64(a: uint64x2_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54700,18 +46487,14 @@ pub fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_s8_u64(a: uint64x2_t) -> int8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54725,15 +46508,14 @@ pub fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { +pub fn vreinterpretq_s16_u64(a: uint64x2_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54747,18 +46529,14 @@ pub fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { - unsafe { - let ret_val: int64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s32_u64(a: uint64x2_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54772,15 +46550,14 @@ pub fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { +pub fn vreinterpretq_s64_u64(a: uint64x2_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54794,22 +46571,14 @@ pub fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_u8_u64(a: uint64x2_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54823,15 +46592,14 @@ pub fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { +pub fn vreinterpretq_u16_u64(a: uint64x2_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54845,18 +46613,14 @@ pub fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_u32_u64(a: uint64x2_t) -> uint32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_u64)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54870,15 +46634,14 @@ pub fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { +pub fn vreinterpretq_p8_u64(a: uint64x2_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_u64)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54892,18 +46655,14 @@ pub fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p16_u64(a: uint64x2_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54917,15 +46676,14 @@ pub fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { +pub fn vreinterpret_f32_p8(a: poly8x8_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54939,18 +46697,14 @@ pub fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { - unsafe { - let ret_val: uint64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_s8_p8(a: poly8x8_t) -> int8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54964,15 +46718,14 @@ pub fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { +pub fn vreinterpret_s16_p8(a: poly8x8_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -54986,22 +46739,14 @@ pub fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_s32_p8(a: poly8x8_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55015,15 +46760,14 @@ pub fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { +pub fn vreinterpret_s64_p8(a: poly8x8_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55037,18 +46781,14 @@ pub fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u8_p8(a: poly8x8_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55062,15 +46802,14 @@ pub fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { +pub fn vreinterpret_u16_p8(a: poly8x8_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p128)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55084,18 +46823,14 @@ pub fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_u32_p8(a: poly8x8_t) -> uint32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55109,15 +46844,14 @@ pub fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { +pub fn vreinterpret_u64_p8(a: poly8x8_t) -> uint64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55131,16 +46865,14 @@ pub fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { - let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_p16_p8(a: poly8x8_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55154,15 +46886,14 @@ pub fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { +pub fn vreinterpretq_f32_p8(a: poly8x16_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55176,17 +46907,14 @@ pub fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_s8_p8(a: poly8x16_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55200,15 +46928,14 @@ pub fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { +pub fn vreinterpretq_s16_p8(a: poly8x16_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55222,20 +46949,14 @@ pub fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { - let a: int8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s32_p8(a: poly8x16_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55249,15 +46970,14 @@ pub fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { +pub fn vreinterpretq_s64_p8(a: poly8x16_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55271,16 +46991,14 @@ pub fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { - let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_u8_p8(a: poly8x16_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55294,15 +47012,14 @@ pub fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { +pub fn vreinterpretq_u16_p8(a: poly8x16_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55316,16 +47033,14 @@ pub fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_u32_p8(a: poly8x16_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p8)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55339,15 +47054,14 @@ pub fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { +pub fn vreinterpretq_u64_p8(a: poly8x16_t) -> uint64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p8)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55361,19 +47075,14 @@ pub fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { - let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_p16_p8(a: poly8x16_t) -> poly16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_f32_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55387,15 +47096,14 @@ pub fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { +pub fn vreinterpret_f32_p16(a: poly16x4_t) -> float32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55409,16 +47117,14 @@ pub fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { - let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpret_s8_p16(a: poly16x4_t) -> int8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55432,15 +47138,14 @@ pub fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { +pub fn vreinterpret_s16_p16(a: poly16x4_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55454,16 +47159,14 @@ pub fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpret_s32_p16(a: poly16x4_t) -> int32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s64_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55477,15 +47180,14 @@ pub fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { +pub fn vreinterpret_s64_p16(a: poly16x4_t) -> int64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55499,19 +47201,14 @@ pub fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { - let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_u8_p16(a: poly16x4_t) -> uint8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55525,15 +47222,14 @@ pub fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { +pub fn vreinterpret_u16_p16(a: poly16x4_t) -> uint16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55547,16 +47243,14 @@ pub fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { - let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpret_u32_p16(a: poly16x4_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u64_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55570,15 +47264,14 @@ pub fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { +pub fn vreinterpret_u64_p16(a: poly16x4_t) -> uint64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55592,16 +47285,14 @@ pub fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { - let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_p8_p16(a: poly16x4_t) -> poly8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_f32_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55615,15 +47306,14 @@ pub fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { +pub fn vreinterpretq_f32_p16(a: poly16x8_t) -> float32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55637,17 +47327,14 @@ pub fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_s8_p16(a: poly16x8_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55661,15 +47348,14 @@ pub fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { +pub fn vreinterpretq_s16_p16(a: poly16x8_t) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55683,20 +47369,14 @@ pub fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { - let a: uint8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_s32_p16(a: poly16x8_t) -> int32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55710,15 +47390,14 @@ pub fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { +pub fn vreinterpretq_s64_p16(a: poly16x8_t) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55732,16 +47411,14 @@ pub fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { - let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_u8_p16(a: poly16x8_t) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55755,15 +47432,14 @@ pub fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { +pub fn vreinterpretq_u16_p16(a: poly16x8_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55777,16 +47453,14 @@ pub fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_u32_p16(a: poly16x8_t) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p16)"] #[inline] -#[cfg(target_endian = "little")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55800,15 +47474,14 @@ pub fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { +pub fn vreinterpretq_u64_p16(a: poly16x8_t) -> uint64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p16)"] #[inline] -#[cfg(target_endian = "big")] -#[target_feature(enable = "neon,aes")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[cfg_attr( all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), @@ -55822,17 +47495,12 @@ pub fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { - let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_p8_p16(a: poly16x8_t) -> poly8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55848,13 +47516,12 @@ pub fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { +pub fn vreinterpretq_s8_p128(a: p128) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55870,14 +47537,12 @@ pub fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { - let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpretq_s16_p128(a: p128) -> int16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55893,13 +47558,12 @@ pub fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { +pub fn vreinterpretq_s32_p128(a: p128) -> int32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s64_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55915,14 +47579,12 @@ pub fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_s64_p128(a: p128) -> int64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55938,13 +47600,12 @@ pub fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { +pub fn vreinterpretq_u8_p128(a: p128) -> uint8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u32)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55960,17 +47621,12 @@ pub fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { - let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_u16_p128(a: p128) -> uint16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -55986,13 +47642,12 @@ pub fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { +pub fn vreinterpretq_u32_p128(a: p128) -> uint32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u64_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56008,14 +47663,12 @@ pub fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { - let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpretq_u64_p128(a: p128) -> uint64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56031,13 +47684,12 @@ pub fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { +pub fn vreinterpretq_p8_p128(a: p128) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p128)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56053,14 +47705,12 @@ pub fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { - let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpretq_p16_p128(a: p128) -> poly16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p128)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56076,13 +47726,12 @@ pub fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { +pub fn vreinterpretq_p64_p128(a: p128) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56098,15 +47747,12 @@ pub fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_p64_s8(a: int8x8_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56122,13 +47768,12 @@ pub fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { +pub fn vreinterpretq_p128_s8(a: int8x16_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p8)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56144,18 +47789,12 @@ pub fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { - let a: poly8x16_t = - unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_p64_s8(a: int8x16_t) -> poly64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56171,13 +47810,12 @@ pub fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { +pub fn vreinterpret_p64_s16(a: int16x4_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56193,14 +47831,12 @@ pub fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { - let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; +pub fn vreinterpretq_p128_s16(a: int16x8_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56216,13 +47852,12 @@ pub fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { +pub fn vreinterpretq_p64_s16(a: int16x8_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56238,14 +47873,12 @@ pub fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; +pub fn vreinterpret_p64_s32(a: int32x2_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56261,13 +47894,12 @@ pub fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { +pub fn vreinterpretq_p128_s32(a: int32x4_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p16)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_s32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56283,17 +47915,12 @@ pub fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { - let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; - unsafe { - let ret_val: poly64x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_p64_s32(a: int32x4_t) -> poly64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_s64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56309,13 +47936,12 @@ pub fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { +pub fn vreinterpretq_p128_s64(a: int64x2_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56331,16 +47957,12 @@ pub fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { - unsafe { - let ret_val: int8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p64_u8(a: uint8x8_t) -> poly64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56356,13 +47978,12 @@ pub fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { +pub fn vreinterpretq_p128_u8(a: uint8x16_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56378,16 +47999,12 @@ pub fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { - unsafe { - let ret_val: int16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p64_u8(a: uint8x16_t) -> poly64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56403,13 +48020,12 @@ pub fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { +pub fn vreinterpret_p64_u16(a: uint16x4_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56425,16 +48041,12 @@ pub fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { - unsafe { - let ret_val: int32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpretq_p128_u16(a: uint16x8_t) -> p128 { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56450,13 +48062,12 @@ pub fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { +pub fn vreinterpretq_p64_u16(a: uint16x8_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56472,16 +48083,12 @@ pub fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { - unsafe { - let ret_val: uint8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_p64_u32(a: uint32x2_t) -> poly64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u32)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56497,13 +48104,12 @@ pub fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { +pub fn vreinterpretq_p128_u32(a: uint32x4_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_u32)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56519,16 +48125,12 @@ pub fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { - unsafe { - let ret_val: uint16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p64_u32(a: uint32x4_t) -> poly64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_u64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56544,13 +48146,12 @@ pub fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { +pub fn vreinterpretq_p128_u64(a: uint64x2_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56566,16 +48167,12 @@ pub fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { - unsafe { - let ret_val: uint32x2_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [1, 0]) - } +pub fn vreinterpret_p64_p8(a: poly8x8_t) -> poly64x1_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p8)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56591,13 +48188,12 @@ pub fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { +pub fn vreinterpretq_p128_p8(a: poly8x16_t) -> p128 { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p8)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56613,16 +48209,12 @@ pub fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { - unsafe { - let ret_val: poly8x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_p64_p8(a: poly8x16_t) -> poly64x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p64_p16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56638,13 +48230,12 @@ pub fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { +pub fn vreinterpret_p64_p16(a: poly16x4_t) -> poly64x1_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p16)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56660,16 +48251,12 @@ pub fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { - unsafe { - let ret_val: poly16x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_p128_p16(a: poly16x8_t) -> p128 { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p64_p16)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56685,13 +48272,12 @@ pub fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { +pub fn vreinterpretq_p64_p16(a: poly16x8_t) -> poly64x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s8_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56707,14 +48293,12 @@ pub fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; +pub fn vreinterpret_s8_p64(a: poly64x1_t) -> int8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s16_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56730,13 +48314,12 @@ pub fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { +pub fn vreinterpret_s16_p64(a: poly64x1_t) -> int16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_s32_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56752,21 +48335,12 @@ pub fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpret_s32_p64(a: poly64x1_t) -> int32x2_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u8_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56782,13 +48356,12 @@ pub fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { +pub fn vreinterpret_u8_p64(a: poly64x1_t) -> uint8x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u16_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56804,17 +48377,12 @@ pub fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpret_u16_p64(a: poly64x1_t) -> uint16x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_u32_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56830,13 +48398,12 @@ pub fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { +pub fn vreinterpret_u32_p64(a: poly64x1_t) -> uint32x2_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p8_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56852,17 +48419,12 @@ pub fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: int32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpret_p8_p64(a: poly64x1_t) -> poly8x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpret_p16_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56878,13 +48440,12 @@ pub fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { +pub fn vreinterpret_p16_p64(a: poly64x1_t) -> poly16x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p128_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56900,21 +48461,12 @@ pub fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_p128_p64(a: poly64x2_t) -> p128 { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s8_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56930,13 +48482,12 @@ pub fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { +pub fn vreinterpretq_s8_p64(a: poly64x2_t) -> int8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s16_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56952,17 +48503,12 @@ pub fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } +pub fn vreinterpretq_s16_p64(a: poly64x2_t) -> int16x8_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_s32_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -56978,13 +48524,12 @@ pub fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { +pub fn vreinterpretq_s32_p64(a: poly64x2_t) -> int32x4_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u8_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -57000,17 +48545,12 @@ pub fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: uint32x4_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [3, 2, 1, 0]) - } +pub fn vreinterpretq_u8_p64(a: poly64x2_t) -> uint8x16_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u16_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -57026,13 +48566,12 @@ pub fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { +pub fn vreinterpretq_u16_p64(a: poly64x2_t) -> uint16x8_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_u32_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -57048,21 +48587,12 @@ pub fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly8x16_t = transmute(a); - simd_shuffle!( - ret_val, - ret_val, - [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - ) - } +pub fn vreinterpretq_u32_p64(a: poly64x2_t) -> uint32x4_t { + unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p64)"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p8_p64)"] #[inline] -#[cfg(target_endian = "little")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -57078,13 +48608,12 @@ pub fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] -pub fn vreinterpretq_p16_p64(a: poly64x2_t) -> poly16x8_t { +pub fn vreinterpretq_p8_p64(a: poly64x2_t) -> poly8x16_t { unsafe { transmute(a) } } #[doc = "Vector reinterpret cast operation"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vreinterpretq_p16_p64)"] #[inline] -#[cfg(target_endian = "big")] #[target_feature(enable = "neon,aes")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] @@ -57101,11 +48630,7 @@ pub fn vreinterpretq_p16_p64(a: poly64x2_t) -> poly16x8_t { unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800") )] pub fn vreinterpretq_p16_p64(a: poly64x2_t) -> poly16x8_t { - let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; - unsafe { - let ret_val: poly16x8_t = transmute(a); - simd_shuffle!(ret_val, ret_val, [7, 6, 5, 4, 3, 2, 1, 0]) - } + unsafe { transmute(a) } } #[doc = "Reversing vector elements (swap endianness)"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrev16_p8)"] diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml index a1a837bc61064..ccdcea980e1b2 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml @@ -8781,6 +8781,7 @@ intrinsics: - [float64x1_t, float32x2_t] - [float32x4_t, float64x2_t] - [float64x2_t, float32x4_t] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] @@ -8801,6 +8802,7 @@ intrinsics: # q - [float64x2_t, float16x8_t] - [float16x8_t, float64x2_t] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml index 43dd3b9031507..61a3a5853632c 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml @@ -8480,6 +8480,7 @@ intrinsics: - [poly16x8_t, p128] - [int8x16_t, p128] - [uint8x16_t, p128] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] @@ -8717,6 +8718,7 @@ intrinsics: - [poly8x16_t, float32x4_t] - [poly16x8_t, float32x4_t] - [p128, float32x4_t] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] @@ -8780,6 +8782,7 @@ intrinsics: - [float16x8_t, uint16x8_t] - [float16x8_t, uint32x4_t] - [float16x8_t, uint64x2_t] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] @@ -8804,6 +8807,7 @@ intrinsics: - [poly128_t, float16x8_t] - [float16x8_t, poly128_t] - [float16x8_t, poly64x2_t] + big_endian_inverse: false compose: - FnCall: [transmute, [a]] From 44edbc6d54e0bd3f9eea882ed5cd7646d6b79523 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 12 Sep 2025 04:52:27 +0000 Subject: [PATCH 200/251] Prepare for merging from rust-lang/rust This updates the rust-version file to 2a9bacf6187685931d52346a0ecff2e52bdc91cc. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b71a0d219d778..b3f8a26875f40 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f4665ab8368ad2e8a86d4390ae35c28bdd9561bb +2a9bacf6187685931d52346a0ecff2e52bdc91cc From 8b5335cbba6f68b1e3727e1de6095d2e126f08e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Sep 2025 13:34:22 +0200 Subject: [PATCH 201/251] disable broken parts of CI for now --- src/tools/miri/.github/workflows/ci.yml | 33 +++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index c0fed96d4e6e3..e1a948c92faa4 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -31,21 +31,22 @@ jobs: os: ubuntu-24.04-arm multiarch: armhf gcc_cross: arm-linux-gnueabihf - - host_target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest - multiarch: riscv64 - gcc_cross: riscv64-linux-gnu - qemu: true - - host_target: s390x-unknown-linux-gnu - os: ubuntu-latest - multiarch: s390x - gcc_cross: s390x-linux-gnu - qemu: true - - host_target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest - multiarch: ppc64el - gcc_cross: powerpc64le-linux-gnu - qemu: true + # Disabled due to Ubuntu repo trouble + # - host_target: riscv64gc-unknown-linux-gnu + # os: ubuntu-latest + # multiarch: riscv64 + # gcc_cross: riscv64-linux-gnu + # qemu: true + # - host_target: s390x-unknown-linux-gnu + # os: ubuntu-latest + # multiarch: s390x + # gcc_cross: s390x-linux-gnu + # qemu: true + # - host_target: powerpc64le-unknown-linux-gnu + # os: ubuntu-latest + # multiarch: ppc64el + # gcc_cross: powerpc64le-linux-gnu + # qemu: true - host_target: aarch64-apple-darwin os: macos-latest - host_target: i686-pc-windows-msvc @@ -67,7 +68,7 @@ jobs: - name: install multiarch if: ${{ matrix.multiarch != '' }} run: | - # s390x, ppc64el need Ubuntu Ports to be in the mirror list + # s390x, ppc64el, riscv64 need Ubuntu Ports to be in the mirror list sudo bash -c "echo 'https://ports.ubuntu.com/ priority:4' >> /etc/apt/apt-mirrors.txt" # Add architecture sudo dpkg --add-architecture ${{ matrix.multiarch }} From 221eb1f0d51a97ec6ccb67427635370797d37225 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Fri, 12 Sep 2025 11:50:25 +0000 Subject: [PATCH 202/251] intrinsic-test: Make Clippy happy --- library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs | 2 +- library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs index b019abab21346..65c179ef0d083 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs @@ -113,7 +113,7 @@ fn json_to_intrinsic( Ok(Intrinsic { name, arguments, - results: results, + results, arch_tags: intr.architectures, }) } diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs index 312cbee692a56..c6b964a9ce4e4 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs @@ -253,7 +253,7 @@ pub fn generate_rust_test_loop( } /// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic. -fn generate_rust_specializations<'a>( +fn generate_rust_specializations( constraints: &mut impl Iterator>, ) -> Vec> { let mut specializations = vec![vec![]]; From a3b7aad20f6ff2a4af0e96c543ac300650c97d5e Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Fri, 12 Sep 2025 11:50:51 +0000 Subject: [PATCH 203/251] stdarch-gen-arm: Make Clippy happy --- library/stdarch/crates/stdarch-gen-arm/src/load_store_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/crates/stdarch-gen-arm/src/load_store_tests.rs b/library/stdarch/crates/stdarch-gen-arm/src/load_store_tests.rs index 3f3bfed132c76..0f4de83dacb4a 100644 --- a/library/stdarch/crates/stdarch-gen-arm/src/load_store_tests.rs +++ b/library/stdarch/crates/stdarch-gen-arm/src/load_store_tests.rs @@ -85,7 +85,7 @@ pub fn generate_load_store_tests( TokenStream::from_str(&PREAMBLE).map_err(|e| format!("Preamble is invalid: {e}"))?; // Only output manual tests for the SVE set let manual_tests = match &load_intrinsics[0].target_features[..] { - [s] if s == "sve" => TokenStream::from_str(&MANUAL_TESTS) + [s] if s == "sve" => TokenStream::from_str(MANUAL_TESTS) .map_err(|e| format!("Manual tests are invalid: {e}"))?, _ => quote!(), }; From 05133f2115940aa581df8831031ea77c2c7c99c8 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Fri, 12 Sep 2025 11:51:38 +0000 Subject: [PATCH 204/251] examples: Make Clippy happy --- library/stdarch/examples/hex.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/stdarch/examples/hex.rs b/library/stdarch/examples/hex.rs index 95ffbaf666cea..621f55bc0951f 100644 --- a/library/stdarch/examples/hex.rs +++ b/library/stdarch/examples/hex.rs @@ -22,7 +22,6 @@ #![allow( clippy::unwrap_used, clippy::print_stdout, - clippy::unwrap_used, clippy::shadow_reuse, clippy::cast_possible_wrap, clippy::cast_ptr_alignment, From 8a574ca862493b1977749e1a6e3fb85b9356fad7 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 12 Sep 2025 20:07:07 +0800 Subject: [PATCH 205/251] Fix extra semicolon before else in let-stmt Example --- ```rust fn main() { let x = if true { () } $0 else {}; } ``` **Before this PR**: ```rust fn main() { let x = if true { () } else if $1 { $0 }; else {}; } ``` **After this PR**: ```rust fn main() { let x = if true { () } else if $1 { $0 } else {}; } ``` --- .../ide-completion/src/completions/keyword.rs | 40 +++++++++++++++++++ .../ide-completion/src/context/analysis.rs | 12 +++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index b3d770997ab0c..6162d98372839 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -269,6 +269,46 @@ fn main() { "#, ); + check_edit( + "else if", + r#" +fn main() { + let x = if true { + () + } $0 else {}; +} +"#, + r#" +fn main() { + let x = if true { + () + } else if $1 { + $0 +} else {}; +} +"#, + ); + + check_edit( + "else if", + r#" +fn main() { + let x = if true { + () + } $0 else if true {}; +} +"#, + r#" +fn main() { + let x = if true { + () + } else if $1 { + $0 +} else if true {}; +} +"#, + ); + check_edit( "else", r#" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 33b98a33cabf6..b33a547dee972 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -970,6 +970,16 @@ fn classify_name_ref<'db>( let after_incomplete_let = |node: SyntaxNode| { prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast) }; + let before_else_kw = |node: &SyntaxNode| { + node.parent() + .and_then(ast::ExprStmt::cast) + .filter(|stmt| stmt.semicolon_token().is_none()) + .and_then(|stmt| non_trivia_sibling(stmt.syntax().clone().into(), Direction::Next)) + .and_then(NodeOrToken::into_node) + .filter(|next| next.kind() == SyntaxKind::ERROR) + .and_then(|next| next.first_token()) + .is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW) + }; // We do not want to generate path completions when we are sandwiched between an item decl signature and its body. // ex. trait Foo $0 {} @@ -1276,7 +1286,7 @@ fn classify_name_ref<'db>( .parent() .and_then(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()) - || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true); + || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it); let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); From 225e8ff17b593c7621f639c7cd50de2d93c7aee0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Sep 2025 16:30:41 +0200 Subject: [PATCH 206/251] move _Unwind_RaiseException out of the frame_in_std section --- .../miri/src/shims/windows/foreign_items.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 7b13f1d908073..c3ca01bbf3403 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -820,6 +820,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int(length.strict_sub(1), dest)?; } + "_Unwind_RaiseException" => { + // This is not formally part of POSIX, but it is very wide-spread on POSIX systems. + // It was originally specified as part of the Itanium C++ ABI: + // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw. + // MinGW implements _Unwind_RaiseException on top of SEH exceptions. + if this.tcx.sess.target.env != "gnu" { + throw_unsup_format!( + "`_Unwind_RaiseException` is not supported on non-MinGW Windows", + ); + } + // This function looks and behaves excatly like miri_start_unwind. + let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.handle_miri_start_unwind(payload)?; + return interp_ok(EmulateItemResult::NeedsUnwind); + } + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { @@ -880,22 +896,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - "_Unwind_RaiseException" => { - // This is not formally part of POSIX, but it is very wide-spread on POSIX systems. - // It was originally specified as part of the Itanium C++ ABI: - // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw. - // MinGW implements _Unwind_RaiseException on top of SEH exceptions. - if this.tcx.sess.target.env != "gnu" { - throw_unsup_format!( - "`_Unwind_RaiseException` is not supported on non-MinGW Windows", - ); - } - // This function looks and behaves excatly like miri_start_unwind. - let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - this.handle_miri_start_unwind(payload)?; - return interp_ok(EmulateItemResult::NeedsUnwind); - } - _ => return interp_ok(EmulateItemResult::NotSupported), } From 260dd6f7ea7dec25c98ef6299bf1730c7dcf40b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Sep 2025 17:04:59 +0200 Subject: [PATCH 207/251] make a basic hello world work on wasip2 --- src/tools/miri/README.md | 2 +- src/tools/miri/ci/ci.sh | 2 +- .../miri/src/shims/wasi/foreign_items.rs | 68 +++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 517aa343a6d4d..7094231b902f3 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -220,7 +220,7 @@ degree documented below): - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. + - `wasi`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 6356e33f61e84..bcc110f648b9b 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -153,7 +153,7 @@ case $HOST_TARGET in BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd - TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm + TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC hello wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std ;; diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index bfcdbd8130d84..ffc02dc986f9a 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -35,6 +35,74 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(res, dest)?; } + // Standard input/output + // FIXME: These shims are hacks that just get basic stdout/stderr working. We can't + // constrain them to "std" since std itself uses the wasi crate for this. + "get-stdout" => { + let [] = + this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?; + this.write_scalar(Scalar::from_i32(1), dest)?; // POSIX FD number for stdout + } + "get-stderr" => { + let [] = + this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?; + this.write_scalar(Scalar::from_i32(2), dest)?; // POSIX FD number for stderr + } + "[resource-drop]output-stream" => { + let [handle] = + this.check_shim_sig(shim_sig!(extern "C" fn(i32) -> ()), link_name, abi, args)?; + let handle = this.read_scalar(handle)?.to_i32()?; + + if !(handle == 1 || handle == 2) { + throw_unsup_format!("wasm output-stream: unsupported handle"); + } + // We don't actually close these FDs, so this is a NOP. + } + "[method]output-stream.blocking-write-and-flush" => { + let [handle, buf, len, ret_area] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, usize, *mut _) -> ()), + link_name, + abi, + args, + )?; + let handle = this.read_scalar(handle)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let len = this.read_target_usize(len)?; + let ret_area = this.read_pointer(ret_area)?; + + if len > 4096 { + throw_unsup_format!( + "wasm output-stream.blocking-write-and-flush: buffer too big" + ); + } + let len = usize::try_from(len).unwrap(); + let Some(fd) = this.machine.fds.get(handle) else { + throw_unsup_format!( + "wasm output-stream.blocking-write-and-flush: unsupported handle" + ); + }; + fd.write( + this.machine.communicate(), + buf, + len, + this, + callback!( + @capture<'tcx> { + len: usize, + ret_area: Pointer, + } + |this, result: Result| { + if !matches!(result, Ok(l) if l == len) { + throw_unsup_format!("wasm output-stream.blocking-write-and-flush: returning errors is not supported"); + } + // 0 in the first byte of the ret_area indicates success. + let ret = this.ptr_to_mplace(ret_area, this.machine.layouts.u8); + this.write_null(&ret)?; + interp_ok(()) + }), + )?; + } + _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) From a70d78a55286a85cf5e06958929f5a6071fa1c67 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 14 Mar 2025 09:58:46 +0100 Subject: [PATCH 208/251] Implement more features for GenMC mode - Handling Compare-Exchange operations. - Limitation: Compare-Exchange currently ignores possibility of spurious failures. - Limitation: Compare-Exchange failure memory ordering is ignored. - Upgrade compare-exchange success ordering to avoid reporting non-existent bugs. - Add warnings for GenMC mode for unsupported features. - Add a lot of tests, including translation of GenMC litmus tests and Loom tests. - Cleanup --- .../genmc-sys/cpp/include/MiriInterface.hpp | 82 +++++++++---- .../cpp/src/MiriInterface/EventHandling.cpp | 65 +++++++++++ .../genmc-sys/cpp/src/MiriInterface/Setup.cpp | 8 +- src/tools/miri/genmc-sys/src/lib.rs | 25 ++++ .../miri/src/concurrency/genmc/helper.rs | 82 ++++++++++++- src/tools/miri/src/concurrency/genmc/mod.rs | 109 +++++++++++++++--- src/tools/miri/src/concurrency/genmc/run.rs | 4 +- src/tools/miri/src/diagnostics.rs | 26 +++++ .../genmc/fail/data_race/mpu2_rels_rlx.rs | 45 ++++++++ .../genmc/fail/data_race/mpu2_rels_rlx.stderr | 19 +++ .../fail/loom/store_buffering.genmc.stderr | 13 +++ .../loom/store_buffering.non_genmc.stderr | 13 +++ .../tests/genmc/fail/loom/store_buffering.rs | 57 +++++++++ .../atomics/cas_failure_ord_racy_key_init.rs | 70 +++++++++++ .../cas_failure_ord_racy_key_init.stderr | 22 ++++ .../tests/genmc/pass/atomics/cas_simple.rs | 34 ++++++ .../genmc/pass/atomics/cas_simple.stderr | 2 + .../miri/tests/genmc/pass/litmus/IRIWish.rs | 4 +- .../tests/genmc/pass/litmus/MPU2_rels_acqf.rs | 67 +++++++++++ .../genmc/pass/litmus/MPU2_rels_acqf.stderr | 38 ++++++ .../miri/tests/genmc/pass/litmus/Z6_U.rs | 7 +- .../miri/tests/genmc/pass/litmus/casdep.rs | 37 ++++++ .../tests/genmc/pass/litmus/casdep.stderr | 2 + src/tools/miri/tests/genmc/pass/litmus/ccr.rs | 34 ++++++ .../miri/tests/genmc/pass/litmus/ccr.stderr | 2 + src/tools/miri/tests/genmc/pass/litmus/cii.rs | 35 ++++++ .../miri/tests/genmc/pass/litmus/cii.stderr | 2 + 27 files changed, 850 insertions(+), 54 deletions(-) create mode 100644 src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.rs create mode 100644 src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr create mode 100644 src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr create mode 100644 src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr create mode 100644 src/tools/miri/tests/genmc/fail/loom/store_buffering.rs create mode 100644 src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs create mode 100644 src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr create mode 100644 src/tools/miri/tests/genmc/pass/atomics/cas_simple.rs create mode 100644 src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/casdep.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/casdep.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/ccr.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/ccr.stderr create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cii.rs create mode 100644 src/tools/miri/tests/genmc/pass/litmus/cii.stderr diff --git a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp index b076937584326..662eb0e173ca8 100644 --- a/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp +++ b/src/tools/miri/genmc-sys/cpp/include/MiriInterface.hpp @@ -34,6 +34,7 @@ struct SchedulingResult; struct LoadResult; struct StoreResult; struct ReadModifyWriteResult; +struct CompareExchangeResult; // GenMC uses `int` for its thread IDs. using ThreadId = int; @@ -100,6 +101,17 @@ struct MiriGenmcShim : private GenMCDriver { GenmcScalar rhs_value, GenmcScalar old_val ); + [[nodiscard]] CompareExchangeResult handle_compare_exchange( + ThreadId thread_id, + uint64_t address, + uint64_t size, + GenmcScalar expected_value, + GenmcScalar new_value, + GenmcScalar old_val, + MemOrdering success_ordering, + MemOrdering fail_load_ordering, + bool can_fail_spuriously + ); [[nodiscard]] StoreResult handle_store( ThreadId thread_id, uint64_t address, @@ -231,15 +243,15 @@ constexpr auto get_global_alloc_static_mask() -> uint64_t { namespace GenmcScalarExt { inline GenmcScalar uninit() { return GenmcScalar { - /* value: */ 0, - /* is_init: */ false, + .value = 0, + .is_init = false, }; } inline GenmcScalar from_sval(SVal sval) { return GenmcScalar { - /* value: */ sval.get(), - /* is_init: */ true, + .value = sval.get(), + .is_init = true, }; } @@ -252,22 +264,22 @@ inline SVal to_sval(GenmcScalar scalar) { namespace LoadResultExt { inline LoadResult no_value() { return LoadResult { - /* error: */ std::unique_ptr(nullptr), - /* has_value: */ false, - /* read_value: */ GenmcScalarExt::uninit(), + .error = std::unique_ptr(nullptr), + .has_value = false, + .read_value = GenmcScalarExt::uninit(), }; } inline LoadResult from_value(SVal read_value) { - return LoadResult { /* error: */ std::unique_ptr(nullptr), - /* has_value: */ true, - /* read_value: */ GenmcScalarExt::from_sval(read_value) }; + return LoadResult { .error = std::unique_ptr(nullptr), + .has_value = true, + .read_value = GenmcScalarExt::from_sval(read_value) }; } inline LoadResult from_error(std::unique_ptr error) { - return LoadResult { /* error: */ std::move(error), - /* has_value: */ false, - /* read_value: */ GenmcScalarExt::uninit() }; + return LoadResult { .error = std::move(error), + .has_value = false, + .read_value = GenmcScalarExt::uninit() }; } } // namespace LoadResultExt @@ -278,26 +290,50 @@ inline StoreResult ok(bool is_coherence_order_maximal_write) { } inline StoreResult from_error(std::unique_ptr error) { - return StoreResult { /* error: */ std::move(error), - /* is_coherence_order_maximal_write: */ false }; + return StoreResult { .error = std::move(error), .is_coherence_order_maximal_write = false }; } } // namespace StoreResultExt namespace ReadModifyWriteResultExt { inline ReadModifyWriteResult ok(SVal old_value, SVal new_value, bool is_coherence_order_maximal_write) { - return ReadModifyWriteResult { /* error: */ std::unique_ptr(nullptr), - /* old_value: */ GenmcScalarExt::from_sval(old_value), - /* new_value: */ GenmcScalarExt::from_sval(new_value), - is_coherence_order_maximal_write }; + return ReadModifyWriteResult { .error = std::unique_ptr(nullptr), + .old_value = GenmcScalarExt::from_sval(old_value), + .new_value = GenmcScalarExt::from_sval(new_value), + .is_coherence_order_maximal_write = + is_coherence_order_maximal_write }; } inline ReadModifyWriteResult from_error(std::unique_ptr error) { - return ReadModifyWriteResult { /* error: */ std::move(error), - /* old_value: */ GenmcScalarExt::uninit(), - /* new_value: */ GenmcScalarExt::uninit(), - /* is_coherence_order_maximal_write: */ false }; + return ReadModifyWriteResult { .error = std::move(error), + .old_value = GenmcScalarExt::uninit(), + .new_value = GenmcScalarExt::uninit(), + .is_coherence_order_maximal_write = false }; } } // namespace ReadModifyWriteResultExt +namespace CompareExchangeResultExt { +inline CompareExchangeResult success(SVal old_value, bool is_coherence_order_maximal_write) { + return CompareExchangeResult { .error = nullptr, + .old_value = GenmcScalarExt::from_sval(old_value), + .is_success = true, + .is_coherence_order_maximal_write = + is_coherence_order_maximal_write }; +} + +inline CompareExchangeResult failure(SVal old_value) { + return CompareExchangeResult { .error = nullptr, + .old_value = GenmcScalarExt::from_sval(old_value), + .is_success = false, + .is_coherence_order_maximal_write = false }; +} + +inline CompareExchangeResult from_error(std::unique_ptr error) { + return CompareExchangeResult { .error = std::move(error), + .old_value = GenmcScalarExt::uninit(), + .is_success = false, + .is_coherence_order_maximal_write = false }; +} +} // namespace CompareExchangeResultExt + #endif /* GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp index cd28e0d148f58..05c82641df948 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/EventHandling.cpp @@ -155,6 +155,71 @@ void MiriGenmcShim::handle_fence(ThreadId thread_id, MemOrdering ord) { ); } +[[nodiscard]] auto MiriGenmcShim::handle_compare_exchange( + ThreadId thread_id, + uint64_t address, + uint64_t size, + GenmcScalar expected_value, + GenmcScalar new_value, + GenmcScalar old_val, + MemOrdering success_ordering, + MemOrdering fail_load_ordering, + bool can_fail_spuriously +) -> CompareExchangeResult { + // NOTE: Both the store and load events should get the same `ordering`, it should not be split + // into a load and a store component. This means we can have for example `AcqRel` loads and + // stores, but this is intended for CAS operations. + + // FIXME(GenMC): properly handle failure memory ordering. + + auto expectedVal = GenmcScalarExt::to_sval(expected_value); + auto new_val = GenmcScalarExt::to_sval(new_value); + + const auto load_ret = handle_load_reset_if_none( + thread_id, + success_ordering, + SAddr(address), + ASize(size), + AType::Unsigned, // The type is only used for printing. + expectedVal, + new_val + ); + if (const auto* err = std::get_if(&load_ret)) + return CompareExchangeResultExt::from_error(format_error(*err)); + const auto* ret_val = std::get_if(&load_ret); + ERROR_ON(nullptr == ret_val, "Unimplemented: load returned unexpected result."); + const auto read_old_val = *ret_val; + if (read_old_val != expectedVal) + return CompareExchangeResultExt::failure(read_old_val); + + // FIXME(GenMC): Add support for modelling spurious failures. + + const auto storePos = inc_pos(thread_id); + const auto store_ret = GenMCDriver::handleStore( + storePos, + success_ordering, + SAddr(address), + ASize(size), + AType::Unsigned, // The type is only used for printing. + new_val + ); + if (const auto* err = std::get_if(&store_ret)) + return CompareExchangeResultExt::from_error(format_error(*err)); + const auto* store_ret_val = std::get_if(&store_ret); + ERROR_ON( + nullptr == store_ret_val, + "Unimplemented: compare-exchange store returned unexpected result." + ); + + // FIXME(genmc,mixed-accesses): Use the value that GenMC returns from handleStore (once + // available). + const auto& g = getExec().getGraph(); + return CompareExchangeResultExt::success( + read_old_val, + /* is_coherence_order_maximal_write */ g.co_max(SAddr(address))->getPos() == storePos + ); +} + /**** Memory (de)allocation ****/ auto MiriGenmcShim::handle_malloc(ThreadId thread_id, uint64_t size, uint64_t alignment) diff --git a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp index 5a53fee059216..a17a83aa06e13 100644 --- a/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp +++ b/src/tools/miri/genmc-sys/cpp/src/MiriInterface/Setup.cpp @@ -152,10 +152,10 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel // Miri already ensures that memory accesses are valid, so this check doesn't matter. // We check that the address is static, but skip checking if it is part of an actual // allocation. - /* isStaticallyAllocated: */ [](SAddr addr) { return addr.isStatic(); }, + .isStaticallyAllocated = [](SAddr addr) { return addr.isStatic(); }, // FIXME(genmc,error reporting): Once a proper a proper API for passing such information is // implemented in GenMC, Miri should use it to improve the produced error messages. - /* getStaticName: */ [](SAddr addr) { return "[UNKNOWN STATIC]"; }, + .getStaticName = [](SAddr addr) { return "[UNKNOWN STATIC]"; }, // This function is called to get the initial value stored at the given address. // // From a Miri perspective, this API doesn't work very well: most memory starts out @@ -177,10 +177,10 @@ static auto to_genmc_verbosity_level(const LogLevel log_level) -> VerbosityLevel // FIXME(genmc): implement proper support for uninitialized memory in GenMC. Ideally, the // initial value getter would return an `optional`, since the memory location may be // uninitialized. - /* initValGetter: */ [](const AAccess& a) { return SVal(0xDEAD); }, + .initValGetter = [](const AAccess& a) { return SVal(0xDEAD); }, // Miri serves non-atomic loads from its own memory and these GenMC checks are wrong in // that case. This should no longer be required with proper mixed-size access support. - /* skipUninitLoadChecks: */ [](MemOrdering ord) { return ord == MemOrdering::NotAtomic; }, + .skipUninitLoadChecks = [](MemOrdering ord) { return ord == MemOrdering::NotAtomic; }, }; driver->setInterpCallbacks(std::move(interpreter_callbacks)); diff --git a/src/tools/miri/genmc-sys/src/lib.rs b/src/tools/miri/genmc-sys/src/lib.rs index 1de4c4eb5e8e9..31bc2606adc01 100644 --- a/src/tools/miri/genmc-sys/src/lib.rs +++ b/src/tools/miri/genmc-sys/src/lib.rs @@ -198,6 +198,19 @@ mod ffi { is_coherence_order_maximal_write: bool, } + #[must_use] + #[derive(Debug)] + struct CompareExchangeResult { + /// If there was an error, it will be stored in `error`, otherwise it is `None`. + error: UniquePtr, + /// The value that was read by the compare-exchange. + old_value: GenmcScalar, + /// `true` if compare_exchange op was successful. + is_success: bool, + /// `true` if the write should also be reflected in Miri's memory representation. + is_coherence_order_maximal_write: bool, + } + /**** These are GenMC types that we have to copy-paste here since cxx does not support "importing" externally defined C++ types. ****/ @@ -313,6 +326,18 @@ mod ffi { rhs_value: GenmcScalar, old_value: GenmcScalar, ) -> ReadModifyWriteResult; + fn handle_compare_exchange( + self: Pin<&mut MiriGenmcShim>, + thread_id: i32, + address: u64, + size: u64, + expected_value: GenmcScalar, + new_value: GenmcScalar, + old_value: GenmcScalar, + success_ordering: MemOrdering, + fail_load_ordering: MemOrdering, + can_fail_spuriously: bool, + ) -> CompareExchangeResult; fn handle_store( self: Pin<&mut MiriGenmcShim>, thread_id: i32, diff --git a/src/tools/miri/src/concurrency/genmc/helper.rs b/src/tools/miri/src/concurrency/genmc/helper.rs index 2a84ca2036676..48a5ec8bb2608 100644 --- a/src/tools/miri/src/concurrency/genmc/helper.rs +++ b/src/tools/miri/src/concurrency/genmc/helper.rs @@ -1,20 +1,52 @@ +use std::sync::RwLock; + use genmc_sys::{MemOrdering, RMWBinOp}; use rustc_abi::Size; use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::ty::ScalarInt; +use rustc_span::Span; use tracing::debug; use super::GenmcScalar; +use crate::diagnostics::EvalContextExt; use crate::intrinsics::AtomicRmwOp; use crate::{ - AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MiriInterpCx, Scalar, - throw_unsup_format, + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, InterpCx, MiriInterpCx, + MiriMachine, NonHaltingDiagnostic, Scalar, throw_unsup_format, }; /// Maximum size memory access in bytes that GenMC supports. pub(super) const MAX_ACCESS_SIZE: u64 = 8; +/// Type for storing spans for already emitted warnings. +pub(super) type WarningCache = RwLock>; + +#[derive(Default)] +pub(super) struct Warnings { + pub(super) compare_exchange_failure_ordering: WarningCache, + pub(super) compare_exchange_weak: WarningCache, +} + +/// Emit a warning if it hasn't already been reported for current span. +pub(super) fn emit_warning<'tcx>( + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + cache: &WarningCache, + diagnostic: impl FnOnce() -> NonHaltingDiagnostic, +) { + let span = ecx.machine.current_span(); + if cache.read().unwrap().contains(&span) { + return; + } + // This span has not yet been reported, so we insert it into the cache and report it. + let mut cache = cache.write().unwrap(); + if cache.insert(span) { + // Some other thread may have added this span while we didn't hold the lock, so we only emit it if the insertions succeeded. + ecx.emit_diagnostic(diagnostic()); + } +} + /// This function is used to split up a large memory access into aligned, non-overlapping chunks of a limited size. /// Returns an iterator over the chunks, yielding `(base address, size)` of each chunk, ordered by address. pub fn split_access(address: Size, size: Size) -> impl Iterator { @@ -112,7 +144,53 @@ impl AtomicFenceOrd { } } +/// Since GenMC ignores the failure memory ordering and Miri should not detect bugs that don't actually exist, we upgrade the success ordering if required. +/// This means that Miri running in GenMC mode will not explore all possible executions allowed under the RC11 memory model. +/// FIXME(genmc): remove this once GenMC properly supports the failure memory ordering. +pub(super) fn maybe_upgrade_compare_exchange_success_orderings( + success: AtomicRwOrd, + failure: AtomicReadOrd, +) -> AtomicRwOrd { + use AtomicReadOrd::*; + let (success_read, success_write) = success.split_memory_orderings(); + let upgraded_success_read = match (success_read, failure) { + (_, SeqCst) | (SeqCst, _) => SeqCst, + (Acquire, _) | (_, Acquire) => Acquire, + (Relaxed, Relaxed) => Relaxed, + }; + AtomicRwOrd::from_split_memory_orderings(upgraded_success_read, success_write) +} + impl AtomicRwOrd { + /// Split up an atomic read-write memory ordering into a separate read and write ordering. + pub(super) fn split_memory_orderings(self) -> (AtomicReadOrd, AtomicWriteOrd) { + match self { + AtomicRwOrd::Relaxed => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Relaxed), + AtomicRwOrd::Acquire => (AtomicReadOrd::Acquire, AtomicWriteOrd::Relaxed), + AtomicRwOrd::Release => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Release), + AtomicRwOrd::AcqRel => (AtomicReadOrd::Acquire, AtomicWriteOrd::Release), + AtomicRwOrd::SeqCst => (AtomicReadOrd::SeqCst, AtomicWriteOrd::SeqCst), + } + } + + /// Split up an atomic read-write memory ordering into a separate read and write ordering. + fn from_split_memory_orderings( + read_ordering: AtomicReadOrd, + write_ordering: AtomicWriteOrd, + ) -> Self { + match (read_ordering, write_ordering) { + (AtomicReadOrd::Relaxed, AtomicWriteOrd::Relaxed) => AtomicRwOrd::Relaxed, + (AtomicReadOrd::Acquire, AtomicWriteOrd::Relaxed) => AtomicRwOrd::Acquire, + (AtomicReadOrd::Relaxed, AtomicWriteOrd::Release) => AtomicRwOrd::Release, + (AtomicReadOrd::Acquire, AtomicWriteOrd::Release) => AtomicRwOrd::AcqRel, + (AtomicReadOrd::SeqCst, AtomicWriteOrd::SeqCst) => AtomicRwOrd::SeqCst, + _ => + panic!( + "Unsupported memory ordering combination ({read_ordering:?}, {write_ordering:?})" + ), + } + } + pub(super) fn to_genmc(self) -> MemOrdering { match self { AtomicRwOrd::Relaxed => MemOrdering::Relaxed, diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs index c1da86c673364..7270c66810608 100644 --- a/src/tools/miri/src/concurrency/genmc/mod.rs +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -13,15 +13,16 @@ use tracing::{debug, info}; use self::global_allocations::{EvalContextExt as _, GlobalAllocationHandler}; use self::helper::{ - MAX_ACCESS_SIZE, genmc_scalar_to_scalar, scalar_to_genmc_scalar, to_genmc_rmw_op, + MAX_ACCESS_SIZE, Warnings, emit_warning, genmc_scalar_to_scalar, + maybe_upgrade_compare_exchange_success_orderings, scalar_to_genmc_scalar, to_genmc_rmw_op, }; use self::thread_id_map::ThreadIdMap; use crate::concurrency::genmc::helper::split_access; use crate::intrinsics::AtomicRmwOp; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, MiriMemoryKind, Scalar, TerminationInfo, ThreadId, ThreadManager, VisitProvenance, - VisitWith, + MiriMachine, MiriMemoryKind, NonHaltingDiagnostic, Scalar, TerminationInfo, ThreadId, + ThreadManager, VisitProvenance, VisitWith, }; mod config; @@ -81,16 +82,22 @@ impl PerExecutionState { } } -#[derive(Debug)] struct GlobalState { /// Keep track of global allocations, to ensure they keep the same address across different executions, even if the order of allocations changes. /// The `AllocId` for globals is stable across executions, so we can use it as an identifier. global_allocations: GlobalAllocationHandler, + + /// Cache for which warnings have already been shown to the user. + /// `None` if warnings are disabled. + warning_cache: Option, } impl GlobalState { - fn new(target_usize_max: u64) -> Self { - Self { global_allocations: GlobalAllocationHandler::new(target_usize_max) } + fn new(target_usize_max: u64, print_warnings: bool) -> Self { + Self { + global_allocations: GlobalAllocationHandler::new(target_usize_max), + warning_cache: print_warnings.then(Default::default), + } } } @@ -348,21 +355,91 @@ impl GenmcCtx { /// `old_value` is the value that a non-atomic load would read here, or `None` if the memory is uninitalized. pub(crate) fn atomic_compare_exchange<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _expected_old_value: Scalar, - _new_value: Scalar, - _success: AtomicRwOrd, - _fail: AtomicReadOrd, - _can_fail_spuriously: bool, - _old_value: Scalar, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + expected_old_value: Scalar, + new_value: Scalar, + success: AtomicRwOrd, + fail: AtomicReadOrd, + can_fail_spuriously: bool, + old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Option, bool)> { assert!( !self.get_alloc_data_races(), "atomic compare-exchange with data race checking disabled." ); - throw_unsup_format!("FIXME(genmc): Add support for atomic compare_exchange.") + assert_ne!(0, size.bytes()); + assert!( + size.bytes() <= MAX_ACCESS_SIZE, + "GenMC currently does not support atomic accesses larger than {} bytes (got {} bytes)", + MAX_ACCESS_SIZE, + size.bytes() + ); + + // Upgrade the success memory ordering to equal the failure ordering, since GenMC currently ignores the failure ordering. + // FIXME(genmc): remove this once GenMC properly supports the failure memory ordering. + let upgraded_success_ordering = + maybe_upgrade_compare_exchange_success_orderings(success, fail); + + if let Some(warning_cache) = &self.global_state.warning_cache { + // FIXME(genmc): remove once GenMC supports failure memory ordering in `compare_exchange`. + let (effective_failure_ordering, _) = + upgraded_success_ordering.split_memory_orderings(); + // Return a warning if the actual orderings don't match the upgraded ones. + if success != upgraded_success_ordering || effective_failure_ordering != fail { + emit_warning(ecx, &warning_cache.compare_exchange_failure_ordering, || { + NonHaltingDiagnostic::GenmcCompareExchangeOrderingMismatch { + success_ordering: success, + upgraded_success_ordering, + failure_ordering: fail, + effective_failure_ordering, + } + }); + } + // FIXME(genmc): remove once GenMC implements spurious failures for `compare_exchange_weak`. + if can_fail_spuriously { + emit_warning(ecx, &warning_cache.compare_exchange_weak, || { + NonHaltingDiagnostic::GenmcCompareExchangeWeak + }); + } + } + + debug!( + "GenMC: atomic_compare_exchange, address: {address:?}, size: {size:?} (expect: {expected_old_value:?}, new: {new_value:?}, old_value: {old_value:?}, {success:?}, orderings: {fail:?}), can fail spuriously: {can_fail_spuriously}" + ); + + let thread_infos = self.exec_state.thread_id_manager.borrow(); + let genmc_tid = thread_infos.get_genmc_tid(ecx.machine.threads.active_thread()); + + let cas_result = self.handle.borrow_mut().pin_mut().handle_compare_exchange( + genmc_tid, + address.bytes(), + size.bytes(), + scalar_to_genmc_scalar(ecx, expected_old_value)?, + scalar_to_genmc_scalar(ecx, new_value)?, + scalar_to_genmc_scalar(ecx, old_value)?, + upgraded_success_ordering.to_genmc(), + fail.to_genmc(), + can_fail_spuriously, + ); + + if let Some(error) = cas_result.error.as_ref() { + // FIXME(genmc): error handling + throw_ub_format!("{}", error.to_string_lossy()); + } + + let return_scalar = genmc_scalar_to_scalar(ecx, cas_result.old_value, size)?; + debug!( + "GenMC: atomic_compare_exchange: result: {cas_result:?}, returning scalar: {return_scalar:?}" + ); + // The write can only be a co-maximal write if the CAS succeeded. + assert!(cas_result.is_success || !cas_result.is_coherence_order_maximal_write); + interp_ok(( + return_scalar, + cas_result.is_coherence_order_maximal_write.then_some(new_value), + cas_result.is_success, + )) } /// Inform GenMC about a non-atomic memory load diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs index 24d13e6375b11..7e4ed816a76a1 100644 --- a/src/tools/miri/src/concurrency/genmc/run.rs +++ b/src/tools/miri/src/concurrency/genmc/run.rs @@ -23,7 +23,9 @@ pub fn run_genmc_mode<'tcx>( // There exists only one `global_state` per full run in GenMC mode. // It is shared by all `GenmcCtx` in this run. // FIXME(genmc): implement multithreading once GenMC supports it. - let global_state = Arc::new(GlobalState::new(tcx.target_usize_max())); + // FIXME(genmc): disable warnings in estimation mode once it is added. + let global_state = + Arc::new(GlobalState::new(tcx.target_usize_max(), /* print_warnings */ true)); let genmc_ctx = Rc::new(GenmcCtx::new(config, global_state)); // `rep` is used to report the progress, Miri will panic on wrap-around. diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 0842307caf9ab..15f7ccbabca6a 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -141,6 +141,13 @@ pub enum NonHaltingDiagnostic { ptr: Pointer, }, ExternTypeReborrow, + GenmcCompareExchangeWeak, + GenmcCompareExchangeOrderingMismatch { + success_ordering: AtomicRwOrd, + upgraded_success_ordering: AtomicRwOrd, + failure_ordering: AtomicReadOrd, + effective_failure_ordering: AtomicReadOrd, + }, } /// Level of Miri specific diagnostics @@ -637,6 +644,8 @@ impl<'tcx> MiriMachine<'tcx> { ("sharing memory with a native function".to_string(), DiagLevel::Warning), ExternTypeReborrow => ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning), + GenmcCompareExchangeWeak | GenmcCompareExchangeOrderingMismatch { .. } => + ("GenMC might miss possible behaviors of this code".to_string(), DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedAlloc(..) @@ -675,6 +684,23 @@ impl<'tcx> MiriMachine<'tcx> { format!("weak memory emulation: outdated value returned from load at {ptr}"), ExternTypeReborrow => format!("reborrow of a reference to `extern type` is not properly supported"), + GenmcCompareExchangeWeak => + "GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures." + .to_string(), + GenmcCompareExchangeOrderingMismatch { + success_ordering, + upgraded_success_ordering, + failure_ordering, + effective_failure_ordering, + } => { + let was_upgraded_msg = if success_ordering != upgraded_success_ordering { + format!("Success ordering '{success_ordering:?}' was upgraded to '{upgraded_success_ordering:?}' to match failure ordering '{failure_ordering:?}'") + } else { + assert_ne!(failure_ordering, effective_failure_ordering); + format!("Due to success ordering '{success_ordering:?}', the failure ordering '{failure_ordering:?}' is treated like '{effective_failure_ordering:?}'") + }; + format!("GenMC currently does not model the failure ordering for `compare_exchange`. {was_upgraded_msg}. Miri with GenMC might miss bugs related to this memory access.") + } }; let notes = match &e { diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.rs b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.rs new file mode 100644 index 0000000000000..32954a643b34b --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test `wrong/racy/MPU2+rels+rlx`. +// Test if Miri with GenMC can detect the data race on `X`. +// The data race only occurs if thread 1 finishes, then threads 3 and 4 run, then thread 2. +// +// This data race is hard to detect for Miri without GenMC, requiring -Zmiri-many-seeds=0..1024 at the time this test was created. + +// FIXME(genmc): once Miri-GenMC error reporting is improved, ensure that it correctly points to the two spans involved in the data race. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; + +use genmc::spawn_pthread_closure; +static mut X: u64 = 0; +static Y: AtomicUsize = AtomicUsize::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let _t1 = spawn_pthread_closure(|| { + X = 1; + Y.store(0, Release); + Y.store(1, Relaxed); + }); + let _t2 = spawn_pthread_closure(|| { + if Y.load(Relaxed) > 2 { + X = 2; //~ ERROR: Undefined Behavior: Non-atomic race + } + }); + let _t3 = spawn_pthread_closure(|| { + let _ = Y.compare_exchange(2, 3, Relaxed, Relaxed); + }); + + let _t4 = spawn_pthread_closure(|| { + let _ = Y.compare_exchange(1, 2, Relaxed, Relaxed); + }); + } + 0 +} diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr new file mode 100644 index 0000000000000..946d9a2124b88 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: Non-atomic race + --> tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC + | +LL | X = 2; + | ^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC + = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC}>` + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | f(); + | ^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr new file mode 100644 index 0000000000000..a6c3ed7055e75 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: the program aborted execution + --> tests/genmc/fail/loom/store_buffering.rs:LL:CC + | +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/loom/store_buffering.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr new file mode 100644 index 0000000000000..a6c3ed7055e75 --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr @@ -0,0 +1,13 @@ +error: abnormal termination: the program aborted execution + --> tests/genmc/fail/loom/store_buffering.rs:LL:CC + | +LL | std::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/loom/store_buffering.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs new file mode 100644 index 0000000000000..4955dfd8a77ad --- /dev/null +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.rs @@ -0,0 +1,57 @@ +//@ revisions: non_genmc genmc +//@[genmc] compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: Copyright (c) 2019 Carl Lerche + +// This is the test `store_buffering` from `loom/test/litmus.rs`, adapted for Miri-GenMC. +// https://github.com/tokio-rs/loom/blob/dbf32b04bae821c64be44405a0bb72ca08741558/tests/litmus.rs + +// This test shows the comparison between running Miri with or without GenMC. +// Without GenMC, Miri requires multiple iterations of the loop to detect the error. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // For normal Miri, we need multiple repetitions, but GenMC should find the bug with only 1. + const REPS: usize = if cfg!(non_genmc) { 128 } else { 1 }; + for _ in 0..REPS { + // New atomics every iterations, so they don't influence each other. + let x = AtomicUsize::new(0); + let y = AtomicUsize::new(0); + + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + x.store(0, Relaxed); + y.store(0, Relaxed); + + let mut a: usize = 1234; + let mut b: usize = 1234; + unsafe { + let ids = [ + spawn_pthread_closure(|| { + x.store(1, Relaxed); + a = y.load(Relaxed) + }), + spawn_pthread_closure(|| { + y.store(1, Relaxed); + b = x.load(Relaxed) + }), + ]; + join_pthreads(ids); + } + if (a, b) == (0, 0) { + std::process::abort(); //~ ERROR: abnormal termination + } + } + + 0 +} diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs new file mode 100644 index 0000000000000..8a77d54a64f8b --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs @@ -0,0 +1,70 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows -Zmiri-ignore-leaks + +// Adapted from: `impl LazyKey`, `fn lazy_init`: rust/library/std/src/sys/thread_local/key/racy.rs +// Two threads race to initialize a key, which is just an index into an array in this test. +// The (Acquire, Release) orderings on the compare_exchange prevent any data races for reading from `VALUES[key]`. + +// FIXME(genmc): GenMC does not model the failure ordering of compare_exchange currently. +// Miri thus upgrades the success ordering to prevent showing any false data races in cases like this one. +// Once GenMC supports the failure ordering, this test should work without the upgrading. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +const KEY_SENTVAL: usize = usize::MAX; + +static KEY: AtomicUsize = AtomicUsize::new(KEY_SENTVAL); + +static mut VALUES: [usize; 2] = [0, 0]; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + KEY.store(KEY_SENTVAL, Relaxed); + + unsafe { + let mut a = 0; + let mut b = 0; + let ids = [ + spawn_pthread_closure(|| { + VALUES[0] = 42; + let key = get_or_init(0); + if key > 2 { + std::process::abort(); + } + a = VALUES[key]; + }), + spawn_pthread_closure(|| { + VALUES[1] = 1234; + let key = get_or_init(1); + if key > 2 { + std::process::abort(); + } + b = VALUES[key]; + }), + ]; + join_pthreads(ids); + if a != b { + std::process::abort(); + } + } + 0 +} + +fn get_or_init(key: usize) -> usize { + match KEY.compare_exchange(KEY_SENTVAL, key, Release, Acquire) { + // The CAS succeeded, so we've created the actual key. + Ok(_) => key, + // If someone beat us to the punch, use their key instead. + // The `Acquire` failure ordering means we synchronized with the `Release` compare_exchange in the thread that wrote the other key. + // We can thus read from `VALUES[other_key]` without a data race. + Err(other_key) => other_key, + } +} diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr new file mode 100644 index 0000000000000..d97b8b3d92f48 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr @@ -0,0 +1,22 @@ +warning: GenMC currently does not model the failure ordering for `compare_exchange`. Success ordering 'Release' was upgraded to 'AcqRel' to match failure ordering 'Acquire'. Miri with GenMC might miss bugs related to this memory access. + --> tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC + | +LL | match KEY.compare_exchange(KEY_SENTVAL, key, Release, Acquire) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code + | + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside `get_or_init` at tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC +note: inside closure + --> tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC + | +LL | let key = get_or_init(0); + | ^^^^^^^^^^^^^^ + = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC}>` + --> tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC + | +LL | f(); + | ^^^ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_simple.rs b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.rs new file mode 100644 index 0000000000000..e32c7cdf80c43 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Test the basic functionality of compare_exchange. + +#![no_main] + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; + +static VALUE: AtomicUsize = AtomicUsize::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + VALUE.store(1, SeqCst); + + // Expect success: + if VALUE.compare_exchange(1, 2, SeqCst, SeqCst) != Ok(1) { + std::process::abort(); + } + // New value should be written: + if 2 != VALUE.load(SeqCst) { + std::process::abort() + } + + // Expect failure: + if VALUE.compare_exchange(1234, 42, SeqCst, SeqCst) != Err(2) { + std::process::abort(); + } + // Value should be unchanged: + if 2 != VALUE.load(SeqCst) { + std::process::abort() + } + 0 +} diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr new file mode 100644 index 0000000000000..3b22247ee44cb --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_simple.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs index 163556dcc8975..c81573d59d1da 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/IRIWish.rs @@ -57,9 +57,7 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { join_pthreads(ids); // Print the values to check that we get all of them: - if writeln!(MiriStderr, "{results:?}").is_err() { - std::process::abort(); - } + writeln!(MiriStderr, "{results:?}").unwrap_or_else(|_| std::process::abort()); 0 } diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.rs b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.rs new file mode 100644 index 0000000000000..9bb156a99970f --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.rs @@ -0,0 +1,67 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's "litmus/MPU2+rels+acqf" test. + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; +#[path = "../../../utils/mod.rs"] +mod utils; + +use std::fmt::Write; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; +use crate::utils::*; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU2+rels+acqf/mpu2+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + + unsafe { + let mut a = Ok(1234); + let mut b = Ok(1234); + let mut c = 1234; + let ids = [ + spawn_pthread_closure(|| { + X.store(1, Relaxed); + + Y.store(0, Release); + Y.store(1, Relaxed); + }), + spawn_pthread_closure(|| { + a = Y.compare_exchange(2, 3, Relaxed, Relaxed); + }), + spawn_pthread_closure(|| { + b = Y.compare_exchange(1, 2, Relaxed, Relaxed); + }), + spawn_pthread_closure(|| { + c = Y.load(Acquire); + if c > 2 { + std::sync::atomic::fence(Acquire); + X.store(2, Relaxed); + } + }), + ]; + join_pthreads(ids); + + // Print the values to check that we get all of them: + writeln!( + MiriStderr, + "X={}, Y={}, a={a:?}, b={b:?}, c={c}", + X.load(Relaxed), + Y.load(Relaxed) + ) + .unwrap_or_else(|_| std::process::abort()); + + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr new file mode 100644 index 0000000000000..4551c00b0575d --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/MPU2_rels_acqf.stderr @@ -0,0 +1,38 @@ +X=1, Y=2, a=Err(1), b=Ok(1), c=2 +X=1, Y=2, a=Err(1), b=Ok(1), c=1 +X=1, Y=2, a=Err(1), b=Ok(1), c=0 +X=1, Y=2, a=Err(1), b=Ok(1), c=0 +X=2, Y=3, a=Ok(2), b=Ok(1), c=3 +X=1, Y=3, a=Ok(2), b=Ok(1), c=3 +X=1, Y=3, a=Ok(2), b=Ok(1), c=2 +X=1, Y=3, a=Ok(2), b=Ok(1), c=1 +X=1, Y=3, a=Ok(2), b=Ok(1), c=0 +X=1, Y=3, a=Ok(2), b=Ok(1), c=0 +X=1, Y=1, a=Err(1), b=Err(0), c=1 +X=1, Y=1, a=Err(1), b=Err(0), c=0 +X=1, Y=1, a=Err(1), b=Err(0), c=0 +X=1, Y=1, a=Err(1), b=Err(0), c=1 +X=1, Y=1, a=Err(1), b=Err(0), c=0 +X=1, Y=1, a=Err(1), b=Err(0), c=0 +X=1, Y=2, a=Err(0), b=Ok(1), c=2 +X=1, Y=2, a=Err(0), b=Ok(1), c=1 +X=1, Y=2, a=Err(0), b=Ok(1), c=0 +X=1, Y=2, a=Err(0), b=Ok(1), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=1 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=1 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=2, a=Err(0), b=Ok(1), c=2 +X=1, Y=2, a=Err(0), b=Ok(1), c=1 +X=1, Y=2, a=Err(0), b=Ok(1), c=0 +X=1, Y=2, a=Err(0), b=Ok(1), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=1 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=1 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +X=1, Y=1, a=Err(0), b=Err(0), c=0 +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs index ac5c3724254d6..f96679b23a5cd 100644 --- a/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs +++ b/src/tools/miri/tests/genmc/pass/litmus/Z6_U.rs @@ -55,11 +55,8 @@ fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { join_pthreads(ids); // Print the values to check that we get all of them: - if writeln!(MiriStderr, "a={a}, b={b}, X={}, Y={}", X.load(Relaxed), Y.load(Relaxed)) - .is_err() - { - std::process::abort(); - } + writeln!(MiriStderr, "a={a}, b={b}, X={}, Y={}", X.load(Relaxed), Y.load(Relaxed)) + .unwrap_or_else(|_| std::process::abort()); 0 } } diff --git a/src/tools/miri/tests/genmc/pass/litmus/casdep.rs b/src/tools/miri/tests/genmc/pass/litmus/casdep.rs new file mode 100644 index 0000000000000..c376d96b111cc --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/casdep.rs @@ -0,0 +1,37 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/casdep". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove these initializing writes once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + Y.store(0, Relaxed); + Z.store(0, Relaxed); + + unsafe { + spawn_pthread_closure(|| { + let a = X.load(Relaxed); + let _b = Y.compare_exchange(a, 1, Relaxed, Relaxed); + Z.store(a, Relaxed); + }); + spawn_pthread_closure(|| { + Y.store(2, Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr b/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr new file mode 100644 index 0000000000000..01701dfe6918a --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/casdep.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/src/tools/miri/tests/genmc/pass/litmus/ccr.rs b/src/tools/miri/tests/genmc/pass/litmus/ccr.rs new file mode 100644 index 0000000000000..865895b4dcd96 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/ccr.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/ccr". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + spawn_pthread_closure(|| { + let expected = 0; + let _ = X.compare_exchange(expected, 42, Relaxed, Relaxed); + }); + spawn_pthread_closure(|| { + let expected = 0; + let _ = X.compare_exchange(expected, 17, Relaxed, Relaxed); + X.load(Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr b/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr new file mode 100644 index 0000000000000..01701dfe6918a --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/ccr.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/src/tools/miri/tests/genmc/pass/litmus/cii.rs b/src/tools/miri/tests/genmc/pass/litmus/cii.rs new file mode 100644 index 0000000000000..663c806e667c4 --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cii.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows + +// Translated from GenMC's test "litmus/cii". + +#![no_main] + +#[path = "../../../utils/genmc.rs"] +mod genmc; + +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::*; + +use crate::genmc::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // FIXME(genmc,HACK): remove this initializing write once Miri-GenMC supports mixed atomic-non-atomic accesses. + X.store(0, Relaxed); + + unsafe { + spawn_pthread_closure(|| { + let expected = 1; + let _ = X.compare_exchange(expected, 2, Relaxed, Relaxed); + }); + spawn_pthread_closure(|| { + X.fetch_add(1, Relaxed); + }); + spawn_pthread_closure(|| { + X.fetch_add(1, Relaxed); + }); + 0 + } +} diff --git a/src/tools/miri/tests/genmc/pass/litmus/cii.stderr b/src/tools/miri/tests/genmc/pass/litmus/cii.stderr new file mode 100644 index 0000000000000..be75e68fde77d --- /dev/null +++ b/src/tools/miri/tests/genmc/pass/litmus/cii.stderr @@ -0,0 +1,2 @@ +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 From ae57f08c1377b304b13fbb922438615d7692d65e Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 13 Sep 2025 04:52:19 +0000 Subject: [PATCH 209/251] Prepare for merging from rust-lang/rust This updates the rust-version file to 4ba1cf9ade4c8e2fa10676a50ee34594eb161837. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b3f8a26875f40..e5f0be9ac9551 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2a9bacf6187685931d52346a0ecff2e52bdc91cc +4ba1cf9ade4c8e2fa10676a50ee34594eb161837 From 3a784d9d1f292707000cdfce9072c876480471e4 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 14 Sep 2025 04:52:56 +0000 Subject: [PATCH 210/251] Prepare for merging from rust-lang/rust This updates the rust-version file to a015919e54c60b1b2bec7a98dec478cfc4a48f4e. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e5f0be9ac9551..8315eb30f9431 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -4ba1cf9ade4c8e2fa10676a50ee34594eb161837 +a015919e54c60b1b2bec7a98dec478cfc4a48f4e From 8df078a3f0071b311be2449407ae523f89ca6a33 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 13 Sep 2025 21:59:39 +0000 Subject: [PATCH 211/251] RISC-V: Improvements of inline assembly uses This commit performs various improvements (better register allocation, less register clobbering on the worst case and better readability) of RISC-V inline assembly use cases. Note that it does not change the `p` module (which defines the "P" extension draft instructions but very likely to change). 1. Use `lateout` as possible. Unlike `out(reg)` and `in(reg)` pair, `lateout(reg)` and `in(reg)` can share the same register because they state that the late-output register is written after all the reads are performed. It can improve register allocation. 2. Add `preserves_flags` option as possible. While RISC-V doesn't have _regular_ condition codes, RISC-V inline assembly in the Rust language assumes that some registers (mainly vector state registers) may be overwritten by default. By adding `preserves_flags` to the intrinsics corresponding instructions without overwriting them, it can minimize register clobbering on the worst case. 3. Use trailing semicolon. As `asm!` declares an action and it doesn't return a value by itself, it would be better to have trailing semicolon to denote that an `asm!` call is effectively a statement. 4. Make most of `asm!` calls multi-lined. `rustfmt` makes some simple (yet long) `asm!` calls multi-lined but it does not perform formatting of complex `asm!` calls with inputs and/or outputs. To keep consistency, it makes most of the `asm!` calls multi-lined. --- .../crates/core_arch/src/riscv64/mod.rs | 21 +- .../crates/core_arch/src/riscv_shared/mod.rs | 245 ++++++++++++++---- 2 files changed, 215 insertions(+), 51 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/riscv64/mod.rs b/library/stdarch/crates/core_arch/src/riscv64/mod.rs index 0e860f6f2ad2f..a7efc0c7f58a1 100644 --- a/library/stdarch/crates/core_arch/src/riscv64/mod.rs +++ b/library/stdarch/crates/core_arch/src/riscv64/mod.rs @@ -20,7 +20,12 @@ pub use zk::*; #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_wu(src: *const u32) -> u32 { let value: u32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x681", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x681", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -38,7 +43,12 @@ pub unsafe fn hlv_wu(src: *const u32) -> u32 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_d(src: *const i64) -> i64 { let value: i64; - asm!(".insn i 0x73, 0x4, {}, {}, 0x6C0", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x6C0", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -53,5 +63,10 @@ pub unsafe fn hlv_d(src: *const i64) -> i64 { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hsv_d(dst: *mut i64, src: i64) { - asm!(".insn r 0x73, 0x4, 0x37, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); + asm!( + ".insn r 0x73, 0x4, 0x37, x0, {}, {}", + in(reg) dst, + in(reg) src, + options(nostack, preserves_flags) + ); } diff --git a/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs b/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs index 3ce24324de2e7..1bd147a64808c 100644 --- a/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs +++ b/library/stdarch/crates/core_arch/src/riscv_shared/mod.rs @@ -44,7 +44,12 @@ use crate::arch::asm; #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub fn pause() { - unsafe { asm!(".insn i 0x0F, 0, x0, x0, 0x010", options(nomem, nostack)) } + unsafe { + asm!( + ".insn i 0x0F, 0, x0, x0, 0x010", + options(nomem, nostack, preserves_flags) + ); + } } /// Generates the `NOP` instruction @@ -54,7 +59,9 @@ pub fn pause() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub fn nop() { - unsafe { asm!("nop", options(nomem, nostack)) } + unsafe { + asm!("nop", options(nomem, nostack, preserves_flags)); + } } /// Generates the `WFI` instruction @@ -65,7 +72,7 @@ pub fn nop() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn wfi() { - asm!("wfi", options(nomem, nostack)) + asm!("wfi", options(nomem, nostack, preserves_flags)); } /// Generates the `FENCE.I` instruction @@ -78,7 +85,7 @@ pub unsafe fn wfi() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn fence_i() { - asm!("fence.i", options(nostack)) + asm!("fence.i", options(nostack, preserves_flags)); } /// Supervisor memory management fence for given virtual address and address space @@ -92,7 +99,7 @@ pub unsafe fn fence_i() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { - asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + asm!("sfence.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack, preserves_flags)); } /// Supervisor memory management fence for given virtual address @@ -104,7 +111,7 @@ pub unsafe fn sfence_vma(vaddr: usize, asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_vma_vaddr(vaddr: usize) { - asm!("sfence.vma {}, x0", in(reg) vaddr, options(nostack)) + asm!("sfence.vma {}, x0", in(reg) vaddr, options(nostack, preserves_flags)); } /// Supervisor memory management fence for given address space @@ -118,7 +125,7 @@ pub unsafe fn sfence_vma_vaddr(vaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_vma_asid(asid: usize) { - asm!("sfence.vma x0, {}", in(reg) asid, options(nostack)) + asm!("sfence.vma x0, {}", in(reg) asid, options(nostack, preserves_flags)); } /// Supervisor memory management fence for all address spaces and virtual addresses @@ -129,7 +136,7 @@ pub unsafe fn sfence_vma_asid(asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_vma_all() { - asm!("sfence.vma", options(nostack)) + asm!("sfence.vma", options(nostack, preserves_flags)); } /// Invalidate supervisor translation cache for given virtual address and address space @@ -139,8 +146,13 @@ pub unsafe fn sfence_vma_all() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { - // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) - asm!(".insn r 0x73, 0, 0x0B, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + // asm!("sinval.vma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack, preserves_flags)); + asm!( + ".insn r 0x73, 0, 0x0B, x0, {}, {}", + in(reg) vaddr, + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Invalidate supervisor translation cache for given virtual address @@ -150,7 +162,11 @@ pub unsafe fn sinval_vma(vaddr: usize, asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sinval_vma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x0B, x0, {}, x0", in(reg) vaddr, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x0B, x0, {}, x0", + in(reg) vaddr, + options(nostack, preserves_flags) + ); } /// Invalidate supervisor translation cache for given address space @@ -160,7 +176,11 @@ pub unsafe fn sinval_vma_vaddr(vaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sinval_vma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x0B, x0, x0, {}", in(reg) asid, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x0B, x0, x0, {}", + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Invalidate supervisor translation cache for all address spaces and virtual addresses @@ -170,7 +190,10 @@ pub unsafe fn sinval_vma_asid(asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sinval_vma_all() { - asm!(".insn r 0x73, 0, 0x0B, x0, x0, x0", options(nostack)) + asm!( + ".insn r 0x73, 0, 0x0B, x0, x0, x0", + options(nostack, preserves_flags) + ); } /// Generates the `SFENCE.W.INVAL` instruction @@ -180,8 +203,11 @@ pub unsafe fn sinval_vma_all() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_w_inval() { - // asm!("sfence.w.inval", options(nostack)) - asm!(".insn i 0x73, 0, x0, x0, 0x180", options(nostack)) + // asm!("sfence.w.inval", options(nostack, preserves_flags)); + asm!( + ".insn i 0x73, 0, x0, x0, 0x180", + options(nostack, preserves_flags) + ); } /// Generates the `SFENCE.INVAL.IR` instruction @@ -191,8 +217,11 @@ pub unsafe fn sfence_w_inval() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn sfence_inval_ir() { - // asm!("sfence.inval.ir", options(nostack)) - asm!(".insn i 0x73, 0, x0, x0, 0x181", options(nostack)) + // asm!("sfence.inval.ir", options(nostack, preserves_flags)); + asm!( + ".insn i 0x73, 0, x0, x0, 0x181", + options(nostack, preserves_flags) + ); } /// Loads virtual machine memory by signed byte integer @@ -207,7 +236,12 @@ pub unsafe fn sfence_inval_ir() { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_b(src: *const i8) -> i8 { let value: i8; - asm!(".insn i 0x73, 0x4, {}, {}, 0x600", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x600", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -223,7 +257,12 @@ pub unsafe fn hlv_b(src: *const i8) -> i8 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_bu(src: *const u8) -> u8 { let value: u8; - asm!(".insn i 0x73, 0x4, {}, {}, 0x601", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x601", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -239,7 +278,12 @@ pub unsafe fn hlv_bu(src: *const u8) -> u8 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_h(src: *const i16) -> i16 { let value: i16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x640", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x640", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -255,7 +299,12 @@ pub unsafe fn hlv_h(src: *const i16) -> i16 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_hu(src: *const u16) -> u16 { let value: u16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x641", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x641", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -271,7 +320,12 @@ pub unsafe fn hlv_hu(src: *const u16) -> u16 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlvx_hu(src: *const u16) -> u16 { let insn: u16; - asm!(".insn i 0x73, 0x4, {}, {}, 0x643", out(reg) insn, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x643", + lateout(reg) insn, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); insn } @@ -287,7 +341,12 @@ pub unsafe fn hlvx_hu(src: *const u16) -> u16 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlv_w(src: *const i32) -> i32 { let value: i32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x680", out(reg) value, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x680", + lateout(reg) value, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); value } @@ -303,7 +362,12 @@ pub unsafe fn hlv_w(src: *const i32) -> i32 { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hlvx_wu(src: *const u32) -> u32 { let insn: u32; - asm!(".insn i 0x73, 0x4, {}, {}, 0x683", out(reg) insn, in(reg) src, options(readonly, nostack)); + asm!( + ".insn i 0x73, 0x4, {}, {}, 0x683", + lateout(reg) insn, + in(reg) src, + options(readonly, nostack, preserves_flags) + ); insn } @@ -318,7 +382,12 @@ pub unsafe fn hlvx_wu(src: *const u32) -> u32 { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hsv_b(dst: *mut i8, src: i8) { - asm!(".insn r 0x73, 0x4, 0x31, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); + asm!( + ".insn r 0x73, 0x4, 0x31, x0, {}, {}", + in(reg) dst, + in(reg) src, + options(nostack, preserves_flags) + ); } /// Stores virtual machine memory by half integer @@ -332,7 +401,12 @@ pub unsafe fn hsv_b(dst: *mut i8, src: i8) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hsv_h(dst: *mut i16, src: i16) { - asm!(".insn r 0x73, 0x4, 0x33, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); + asm!( + ".insn r 0x73, 0x4, 0x33, x0, {}, {}", + in(reg) dst, + in(reg) src, + options(nostack, preserves_flags) + ); } /// Stores virtual machine memory by word integer @@ -346,7 +420,12 @@ pub unsafe fn hsv_h(dst: *mut i16, src: i16) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hsv_w(dst: *mut i32, src: i32) { - asm!(".insn r 0x73, 0x4, 0x35, x0, {}, {}", in(reg) dst, in(reg) src, options(nostack)); + asm!( + ".insn r 0x73, 0x4, 0x35, x0, {}, {}", + in(reg) dst, + in(reg) src, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for given guest virtual address and guest address space @@ -360,8 +439,13 @@ pub unsafe fn hsv_w(dst: *mut i32, src: i32) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) { - // asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid) - asm!(".insn r 0x73, 0, 0x11, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + // asm!("hfence.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack, preserves_flags)); + asm!( + ".insn r 0x73, 0, 0x11, x0, {}, {}", + in(reg) vaddr, + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for given guest virtual address @@ -375,7 +459,11 @@ pub unsafe fn hfence_vvma(vaddr: usize, asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_vvma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x11, x0, {}, x0", in(reg) vaddr, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x11, x0, {}, x0", + in(reg) vaddr, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for given guest address space @@ -389,7 +477,11 @@ pub unsafe fn hfence_vvma_vaddr(vaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_vvma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x11, x0, x0, {}", in(reg) asid, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x11, x0, x0, {}", + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for all guest address spaces and guest virtual addresses @@ -403,7 +495,10 @@ pub unsafe fn hfence_vvma_asid(asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_vvma_all() { - asm!(".insn r 0x73, 0, 0x11, x0, x0, x0", options(nostack)) + asm!( + ".insn r 0x73, 0, 0x11, x0, x0, x0", + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for guest physical address and virtual machine @@ -416,8 +511,13 @@ pub unsafe fn hfence_vvma_all() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) { - // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) - asm!(".insn r 0x73, 0, 0x31, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) + // asm!("hfence.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack, preserves_flags)); + asm!( + ".insn r 0x73, 0, 0x31, x0, {}, {}", + in(reg) gaddr, + in(reg) vmid, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for guest physical address @@ -429,7 +529,11 @@ pub unsafe fn hfence_gvma(gaddr: usize, vmid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_gvma_gaddr(gaddr: usize) { - asm!(".insn r 0x73, 0, 0x31, x0, {}, x0", in(reg) gaddr, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x31, x0, {}, x0", + in(reg) gaddr, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for given virtual machine @@ -441,7 +545,11 @@ pub unsafe fn hfence_gvma_gaddr(gaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_gvma_vmid(vmid: usize) { - asm!(".insn r 0x73, 0, 0x31, x0, x0, {}", in(reg) vmid, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x31, x0, x0, {}", + in(reg) vmid, + options(nostack, preserves_flags) + ); } /// Hypervisor memory management fence for all virtual machines and guest physical addresses @@ -453,7 +561,10 @@ pub unsafe fn hfence_gvma_vmid(vmid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hfence_gvma_all() { - asm!(".insn r 0x73, 0, 0x31, x0, x0, x0", options(nostack)) + asm!( + ".insn r 0x73, 0, 0x31, x0, x0, x0", + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for given guest virtual address and guest address space @@ -465,8 +576,13 @@ pub unsafe fn hfence_gvma_all() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) { - // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) - asm!(".insn r 0x73, 0, 0x13, x0, {}, {}", in(reg) vaddr, in(reg) asid, options(nostack)) + // asm!("hinval.vvma {}, {}", in(reg) vaddr, in(reg) asid, options(nostack, preserves_flags)); + asm!( + ".insn r 0x73, 0, 0x13, x0, {}, {}", + in(reg) vaddr, + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for given guest virtual address @@ -478,7 +594,11 @@ pub unsafe fn hinval_vvma(vaddr: usize, asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_vvma_vaddr(vaddr: usize) { - asm!(".insn r 0x73, 0, 0x13, x0, {}, x0", in(reg) vaddr, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x13, x0, {}, x0", + in(reg) vaddr, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for given guest address space @@ -490,7 +610,11 @@ pub unsafe fn hinval_vvma_vaddr(vaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_vvma_asid(asid: usize) { - asm!(".insn r 0x73, 0, 0x13, x0, x0, {}", in(reg) asid, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x13, x0, x0, {}", + in(reg) asid, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for all guest address spaces and guest virtual addresses @@ -502,7 +626,10 @@ pub unsafe fn hinval_vvma_asid(asid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_vvma_all() { - asm!(".insn r 0x73, 0, 0x13, x0, x0, x0", options(nostack)) + asm!( + ".insn r 0x73, 0, 0x13, x0, x0, x0", + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for guest physical address and virtual machine @@ -515,8 +642,13 @@ pub unsafe fn hinval_vvma_all() { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) { - // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) - asm!(".insn r 0x73, 0, 0x33, x0, {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack)) + // asm!("hinval.gvma {}, {}", in(reg) gaddr, in(reg) vmid, options(nostack, preserves_flags)); + asm!( + ".insn r 0x73, 0, 0x33, x0, {}, {}", + in(reg) gaddr, + in(reg) vmid, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for guest physical address @@ -528,7 +660,11 @@ pub unsafe fn hinval_gvma(gaddr: usize, vmid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_gvma_gaddr(gaddr: usize) { - asm!(".insn r 0x73, 0, 0x33, x0, {}, x0", in(reg) gaddr, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x33, x0, {}, x0", + in(reg) gaddr, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for given virtual machine @@ -540,7 +676,11 @@ pub unsafe fn hinval_gvma_gaddr(gaddr: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_gvma_vmid(vmid: usize) { - asm!(".insn r 0x73, 0, 0x33, x0, x0, {}", in(reg) vmid, options(nostack)) + asm!( + ".insn r 0x73, 0, 0x33, x0, x0, {}", + in(reg) vmid, + options(nostack, preserves_flags) + ); } /// Invalidate hypervisor translation cache for all virtual machines and guest physical addresses @@ -552,7 +692,10 @@ pub unsafe fn hinval_gvma_vmid(vmid: usize) { #[inline] #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub unsafe fn hinval_gvma_all() { - asm!(".insn r 0x73, 0, 0x33, x0, x0, x0", options(nostack)) + asm!( + ".insn r 0x73, 0, 0x33, x0, x0, x0", + options(nostack, preserves_flags) + ); } /// Reads the floating-point rounding mode register `frm` @@ -574,6 +717,12 @@ pub unsafe fn hinval_gvma_all() { #[unstable(feature = "riscv_ext_intrinsics", issue = "114544")] pub fn frrm() -> u32 { let value: u32; - unsafe { asm!("frrm {}", out(reg) value, options(nomem, nostack)) }; + unsafe { + asm!( + "frrm {}", + out(reg) value, + options(nomem, nostack, preserves_flags) + ); + } value } From 9f850ceb33b2f55084362dddd2396db8469779bd Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 12 Sep 2025 01:59:39 +0900 Subject: [PATCH 212/251] fix: Infinite loop while elaborting predicates --- .../crates/hir-ty/src/dyn_compatibility.rs | 3 ++ .../hir-ty/src/dyn_compatibility/tests.rs | 3 +- .../crates/hir-ty/src/lower_nextsolver.rs | 3 ++ .../crates/hir-ty/src/next_solver/interner.rs | 23 +++++++++++++- .../hir-ty/src/tests/regression/new_solver.rs | 31 +++++++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index d4b3751cf5666..b87c998217741 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -138,6 +138,9 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b let interner = DbInterner::new_with(db, Some(krate), None); let predicates = db.generic_predicates_ns(def); + // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to + // rust-analyzer yet + // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490 elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| { match pred.kind().skip_binder() { ClauseKind::Trait(trait_pred) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 4ffa455084971..04a9ba79921ad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -253,7 +253,8 @@ trait Bar { trait Baz : Bar { } "#, - [("Bar", vec![]), ("Baz", vec![SizedSelf, SelfReferential])], + // FIXME: We should also report `SizedSelf` here + [("Bar", vec![]), ("Baz", vec![SelfReferential])], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index c6a8fa81edff5..5c29befe123cf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1358,6 +1358,9 @@ where } } + // FIXME: rustc gathers more predicates by recursing through resulting trait predicates. + // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715 + ( GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), create_diagnostics(ctx.diagnostics), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 0f512fdaf8687..7b6e8a1073d78 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -5,7 +5,7 @@ use base_db::Crate; use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; use hir_def::lang_item::LangItem; use hir_def::signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}; -use hir_def::{AdtId, BlockId, TypeAliasId, VariantId}; +use hir_def::{AdtId, BlockId, GenericDefId, TypeAliasId, VariantId}; use hir_def::{AttrDefId, Lookup}; use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId}; use intern::sym::non_exhaustive; @@ -1334,6 +1334,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .db() .generic_predicates_ns(def_id.0.into()) .iter() + .filter(|p| match p.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(tr) => match tr.self_ty().kind() { + rustc_type_ir::TyKind::Param(param) => param.index == 0, + _ => false, + }, + _ => true, + }) .cloned() .map(|p| (p, Span::dummy())) .collect(); @@ -1345,10 +1352,24 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { + fn is_self_or_assoc(ty: Ty<'_>) -> bool { + match ty.kind() { + rustc_type_ir::TyKind::Param(param) => param.index == 0, + rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => { + is_self_or_assoc(alias.self_ty()) + } + _ => false, + } + } + let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) .iter() + .filter(|p| match p.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(tr) => is_self_or_assoc(tr.self_ty()), + _ => true, + }) .cloned() .map(|p| (p, Span::dummy())) .collect(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 4df788638a315..595f285bd930e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -116,3 +116,34 @@ fn main() { "#]], ); } + +#[test] +fn no_infinite_loop_on_super_predicates_elaboration() { + check_infer( + r#" +//- minicore: sized +trait DimMax { + type Output: Dimension; +} + +trait Dimension: DimMax<:: Smaller, Output = Self> { + type Smaller: Dimension; +} + +fn test(t: T) +where + T: DimMax, + U: Dimension, +{ + let t: >::Output = loop {}; +} +"#, + expect![[r#" + 182..183 't': T + 230..280 '{ ... {}; }': () + 240..241 't': >::Output + 270..277 'loop {}': ! + 275..277 '{}': () + "#]], + ) +} From 5025bfa1466488a879bd83f8a022362970182ce4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 10 Sep 2025 20:34:02 +0300 Subject: [PATCH 213/251] Improve `rust-analyzer diagnostics` In my experience the `processing ` messages make it harder to search for the actual diagnostics, so remove them and instead print the filename only if there is a diagnostic. Also allow choosing the minimum severity. --- .../rust-analyzer/src/cli/diagnostics.rs | 46 +++++++++++++------ .../crates/rust-analyzer/src/cli/flags.rs | 24 ++++++++++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 7b12cb14009ff..82590c8e707fa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -9,7 +9,7 @@ use ide::{AnalysisHost, AssistResolveStrategy, Diagnostic, DiagnosticsConfig, Se use ide_db::{LineIndexDatabase, base_db::SourceDatabase}; use load_cargo::{LoadCargoConfig, ProcMacroServerChoice, load_workspace_at}; -use crate::cli::flags; +use crate::cli::{flags, progress_report::ProgressReport}; impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { @@ -50,23 +50,26 @@ impl flags::Diagnostics { let mut found_error = false; let mut visited_files = FxHashSet::default(); - - let work = all_modules(db).into_iter().filter(|module| { - let file_id = module.definition_source_file_id(db).original_file(db); - let source_root = db.file_source_root(file_id.file_id(db)).source_root_id(db); - let source_root = db.source_root(source_root).source_root(db); - !source_root.is_library - }); - + let min_severity = self.severity.unwrap_or(flags::Severity::Weak); + + let work = all_modules(db) + .into_iter() + .filter(|module| { + let file_id = module.definition_source_file_id(db).original_file(db); + let source_root = db.file_source_root(file_id.file_id(db)).source_root_id(db); + let source_root = db.source_root(source_root).source_root(db); + !source_root.is_library + }) + .collect::>(); + + let mut bar = ProgressReport::new(work.len()); for module in work { let file_id = module.definition_source_file_id(db).original_file(db); if !visited_files.contains(&file_id) { + let message = format!("processing {}", _vfs.file_path(file_id.file_id(db))); + bar.set_message(move || message.clone()); let crate_name = module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned(); - println!( - "processing crate: {crate_name}, module: {}", - _vfs.file_path(file_id.file_id(db)) - ); for diagnostic in analysis .full_diagnostics( &DiagnosticsConfig::test_sample(), @@ -75,6 +78,16 @@ impl flags::Diagnostics { ) .unwrap() { + let severity = match diagnostic.severity { + Severity::Error => flags::Severity::Error, + Severity::Warning => flags::Severity::Warning, + Severity::WeakWarning => flags::Severity::Weak, + Severity::Allow => continue, + }; + if severity < min_severity { + continue; + } + if matches!(diagnostic.severity, Severity::Error) { found_error = true; } @@ -83,12 +96,17 @@ impl flags::Diagnostics { let line_index = db.line_index(range.file_id); let start = line_index.line_col(range.range.start()); let end = line_index.line_col(range.range.end()); - println!("{severity:?} {code:?} from {start:?} to {end:?}: {message}"); + bar.println(format!( + "at crate {crate_name}, file {}: {severity:?} {code:?} from {start:?} to {end:?}: {message}", + _vfs.file_path(file_id.file_id(db)) + )); } visited_files.insert(file_id); } + bar.inc(1); } + bar.finish_and_clear(); println!(); println!("diagnostic scan complete"); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 16f351272b691..75030bedfca3f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -124,6 +124,9 @@ xflags::xflags! { optional --disable-proc-macros /// Run the proc-macro-srv binary at the specified path. optional --proc-macro-srv path: PathBuf + + /// The minimum severity. + optional --severity severity: Severity } /// Report unresolved references @@ -281,6 +284,7 @@ pub struct Diagnostics { pub disable_build_scripts: bool, pub disable_proc_macros: bool, pub proc_macro_srv: Option, + pub severity: Option, } #[derive(Debug)] @@ -376,3 +380,23 @@ impl FromStr for OutputFormat { } } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Severity { + Weak, + Warning, + Error, +} + +impl FromStr for Severity { + type Err = String; + + fn from_str(s: &str) -> Result { + match &*s.to_ascii_lowercase() { + "weak" => Ok(Self::Weak), + "warning" => Ok(Self::Warning), + "error" => Ok(Self::Error), + _ => Err(format!("unknown severity `{s}`")), + } + } +} From 55b8d4e6ffc220db78b928aacc274423631134f7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 15 Sep 2025 07:56:35 +0300 Subject: [PATCH 214/251] Don't mark unknown type as implementing every notable trait Because the new solver, will return "yes" for them (which is a good thing). --- .../rust-analyzer/crates/ide/src/hover.rs | 6 +++++ .../crates/ide/src/hover/tests.rs | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 3f52303d74e48..03b9b3677511c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -483,6 +483,12 @@ fn notable_traits<'db>( db: &'db RootDatabase, ty: &hir::Type<'db>, ) -> Vec<(hir::Trait, Vec<(Option>, hir::Name)>)> { + if ty.is_unknown() { + // The trait solver returns "yes" to the question whether the error type + // impls any trait, and we don't want to show it as having any notable trait. + return Vec::new(); + } + db.notable_traits_in_deps(ty.krate(db).into()) .iter() .flat_map(|it| &**it) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 58d8a7edbe042..a88c0c9866e5f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -11097,3 +11097,26 @@ impl Enum<'_, Borrowed> { "#]], ); } + +#[test] +fn unknown_should_not_implement_notable_traits() { + check( + r#" +//- minicore: future, iterator +fn foo() { + let x$0; +} + "#, + expect![[r#" + *x* + + ```rust + let x: {unknown} + ``` + + --- + + no Drop + "#]], + ); +} From 91f32ed1803b7164446f386c5844718e963aeb0c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 15 Sep 2025 08:25:17 +0300 Subject: [PATCH 215/251] Add regression tests to some S-blocked-on-new-solver issues That were fixed by the migration. --- .../hir-ty/src/tests/regression/new_solver.rs | 126 ++++++++++++++++++ .../crates/test-utils/src/minicore.rs | 12 +- 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 595f285bd930e..f559230fee394 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -2,6 +2,132 @@ use expect_test::expect; use crate::tests::{check_infer, check_no_mismatches}; +#[test] +fn regression_20365() { + check_infer( + r#" +//- minicore: iterator +struct Vec(T); +struct IntoIter(T); +impl IntoIterator for Vec { + type IntoIter = IntoIter; + type Item = T; +} +impl Iterator for IntoIter { + type Item = T; +} + +fn f(a: Vec) { + let iter = a.into_iter(); +} + +pub trait Space: IntoIterator { + type Ty: Space; +} +impl Space for [u8; 1] { + type Ty = Self; +} + "#, + expect![[r#" + 201..202 'a': Vec + 213..246 '{ ...r(); }': () + 223..227 'iter': IntoIter + 230..231 'a': Vec + 230..243 'a.into_iter()': IntoIter + "#]], + ); +} + +#[test] +fn regression_19971() { + check_infer( + r#" +//- minicore: pointee +fn make(_thin: *const (), _meta: core::ptr::DynMetadata) -> *const T +where + T: core::ptr::Pointee> + ?Sized, +{ + loop {} +} +trait Foo { + fn foo(&self) -> i32 { + loop {} + } +} + +fn test() -> i32 { + struct F {} + impl Foo for F {} + let meta = core::ptr::metadata(0 as *const F as *const dyn Foo); + + let f = F {}; + let fat_ptr = make(&f as *const F as *const (), meta); // <-- infers type as `*const {unknown}` + + let fat_ref = unsafe { &*fat_ptr }; // <-- infers type as `&{unknown}` + fat_ref.foo() // cannot 'go to definition' on `foo` +} + + "#, + expect![[r#" + 11..16 '_thin': *const () + 29..34 '_meta': DynMetadata + 155..170 '{ loop {} }': *const T + 161..168 'loop {}': ! + 166..168 '{}': () + 195..199 'self': &'? Self + 208..231 '{ ... }': i32 + 218..225 'loop {}': ! + 223..225 '{}': () + 252..613 '{ ...foo` }': i32 + 300..304 'meta': DynMetadata + 307..326 'core::...tadata': fn metadata(*const (dyn Foo + '?)) -> ::Metadata + 307..359 'core::...n Foo)': DynMetadata + 327..328 '0': usize + 327..340 '0 as *const F': *const F + 327..358 '0 as *...yn Foo': *const (dyn Foo + '?) + 370..371 'f': F + 374..378 'F {}': F + 388..395 'fat_ptr': *const (dyn Foo + '?) + 398..402 'make': fn make(*const (), DynMetadata) -> *const (dyn Foo + '?) + 398..437 'make(&... meta)': *const (dyn Foo + '?) + 403..405 '&f': &'? F + 403..417 '&f as *const F': *const F + 403..430 '&f as ...nst ()': *const () + 404..405 'f': F + 432..436 'meta': DynMetadata + 489..496 'fat_ref': &'? (dyn Foo + '?) + 499..519 'unsafe..._ptr }': &'? (dyn Foo + '?) + 508..517 '&*fat_ptr': &'? (dyn Foo + '?) + 509..517 '*fat_ptr': dyn Foo + '? + 510..517 'fat_ptr': *const (dyn Foo + '?) + 560..567 'fat_ref': &'? (dyn Foo + '?) + 560..573 'fat_ref.foo()': i32 + "#]], + ); +} + +#[test] +fn regression_19752() { + check_no_mismatches( + r#" +//- minicore: sized, copy +trait T1: Sized + Copy { + fn a(self, other: Self) -> Self { + other + } + + fn b(&mut self, other: Self) { + *self = self.a(other); + } +} + +trait T2: Sized { + type T1: T1; +} + "#, + ); +} + #[test] fn opaque_generics() { check_infer( 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 26e0f46705b9e..7c3e7fea1bdef 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -55,7 +55,7 @@ //! panic: fmt //! phantom_data: //! pin: -//! pointee: copy, send, sync, ord, hash, unpin +//! pointee: copy, send, sync, ord, hash, unpin, phantom_data //! range: //! receiver: deref //! result: @@ -504,6 +504,16 @@ pub mod ptr { #[lang = "metadata_type"] type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } + + #[lang = "dyn_metadata"] + pub struct DynMetadata { + _phantom: crate::marker::PhantomData, + } + + pub const fn metadata(ptr: *const T) -> ::Metadata { + loop {} + } + // endregion:pointee // region:non_null #[rustc_layout_scalar_valid_range_start(1)] From f40e71c9de3d5d1075fa9fd94fccdd6126ae1ad4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 15 Sep 2025 08:50:08 +0300 Subject: [PATCH 216/251] Add Regression Test For The One And The Only Issue #5514 --- .../hir-ty/src/tests/regression/new_solver.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index f559230fee394..82d670cef2b0e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -128,6 +128,40 @@ trait T2: Sized { ); } +#[test] +fn regression_type_checker_does_not_eagerly_select_predicates_from_where_clauses() { + // This was a very long standing issue (#5514) with a lot of duplicates, that was + // fixed by the switch to the new trait solver, so it deserves a long name and a + // honorable mention. + check_infer( + r#" +//- minicore: from + +struct Foo; +impl Foo { + fn method(self) -> i32 { 0 } +} + +fn f>(u: T) { + let x = u.into(); + x.method(); +} + "#, + expect![[r#" + 38..42 'self': Foo + 51..56 '{ 0 }': i32 + 53..54 '0': i32 + 79..80 'u': T + 85..126 '{ ...d(); }': () + 95..96 'x': Foo + 99..100 'u': T + 99..107 'u.into()': Foo + 113..114 'x': Foo + 113..123 'x.method()': i32 + "#]], + ); +} + #[test] fn opaque_generics() { check_infer( From f6a7da8673de4a87e8e882ff533904274396726b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 15 Sep 2025 10:48:26 +0300 Subject: [PATCH 217/251] Add a testing guide --- .../rust-analyzer/docs/book/src/SUMMARY.md | 1 + .../docs/book/src/contributing/testing.md | 106 ++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/tools/rust-analyzer/docs/book/src/contributing/testing.md diff --git a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md index dffdae94a6e86..3fb46d59a4a50 100644 --- a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md +++ b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md @@ -23,3 +23,4 @@ - [Setup](contributing/setup.md) - [Style](contributing/style.md) - [Syntax](contributing/syntax.md) + - [Writing Tests](contributing/testing.md) diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/testing.md b/src/tools/rust-analyzer/docs/book/src/contributing/testing.md new file mode 100644 index 0000000000000..ccee9b847b6e1 --- /dev/null +++ b/src/tools/rust-analyzer/docs/book/src/contributing/testing.md @@ -0,0 +1,106 @@ +rust-analyzer's testing is based on *snapshot tests*: a test is a piece of input text, usually a Rust code, and some output text. There is then some testing helper that runs the feature on the input text and compares the result to the output text. + +rust-analyzer uses a combination of the crate [`expect-test`](https://docs.rs/expect-test) and a custom testing framework. + +This all may sound too abstract, so let's demonstrate with an example. + +Type inference tests are located at `crates/hir-ty/src/tests`. There are various test helpers you can use. One of the simplest is `check_no_mismatches()`: it is given a piece of Rust code (we'll talk more about Rust code in tests later) and asserts that there are no type mismatches in it, that is, one type was expected but another was found (for example, `let x: () = 1` is a type mismatch). Note that we determine type mismatches via rust-analyzer's own analysis, not via the compiler (this is what we are testing, after all), which means there are often missed mismatches and sometimes bogus ones as well. + +For example, the following test will fail: +```rust +#[test] +fn this_will_fail() { + check_no_mismatches( + r#" +fn main() { + let x: () = 1; +} + "#, + ); +} +``` + +Sometimes we want to check more that there are no type mismatches. For that we use other helpers. For example, often we want to assert that the type of some expression is some specific type. For that we use the `check_types()` function. It takes a Rust code string with custom annotation, that are common in our test suite. The general scheme of annotation is: + + - `$0` marks a position. What to do with it is determined by the testing helper. Commonly it denotes the cursor position in IDE tests (for example, hover). + - `$0...$0` marks a range, commonly a selection in IDE tests. + - `^...^`, commonly seen in a comment (`// ^^^^`), labels the line above. For example, the following will attach the label `hey` to the range of the variable name `cool`: + + ```rust + let cool; + // ^^^^ hey + ``` + +`check_types()` uses labels to assert type: when you attach a label to a range, `check_types()` assert that the type of this range will be what written in the label. + +It's all too abstract without an example: +```rust +#[test] +fn my_test() { + check_types( + r#" +fn main() { + let x = 1; + // ^ i32 +} + "#, + ); +} +``` +Here, we assert that the type of the variable `x` is `i32`. Which is true, of course, so the test will pass. + +Oftentimes it is convenient to assert the types of all of the expressions at once, and that brings us to the last kind of test. It uses `expect-test` to match an output text: +```rust +#[test] +fn my_test() { + check_infer( + r#" +fn main() { + let x = 1; +} + "#, + expect![[r#" + 10..28 '{ ...= 1; }': () + 20..21 'x': i32 + 24..25 '1': i32 + "#]], + ); +} +``` +The text inside the `expect![[]]` is determined by the helper, `check_infer()` in this case. For `check_infer()`, each line is a range in the source code (the range is counted in bytes and the source is trimmed, indentation is stripped), next to it there is the text in that range, or some part of it with `...` if it's too long, and finally comes the type of that range. + +The important feature of `expect-test` is that it allows easy update of the expectation. Say you changed something in the code, maybe fixed a bug, and the output in `expect![[]]` needs to change. Or maybe you are writing it from scratch. Writing it by hand is very tedious and prone to mistakes. But `expect-trait` has a magic. You can set the environment variable `UPDATE_EXPECT=1`, then run the test, and it will update automatically! Some editors (e.g. VSCode) make it even more convenient: on them, on the top of every test that uses `expect-test`, next to the usual `Run | Debug` buttons, rust-analyzer also shows an `Update Expect` button. Clicking it will run that test in updating mode. + +## Rust code in the tests + +The first thing that you probably already noticed is that the Rust code in the tests is syntax highlighted! In fact, it even uses semantic highlighting. rust-analyzer highlights strings "as if" they contain Rust code if they are passed to a parameter marked `#[rust_analyzer::rust_fixture]`, and rust-analyzer test helpers do that (in fact, this was designed for them). + +The syntax highlighting is very important, not just because it's nice to the eye: it's very easy to make mistakes in test code, and debugging that can be very hard. Often the test will just fail, printing an `{unknown}` type, and you'll have no clue what's going wrong. The syntax is the clue; if something isn't highlighted correctly, that probably means there is an error (there is one exception to this, which we'll discuss later). You can even set the semantic highlighting tag `unresolved_reference` to e.g. red, so you will see such things clearly. + +Still, often you won't know what's going wrong. Why you can't fix the test, or worse, you expect it to fail but it doesn't. You can try the code on a real IDE to be sure it works. Later we'll give some tips to fix the test. + +### The fixture + +The Rust code in a test is not, a fact, a single Rust file. It has a mini-language that allows you to express multiple files, multiple crates, different configs, and more. All options are documented in `crates/test-utils/src/fixture.rs`, but here are some of the common ones: + + - `//- minicore: flag1, flag2, ...`. This is by far the most common flag. Tests in rust-analyzer don't have access by default to any other type - not `Option`, not `Iterator`, not even `Sized`. This flag allows you to include parts of the `crates/test-utils/src/minicore.rs` file, which mimics `core`. All possible flags are listed at the top of `minicore` along with the flags they imply, then later you can see by `// region:flag` and `// endregion:flag` what code each flag enables. + - `// /path/to/file.rs crate:crate deps:dep_a,dep_b`. The first component is the filename of the code that follows (until the next file). It is required, but only if you supply this line. Other components in this line are optional. They include `crate:crate_name`, to start a new crate, or `deps:dep_a,dep_b`, to declare dependencies between crates. You can also declare modules as usual in Rust - just name your paths `/foo.rs` or `/foo/mod.rs`, declare `mod foo` and that's it! + +So the following snippet: +```rust +//- minicore: sized, fn +// /lib.rs crate:foo +pub mod bar; +// /bar.rs +pub struct Bar; +// /main.rs crate:main deps:foo +use foo::Bar; +``` +Declares two crates `foo` and `main` where `main` depends on `foo`, with dependency in `Sized` and the `FnX` traits from `core`, and a module of `foo` called `bar`. + +And as promised, here are some tips to make your test work: + + - If you use some type/trait, you must *always* include it in `minicore`. Note - not all types from core/std are available there, you can add new (under flags) if you need. And import them if they are not in the prelude. + - If you use unsized types (`dyn Trait`/slices), you may want to include some or all of the following `minicore` flags: `sized`, `unsize`, `coerce_unsized`, `dispatch_from_dyn`. + - If you use closures, consider including the `fn` minicore flag. Async closures need the `async_fn` flag. + - `sized` is commonly needed, consider adding it if you're stuck. From 4e286122d9a9dfcc1ae33c3959a3e8fd325f324b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 15 Sep 2025 05:21:30 +0300 Subject: [PATCH 218/251] Port a bunch of stuff from rustc and fix a bunch of type mismatches/diagnostics This started from porting coercion, but ended with porting much more. --- .../crates/hir-def/src/signatures.rs | 19 + .../crates/hir-ty/src/autoderef.rs | 373 ++- .../crates/hir-ty/src/builder.rs | 47 +- .../crates/hir-ty/src/chalk_ext.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 8 + .../hir-ty/src/diagnostics/unsafe_check.rs | 5 +- .../crates/hir-ty/src/display.rs | 45 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 194 +- .../crates/hir-ty/src/infer/autoderef.rs | 54 + .../crates/hir-ty/src/infer/cast.rs | 156 +- .../crates/hir-ty/src/infer/closure.rs | 2287 +++++------------ .../hir-ty/src/infer/closure/analysis.rs | 1298 ++++++++++ .../crates/hir-ty/src/infer/coerce.rs | 1992 +++++++++----- .../crates/hir-ty/src/infer/expr.rs | 675 +++-- .../crates/hir-ty/src/infer/pat.rs | 31 +- .../crates/hir-ty/src/infer/unify.rs | 612 +++-- .../rust-analyzer/crates/hir-ty/src/layout.rs | 7 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 6 +- .../crates/hir-ty/src/lower_nextsolver.rs | 106 + .../crates/hir-ty/src/method_resolution.rs | 47 +- .../crates/hir-ty/src/mir/borrowck.rs | 9 +- .../crates/hir-ty/src/mir/eval.rs | 6 +- .../crates/hir-ty/src/mir/eval/shim.rs | 15 +- .../crates/hir-ty/src/mir/eval/tests.rs | 144 +- .../crates/hir-ty/src/mir/lower.rs | 2 +- .../crates/hir-ty/src/next_solver.rs | 8 +- .../crates/hir-ty/src/next_solver/consts.rs | 47 +- .../crates/hir-ty/src/next_solver/def_id.rs | 60 +- .../crates/hir-ty/src/next_solver/fulfill.rs | 151 +- .../hir-ty/src/next_solver/fulfill/errors.rs | 1332 ++++++++++ .../hir-ty/src/next_solver/generic_arg.rs | 45 +- .../crates/hir-ty/src/next_solver/infer/at.rs | 32 +- .../hir-ty/src/next_solver/infer/mod.rs | 6 + .../infer/region_constraints/mod.rs | 53 +- .../next_solver/infer/relate/generalize.rs | 2 +- .../src/next_solver/infer/relate/lattice.rs | 269 ++ .../src/next_solver/infer/relate/mod.rs | 1 + .../hir-ty/src/next_solver/infer/select.rs | 334 +++ .../src/next_solver/infer/snapshot/fudge.rs | 263 ++ .../src/next_solver/infer/snapshot/mod.rs | 1 + .../next_solver/infer/snapshot/undo_log.rs | 4 + .../hir-ty/src/next_solver/infer/traits.rs | 108 +- .../src/next_solver/infer/type_variable.rs | 15 +- .../crates/hir-ty/src/next_solver/inspect.rs | 501 ++++ .../crates/hir-ty/src/next_solver/interner.rs | 88 +- .../crates/hir-ty/src/next_solver/mapping.rs | 37 + .../solve_normalize.rs => normalize.rs} | 66 +- .../hir-ty/src/next_solver/obligation_ctxt.rs | 203 ++ .../hir-ty/src/next_solver/predicate.rs | 52 +- .../crates/hir-ty/src/next_solver/project.rs | 3 - .../crates/hir-ty/src/next_solver/solver.rs | 16 +- .../src/next_solver/structural_normalize.rs | 57 + .../crates/hir-ty/src/next_solver/ty.rs | 87 +- .../crates/hir-ty/src/next_solver/util.rs | 6 +- .../crates/hir-ty/src/target_feature.rs | 2 +- .../crates/hir-ty/src/tests/coercion.rs | 42 +- .../crates/hir-ty/src/tests/diagnostics.rs | 1 - .../crates/hir-ty/src/tests/incremental.rs | 8 +- .../crates/hir-ty/src/tests/macros.rs | 34 +- .../hir-ty/src/tests/method_resolution.rs | 63 +- .../crates/hir-ty/src/tests/never_type.rs | 24 +- .../crates/hir-ty/src/tests/opaque_types.rs | 1 + .../crates/hir-ty/src/tests/patterns.rs | 38 +- .../crates/hir-ty/src/tests/regression.rs | 242 +- .../hir-ty/src/tests/regression/new_solver.rs | 111 + .../crates/hir-ty/src/tests/simple.rs | 98 +- .../crates/hir-ty/src/tests/traits.rs | 357 +-- .../rust-analyzer/crates/hir-ty/src/traits.rs | 5 - .../rust-analyzer/crates/hir-ty/src/utils.rs | 108 +- .../crates/hir-ty/src/variance.rs | 57 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 8 +- .../src/handlers/convert_closure_to_fn.rs | 7 +- .../src/handlers/extract_function.rs | 2 +- .../ide-completion/src/completions/dot.rs | 4 +- .../ide-completion/src/tests/expression.rs | 3 +- .../src/handlers/typed_hole.rs | 2 +- .../src/handlers/unresolved_method.rs | 24 +- .../crates/ide/src/hover/tests.rs | 14 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 16 +- .../crates/intern/src/symbol/symbols.rs | 1 + .../rust-analyzer/tests/slow-tests/main.rs | 4 +- .../crates/test-utils/src/minicore.rs | 28 +- src/tools/rust-analyzer/xtask/src/tidy.rs | 9 + 84 files changed, 9358 insertions(+), 3944 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs rename src/tools/rust-analyzer/crates/hir-ty/src/next_solver/{project/solve_normalize.rs => normalize.rs} (87%) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/next_solver/structural_normalize.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index bf72fafeae724..47638610ed734 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -489,6 +489,7 @@ bitflags! { const HAS_TARGET_FEATURE = 1 << 9; const DEPRECATED_SAFE_2024 = 1 << 10; const EXPLICIT_SAFE = 1 << 11; + const RUSTC_INTRINSIC = 1 << 12; } } @@ -522,6 +523,9 @@ impl FunctionSignature { if attrs.by_key(sym::target_feature).exists() { flags.insert(FnFlags::HAS_TARGET_FEATURE); } + if attrs.by_key(sym::rustc_intrinsic).exists() { + flags.insert(FnFlags::RUSTC_INTRINSIC); + } let legacy_const_generics_indices = attrs.rustc_legacy_const_generics(); let source = loc.source(db); @@ -617,6 +621,21 @@ impl FunctionSignature { pub fn has_target_feature(&self) -> bool { self.flags.contains(FnFlags::HAS_TARGET_FEATURE) } + + pub fn is_intrinsic(db: &dyn DefDatabase, id: FunctionId) -> bool { + let data = db.function_signature(id); + data.flags.contains(FnFlags::RUSTC_INTRINSIC) + // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used + || match &data.abi { + Some(abi) => *abi == sym::rust_dash_intrinsic, + None => match id.lookup(db).container { + ItemContainerId::ExternBlockId(block) => { + block.abi(db) == Some(sym::rust_dash_intrinsic) + } + _ => false, + }, + } + } } bitflags! { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 82696a5c94daf..fd60ffcf24b0a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -3,27 +3,28 @@ //! reference to a type with the field `bar`. This is an approximation of the //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs). -use std::mem; +use std::fmt; -use chalk_ir::cast::Cast; -use hir_def::lang_item::LangItem; -use hir_expand::name::Name; -use intern::sym; +use hir_def::{TypeAliasId, lang_item::LangItem}; +use rustc_type_ir::inherent::{IntoKind, Ty as _}; +use tracing::debug; use triomphe::Arc; +use crate::next_solver::infer::InferOk; use crate::{ - Canonical, Goal, Interner, ProjectionTyExt, TraitEnvironment, Ty, TyBuilder, TyKind, - db::HirDatabase, infer::unify::InferenceTable, next_solver::mapping::ChalkToNextSolver, + TraitEnvironment, + db::HirDatabase, + infer::unify::InferenceTable, + next_solver::{ + Ty, TyKind, + infer::traits::{ObligationCause, PredicateObligations}, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + obligation_ctxt::ObligationCtxt, + }, }; const AUTODEREF_RECURSION_LIMIT: usize = 20; -#[derive(Debug)] -pub(crate) enum AutoderefKind { - Builtin, - Overloaded, -} - /// Returns types that `ty` transitively dereferences to. This function is only meant to be used /// outside `hir-ty`. /// @@ -34,16 +35,17 @@ pub(crate) enum AutoderefKind { pub fn autoderef( db: &dyn HirDatabase, env: Arc, - ty: Canonical, -) -> impl Iterator { + ty: crate::Canonical, +) -> impl Iterator { let mut table = InferenceTable::new(db, env); + let interner = table.interner; let ty = table.instantiate_canonical(ty); - let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false); + let mut autoderef = Autoderef::new_no_tracking(&mut table, ty.to_nextsolver(interner)); let mut v = Vec::new(); while let Some((ty, _steps)) = autoderef.next() { // `ty` may contain unresolved inference variables. Since there's no chance they would be // resolved, just replace with fallback type. - let resolved = autoderef.table.resolve_completely(ty); + let resolved = autoderef.table.resolve_completely(ty.to_chalk(interner)); // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we // would revisit some already visited types. Stop here to avoid duplication. @@ -59,178 +61,267 @@ pub fn autoderef( v.into_iter() } -trait TrackAutoderefSteps { +pub(crate) trait TrackAutoderefSteps<'db>: Default + fmt::Debug { fn len(&self) -> usize; - fn push(&mut self, kind: AutoderefKind, ty: &Ty); + fn push(&mut self, ty: Ty<'db>, kind: AutoderefKind); } -impl TrackAutoderefSteps for usize { +impl<'db> TrackAutoderefSteps<'db> for usize { fn len(&self) -> usize { *self } - fn push(&mut self, _: AutoderefKind, _: &Ty) { + fn push(&mut self, _: Ty<'db>, _: AutoderefKind) { *self += 1; } } -impl TrackAutoderefSteps for Vec<(AutoderefKind, Ty)> { +impl<'db> TrackAutoderefSteps<'db> for Vec<(Ty<'db>, AutoderefKind)> { fn len(&self) -> usize { self.len() } - fn push(&mut self, kind: AutoderefKind, ty: &Ty) { - self.push((kind, ty.clone())); + fn push(&mut self, ty: Ty<'db>, kind: AutoderefKind) { + self.push((ty, kind)); } } -#[derive(Debug)] -pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> { - pub(crate) table: &'table mut InferenceTable<'db>, - ty: Ty, - at_start: bool, - steps: T, - explicit: bool, - use_receiver_trait: bool, +#[derive(Copy, Clone, Debug)] +pub(crate) enum AutoderefKind { + /// A true pointer type, such as `&T` and `*mut T`. + Builtin, + /// A type which must dispatch to a `Deref` implementation. + Overloaded, } -impl<'table, 'db> Autoderef<'table, 'db> { - pub(crate) fn new( - table: &'table mut InferenceTable<'db>, - ty: Ty, - explicit: bool, - use_receiver_trait: bool, - ) -> Self { - let ty = table.structurally_resolve_type(&ty); - Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait } - } - - pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] { - &self.steps - } +struct AutoderefSnapshot<'db, Steps> { + at_start: bool, + reached_recursion_limit: bool, + steps: Steps, + cur_ty: Ty<'db>, + obligations: PredicateObligations<'db>, } -impl<'table, 'db> Autoderef<'table, 'db, usize> { - pub(crate) fn new_no_tracking( - table: &'table mut InferenceTable<'db>, - ty: Ty, - explicit: bool, - use_receiver_trait: bool, - ) -> Self { - let ty = table.structurally_resolve_type(&ty); - Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait } - } +#[derive(Clone, Copy)] +struct AutoderefTraits { + trait_target: TypeAliasId, } -#[allow(private_bounds)] -impl Autoderef<'_, '_, T> { - pub(crate) fn step_count(&self) -> usize { - self.steps.len() - } +/// Recursively dereference a type, considering both built-in +/// dereferences (`*`) and the `Deref` trait. +/// Although called `Autoderef` it can be configured to use the +/// `Receiver` trait instead of the `Deref` trait. +pub(crate) struct Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> { + // Meta infos: + pub(crate) table: &'a mut InferenceTable<'db>, + traits: Option, - pub(crate) fn final_ty(&self) -> Ty { - self.ty.clone() - } + // Current state: + state: AutoderefSnapshot<'db, Steps>, + + // Configurations: + include_raw_pointers: bool, + use_receiver_trait: bool, } -impl Iterator for Autoderef<'_, '_, T> { - type Item = (Ty, usize); +impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, Steps> { + type Item = (Ty<'db>, usize); - #[tracing::instrument(skip_all)] fn next(&mut self) -> Option { - if mem::take(&mut self.at_start) { - return Some((self.ty.clone(), 0)); + debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty); + if self.state.at_start { + self.state.at_start = false; + debug!("autoderef stage #0 is {:?}", self.state.cur_ty); + return Some((self.state.cur_ty, 0)); } - if self.steps.len() > AUTODEREF_RECURSION_LIMIT { + // If we have reached the recursion limit, error gracefully. + if self.state.steps.len() >= AUTODEREF_RECURSION_LIMIT { + self.state.reached_recursion_limit = true; return None; } - let (kind, new_ty) = - autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?; + if self.state.cur_ty.is_ty_var() { + return None; + } + + // Otherwise, deref if type is derefable: + // NOTE: in the case of self.use_receiver_trait = true, you might think it would + // be better to skip this clause and use the Overloaded case only, since &T + // and &mut T implement Receiver. But built-in derefs apply equally to Receiver + // and Deref, and this has benefits for const and the emitted MIR. + let (kind, new_ty) = if let Some(ty) = + self.state.cur_ty.builtin_deref(self.table.db, self.include_raw_pointers) + { + debug_assert_eq!(ty, self.table.infer_ctxt.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if let TyKind::Alias(..) = ty.kind() { + let (normalized_ty, obligations) = structurally_normalize_ty(self.table, ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) + } else { + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; - self.steps.push(kind, &self.ty); - self.ty = new_ty; + self.state.steps.push(self.state.cur_ty, kind); + debug!( + "autoderef stage #{:?} is {:?} from {:?}", + self.step_count(), + new_ty, + (self.state.cur_ty, kind) + ); + self.state.cur_ty = new_ty; - Some((self.ty.clone(), self.step_count())) + Some((self.state.cur_ty, self.step_count())) } } -pub(crate) fn autoderef_step( - table: &mut InferenceTable<'_>, - ty: Ty, - explicit: bool, - use_receiver_trait: bool, -) -> Option<(AutoderefKind, Ty)> { - if let Some(derefed) = builtin_deref(table.db, &ty, explicit) { - Some((AutoderefKind::Builtin, table.structurally_resolve_type(derefed))) - } else { - Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?)) +impl<'a, 'db> Autoderef<'a, 'db> { + pub(crate) fn new(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self { + Self::new_impl(table, base_ty) } } -pub(crate) fn builtin_deref<'ty>( - db: &dyn HirDatabase, - ty: &'ty Ty, - explicit: bool, -) -> Option<&'ty Ty> { - match ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(ty), - TyKind::Raw(.., ty) if explicit => Some(ty), - &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) if crate::lang_items::is_box(db, adt) => { - substs.at(Interner, 0).ty(Interner) - } - _ => None, +impl<'a, 'db> Autoderef<'a, 'db, usize> { + pub(crate) fn new_no_tracking(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self { + Self::new_impl(table, base_ty) } } -pub(crate) fn deref_by_trait( - table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>, - ty: Ty, - use_receiver_trait: bool, -) -> Option { - let _p = tracing::info_span!("deref_by_trait").entered(); - if table.structurally_resolve_type(&ty).inference_var(Interner).is_some() { - // don't try to deref unknown variables - return None; +impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> { + fn new_impl(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self { + Autoderef { + state: AutoderefSnapshot { + steps: Steps::default(), + cur_ty: table.infer_ctxt.resolve_vars_if_possible(base_ty), + obligations: PredicateObligations::new(), + at_start: true, + reached_recursion_limit: false, + }, + table, + traits: None, + include_raw_pointers: false, + use_receiver_trait: false, + } } - let trait_id = || { - // FIXME: Remove the `false` once `Receiver` needs to be stabilized, doing so will - // effectively bump the MSRV of rust-analyzer to 1.84 due to 1.83 and below lacking the - // blanked impl on `Deref`. - #[expect(clippy::overly_complex_bool_expr)] - if use_receiver_trait - && false - && let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) - { - return Some(receiver); + fn autoderef_traits(&mut self) -> Option { + match &mut self.traits { + Some(it) => Some(*it), + None => { + let traits = if self.use_receiver_trait { + AutoderefTraits { + trait_target: LangItem::ReceiverTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate) + .or_else(|| { + LangItem::DerefTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate) + })?, + } + } else { + AutoderefTraits { + trait_target: LangItem::DerefTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, + } + }; + Some(*self.traits.insert(traits)) + } } - // Old rustc versions might not have `Receiver` trait. - // Fallback to `Deref` if they don't - LangItem::Deref.resolve_trait(db, table.trait_env.krate) - }; - let trait_id = trait_id()?; - let target = - trait_id.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Target))?; - - let projection = { - let b = TyBuilder::subst_for_def(db, trait_id, None); - if b.remaining() != 1 { - // the Target type + Deref trait should only have one generic parameter, - // namely Deref's Self type - return None; - } - let deref_subst = b.push(ty).build(); - TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build() - }; + } + + fn overloaded_deref_ty(&mut self, ty: Ty<'db>) -> Option> { + debug!("overloaded_deref_ty({:?})", ty); + let interner = self.table.interner; + + // , or whatever the equivalent trait is that we've been asked to walk. + let AutoderefTraits { trait_target } = self.autoderef_traits()?; + + let (normalized_ty, obligations) = structurally_normalize_ty( + self.table, + Ty::new_projection(interner, trait_target.into(), [ty]), + )?; + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); - // Check that the type implements Deref at all - let trait_ref = projection.trait_ref(db); - let implements_goal: Goal = trait_ref.cast(Interner); - if table.try_obligation(implements_goal.clone()).no_solution() { + Some(self.table.infer_ctxt.resolve_vars_if_possible(normalized_ty)) + } + + /// Returns the final type we ended up with, which may be an unresolved + /// inference variable. + pub(crate) fn final_ty(&self) -> Ty<'db> { + self.state.cur_ty + } + + pub(crate) fn step_count(&self) -> usize { + self.state.steps.len() + } + + pub(crate) fn take_obligations(&mut self) -> PredicateObligations<'db> { + std::mem::take(&mut self.state.obligations) + } + + pub(crate) fn steps(&self) -> &Steps { + &self.state.steps + } + + #[expect(dead_code)] + pub(crate) fn reached_recursion_limit(&self) -> bool { + self.state.reached_recursion_limit + } + + /// also dereference through raw pointer types + /// e.g., assuming ptr_to_Foo is the type `*const Foo` + /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] + /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] + pub(crate) fn include_raw_pointers(mut self) -> Self { + self.include_raw_pointers = true; + self + } + + /// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as + /// the trait and associated type to iterate, instead of + /// `core::ops::Deref` and `core::ops::Deref::Target` + pub(crate) fn use_receiver_trait(mut self) -> Self { + self.use_receiver_trait = true; + self + } +} + +fn structurally_normalize_ty<'db>( + table: &InferenceTable<'db>, + ty: Ty<'db>, +) -> Option<(Ty<'db>, PredicateObligations<'db>)> { + let mut ocx = ObligationCtxt::new(&table.infer_ctxt); + let Ok(normalized_ty) = + ocx.structurally_normalize_ty(&ObligationCause::misc(), table.param_env, ty) + else { + // We shouldn't have errors here in the old solver, except for + // evaluate/fulfill mismatches, but that's not a reason for an ICE. return None; + }; + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + unreachable!(); } - table.register_obligation(implements_goal.to_nextsolver(table.interner)); + Some((normalized_ty, ocx.into_pending_obligations())) +} + +pub(crate) fn overloaded_deref_ty<'db>( + table: &InferenceTable<'db>, + ty: Ty<'db>, +) -> Option>> { + let interner = table.interner; + + let trait_target = LangItem::DerefTarget.resolve_type_alias(table.db, table.trait_env.krate)?; + + let (normalized_ty, obligations) = + structurally_normalize_ty(table, Ty::new_projection(interner, trait_target.into(), [ty]))?; - let result = table.normalize_projection_ty(projection); - Some(table.structurally_resolve_type(&result)) + Some(InferOk { value: normalized_ty, obligations }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 8af8fb73f344e..3755175cf5163 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -1,16 +1,12 @@ //! `TyBuilder`, a helper for building instances of `Ty` and related types. -use std::iter; - use chalk_ir::{ AdtId, DebruijnIndex, Scalar, cast::{Cast, CastTo, Caster}, fold::TypeFoldable, interner::HasInterner, }; -use hir_def::{ - DefWithBodyId, GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType, -}; +use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType}; use smallvec::SmallVec; use crate::{ @@ -246,47 +242,6 @@ impl TyBuilder<()> { TyBuilder::new((), params, parent_subst) } - /// Creates a `TyBuilder` to build `Substitution` for a coroutine defined in `parent`. - /// - /// A coroutine's substitution consists of: - /// - resume type of coroutine - /// - yield type of coroutine ([`Coroutine::Yield`](std::ops::Coroutine::Yield)) - /// - return type of coroutine ([`Coroutine::Return`](std::ops::Coroutine::Return)) - /// - generic parameters in scope on `parent` - /// - /// in this order. - /// - /// This method prepopulates the builder with placeholder substitution of `parent`, so you - /// should only push exactly 3 `GenericArg`s before building. - pub fn subst_for_coroutine(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> { - let parent_subst = - parent.as_generic_def_id(db).map(|p| generics(db, p).placeholder_subst(db)); - // These represent resume type, yield type, and return type of coroutine. - let params = std::iter::repeat_n(ParamKind::Type, 3).collect(); - TyBuilder::new((), params, parent_subst) - } - - pub fn subst_for_closure( - db: &dyn HirDatabase, - parent: DefWithBodyId, - sig_ty: Ty, - ) -> Substitution { - let sig_ty = sig_ty.cast(Interner); - let self_subst = iter::once(&sig_ty); - let Some(parent) = parent.as_generic_def_id(db) else { - return Substitution::from_iter(Interner, self_subst); - }; - Substitution::from_iter( - Interner, - generics(db, parent) - .placeholder_subst(db) - .iter(Interner) - .chain(self_subst) - .cloned() - .collect::>(), - ) - } - pub fn build(self) -> Substitution { let ((), subst) = self.build_internal(); subst diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 9f0ea14a8063d..1faf9f66dc547 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -210,7 +210,7 @@ impl TyExt for Ty { match self.kind(Interner) { TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)), TyKind::FnDef(def, parameters) => Some(CallableSig::from_def(db, *def, parameters)), - TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty().callable_sig(db), + TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty(db).callable_sig(db), _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 0aec2b9dec7bc..448fc4aede037 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -283,6 +283,14 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: TyDefId, ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; + /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is + /// a `StructId` or `EnumVariantId` with a record constructor. + #[salsa::invoke(crate::lower_nextsolver::value_ty_query)] + fn value_ty_ns<'db>( + &'db self, + def: ValueTyDefId, + ) -> Option>>; + #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] fn type_for_type_alias_with_diagnostics_ns<'db>( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 64c4cdeaddf31..3f04b72c2fc68 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -14,6 +14,7 @@ use hir_def::{ }; use span::Edition; +use crate::utils::TargetFeatureIsSafeInTarget; use crate::{ InferenceResult, Interner, TargetFeatures, TyExt, TyKind, db::HirDatabase, @@ -147,7 +148,7 @@ struct UnsafeVisitor<'db> { edition: Edition, /// On some targets (WASM), calling safe functions with `#[target_feature]` is always safe, even when /// the target feature is not enabled. This flag encodes that. - target_feature_is_safe: bool, + target_feature_is_safe: TargetFeatureIsSafeInTarget, } impl<'db> UnsafeVisitor<'db> { @@ -167,7 +168,7 @@ impl<'db> UnsafeVisitor<'db> { let edition = krate.data(db).edition; let target_feature_is_safe = match &krate.workspace_data(db).target { Ok(target) => target_feature_is_safe_in_target(target), - Err(_) => false, + Err(_) => TargetFeatureIsSafeInTarget::No, }; Self { db, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index ea8bdf8bcbae4..7418e3bbeb49d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -38,14 +38,16 @@ use rustc_apfloat::{ }; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, RegionKind, - inherent::{AdtDef, IntoKind, SliceLike}, + AliasTyKind, CoroutineArgsParts, RegionKind, + inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike}, }; use smallvec::SmallVec; use span::Edition; use stdx::never; use triomphe::Arc; +use crate::next_solver::infer::DbInternerInferExt; +use crate::next_solver::infer::traits::ObligationCause; use crate::{ AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, @@ -789,11 +791,11 @@ fn render_const_scalar_ns( ) -> Result<(), HirDisplayError> { let trait_env = TraitEnvironment::empty(f.krate()); let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); - let ty = crate::next_solver::project::solve_normalize::normalize( - interner, - trait_env.env.to_nextsolver(interner), - ty, - ); + let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis); + let ty = infcx + .at(&ObligationCause::new(), trait_env.env.to_nextsolver(interner)) + .deeply_normalize(ty) + .unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, trait_env) } @@ -1556,7 +1558,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } _ => (), } - let sig = ClosureSubst(&substs).sig_ty().callable_sig(db); + let sig = ClosureSubst(&substs).sig_ty(db).callable_sig(db); if let Some(sig) = sig { let InternedClosure(def, _) = db.lookup_intern_closure(id); let infer = db.infer(def); @@ -1696,26 +1698,17 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { DisplaySourceCodeError::Coroutine, )); } - let subst = convert_args_for_result(interner, subst.as_slice()); - let subst = subst.as_slice(Interner); - let a: Option> = subst - .get(subst.len() - 3..) - .and_then(|args| args.iter().map(|arg| arg.ty(Interner)).collect()); + let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = + subst.split_coroutine_args(); + write!(f, "|")?; + resume_ty.hir_fmt(f)?; + write!(f, "|")?; - if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() { - write!(f, "|")?; - resume_ty.hir_fmt(f)?; - write!(f, "|")?; + write!(f, " yields ")?; + yield_ty.hir_fmt(f)?; - write!(f, " yields ")?; - yield_ty.hir_fmt(f)?; - - write!(f, " -> ")?; - ret_ty.hir_fmt(f)?; - } else { - // This *should* be unreachable, but fallback just in case. - write!(f, "{{coroutine}}")?; - } + write!(f, " -> ")?; + return_ty.hir_fmt(f)?; } TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?, TyKind::Pat(_, _) => write!(f, "{{pat}}")?, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index a7e942d92442c..f5c2f41069ea0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -120,7 +120,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc Arc { @@ -159,7 +164,7 @@ pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc, let mut table = unify::InferenceTable::new(db, trait_env); let ty_with_vars = table.normalize_associated_types_in(ty); - table.resolve_obligations_as_possible(); + table.select_obligations_where_possible(); table.propagate_diverging_flag(); table.resolve_completely(ty_with_vars) } @@ -183,18 +188,14 @@ impl BindingMode { } } +// FIXME: Remove this `InferOk`, switch all code to the second one, that uses `Obligation` instead of `Goal`. #[derive(Debug)] pub(crate) struct InferOk<'db, T> { + #[allow(dead_code)] value: T, goals: Vec>>, } -impl<'db, T> InferOk<'db, T> { - fn map(self, f: impl FnOnce(T) -> U) -> InferOk<'db, U> { - InferOk { value: f(self.value), goals: self.goals } - } -} - #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum InferenceTyDiagnosticSource { /// Diagnostics that come from types in the body. @@ -378,6 +379,26 @@ impl Adjustment { } } +/// At least for initial deployment, we want to limit two-phase borrows to +/// only a few specific cases. Right now, those are mostly "things that desugar" +/// into method calls: +/// - using `x.some_method()` syntax, where some_method takes `&mut self`, +/// - using `Foo::some_method(&mut x, ...)` syntax, +/// - binary assignment operators (`+=`, `-=`, `*=`, etc.). +/// +/// Anything else should be rejected until generalized two-phase borrow support +/// is implemented. Right now, dataflow can't handle the general case where there +/// is more than one use of a mutable borrow, and we don't want to accept too much +/// new code via two-phase borrows, so we try to limit where we create two-phase +/// capable mutable borrows. +/// See #49434 for tracking. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) enum AllowTwoPhase { + // FIXME: We should use this when appropriate. + Yes, + No, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Adjust { /// Go from ! to any type. @@ -393,8 +414,6 @@ pub enum Adjust { /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. /// The target type is `U` in both cases, with the region and mutability /// being those shared by both the receiver and the returned reference. -/// -/// Mutability is `None` when we are not sure. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct OverloadedDeref(pub Option); @@ -656,6 +675,7 @@ pub(crate) struct InferenceContext<'db> { /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext /// and resolve the path via its methods. This will ensure proper error reporting. pub(crate) resolver: Resolver<'db>, + target_features: OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>, generic_def: GenericDefId, generics: OnceCell, table: unify::InferenceTable<'db>, @@ -673,11 +693,11 @@ pub(crate) struct InferenceContext<'db> { /// If `Some`, this stores coercion information for returned /// expressions. If `None`, this is in a context where return is /// inappropriate, such as a const expression. - return_coercion: Option, + return_coercion: Option>, /// The resume type and the yield type, respectively, of the coroutine being inferred. resume_yield_tys: Option<(Ty, Ty)>, diverges: Diverges, - breakables: Vec, + breakables: Vec>, /// Whether we are inside the pattern of a destructuring assignment. inside_assignment: bool, @@ -692,21 +712,21 @@ pub(crate) struct InferenceContext<'db> { /// We do that because sometimes we truncate projections (when a closure captures /// both `a.b` and `a.b.c`), and we want to provide accurate spans in this case. current_capture_span_stack: Vec, - current_closure: Option, + current_closure: Option, /// Stores the list of closure ids that need to be analyzed before this closure. See the /// comment on `InferenceContext::sort_closures` - closure_dependencies: FxHashMap>, - deferred_closures: FxHashMap, ExprId)>>, + closure_dependencies: FxHashMap>, + deferred_closures: FxHashMap, ExprId)>>, diagnostics: Diagnostics, } #[derive(Clone, Debug)] -struct BreakableContext { +struct BreakableContext<'db> { /// Whether this context contains at least one break expression. may_break: bool, /// The coercion target of the context. - coerce: Option, + coerce: Option>, /// The optional label of the context. label: Option, kind: BreakableKind, @@ -721,10 +741,10 @@ enum BreakableKind { Border, } -fn find_breakable( - ctxs: &mut [BreakableContext], +fn find_breakable<'a, 'db>( + ctxs: &'a mut [BreakableContext<'db>], label: Option, -) -> Option<&mut BreakableContext> { +) -> Option<&'a mut BreakableContext<'db>> { let mut ctxs = ctxs .iter_mut() .rev() @@ -735,10 +755,10 @@ fn find_breakable( } } -fn find_continuable( - ctxs: &mut [BreakableContext], +fn find_continuable<'a, 'db>( + ctxs: &'a mut [BreakableContext<'db>], label: Option, -) -> Option<&mut BreakableContext> { +) -> Option<&'a mut BreakableContext<'db>> { match label { Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)), None => find_breakable(ctxs, label), @@ -759,6 +779,7 @@ impl<'db> InferenceContext<'db> { ) -> Self { let trait_env = db.trait_environment_for_body(owner); InferenceContext { + target_features: OnceCell::new(), generics: OnceCell::new(), result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), @@ -794,18 +815,56 @@ impl<'db> InferenceContext<'db> { self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def)) } + #[inline] + fn krate(&self) -> Crate { + self.resolver.krate() + } + + fn target_features<'a>( + db: &dyn HirDatabase, + target_features: &'a OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>, + owner: DefWithBodyId, + krate: Crate, + ) -> (&'a TargetFeatures, TargetFeatureIsSafeInTarget) { + let (target_features, target_feature_is_safe) = target_features.get_or_init(|| { + let target_features = match owner { + DefWithBodyId::FunctionId(id) => TargetFeatures::from_attrs(&db.attrs(id.into())), + _ => TargetFeatures::default(), + }; + let target_feature_is_safe = match &krate.workspace_data(db).target { + Ok(target) => crate::utils::target_feature_is_safe_in_target(target), + Err(_) => TargetFeatureIsSafeInTarget::No, + }; + (target_features, target_feature_is_safe) + }); + (target_features, *target_feature_is_safe) + } + + #[inline] + pub(crate) fn set_tainted_by_errors(&mut self) { + self.result.has_errors = true; + } + // FIXME: This function should be private in module. It is currently only used in the consteval, since we need // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you // used this function for another workaround, mention it here. If you really need this function and believe that // there is no problem in it being `pub(crate)`, remove this comment. - pub(crate) fn resolve_all(self) -> InferenceResult { + pub(crate) fn resolve_all(mut self) -> InferenceResult { + self.table.select_obligations_where_possible(); + self.table.fallback_if_possible(); + + // Comment from rustc: + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + let cast_checks = std::mem::take(&mut self.deferred_cast_checks); + for mut cast in cast_checks.into_iter() { + if let Err(diag) = cast.check(&mut self) { + self.diagnostics.push(diag); + } + } + let InferenceContext { - mut table, - mut result, - mut deferred_cast_checks, - tuple_field_accesses_rev, - diagnostics, - .. + mut table, mut result, tuple_field_accesses_rev, diagnostics, .. } = self; let mut diagnostics = diagnostics.finish(); // Destructure every single field so whenever new fields are added to `InferenceResult` we @@ -831,31 +890,12 @@ impl<'db> InferenceContext<'db> { closure_info: _, mutated_bindings_in_closure: _, tuple_field_access_types: _, - coercion_casts, + coercion_casts: _, diagnostics: _, } = &mut result; - table.resolve_obligations_as_possible(); - table.fallback_if_possible(); - - // Comment from rustc: - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - let mut apply_adjustments = |expr, adj: Vec<_>| { - expr_adjustments.insert(expr, adj.into_boxed_slice()); - }; - let mut set_coercion_cast = |expr| { - coercion_casts.insert(expr); - }; - for cast in deferred_cast_checks.iter_mut() { - if let Err(diag) = - cast.check(&mut table, &mut apply_adjustments, &mut set_coercion_cast) - { - diagnostics.push(diag); - } - } // FIXME resolve obligations as well (use Guidance if necessary) - table.resolve_obligations_as_possible(); + table.select_obligations_where_possible(); // make sure diverging type variables are marked as such table.propagate_diverging_flag(); @@ -1081,7 +1121,8 @@ impl<'db> InferenceContext<'db> { }; self.return_ty = self.process_user_written_ty(return_ty); - self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); + self.return_coercion = + Some(CoerceMany::new(self.return_ty.to_nextsolver(self.table.interner))); // Functions might be defining usage sites of TAITs. // To define an TAITs, that TAIT must appear in the function's signatures. @@ -1117,8 +1158,12 @@ impl<'db> InferenceContext<'db> { fold_tys( t, |ty, _| { + let ty = self.table.structurally_resolve_type(&ty); let opaque_ty_id = match ty.kind(Interner) { - TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, + TyKind::OpaqueType(opaque_ty_id, _) + | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id, .. })) => { + *opaque_ty_id + } _ => return ty, }; let (impl_traits, idx) = @@ -1214,9 +1259,11 @@ impl<'db> InferenceContext<'db> { ty: &chalk_ir::Ty, outer_binder: DebruijnIndex, ) -> std::ops::ControlFlow { - let ty = self.table.resolve_ty_shallow(ty); + let ty = self.table.structurally_resolve_type(ty); - if let TyKind::OpaqueType(id, _) = ty.kind(Interner) + if let TyKind::OpaqueType(id, _) + | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id: id, .. })) = + ty.kind(Interner) && let ImplTraitId::TypeAliasImplTrait(alias_id, _) = self.db.lookup_intern_impl_trait_id((*id).into()) { @@ -1361,6 +1408,13 @@ impl<'db> InferenceContext<'db> { } } + fn write_pat_adj(&mut self, pat: PatId, adjustments: Box<[Ty]>) { + if adjustments.is_empty() { + return; + } + self.result.pat_adjustments.entry(pat).or_default().extend(adjustments); + } + fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { self.result.method_resolutions.insert(expr, (func, subst)); } @@ -1587,24 +1641,14 @@ impl<'db> InferenceContext<'db> { self.table.process_remote_user_written_ty(ty) } - /// Recurses through the given type, normalizing associated types mentioned - /// in it by replacing them by type variables and registering obligations to - /// resolve later. This should be done once for every type we get from some - /// type annotation (e.g. from a let type annotation, field type or function - /// call). `make_ty` handles this already, but e.g. for field types we need - /// to do it as well. - fn normalize_associated_types_in(&mut self, ty: T) -> T - where - T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, - U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, - { - self.table.normalize_associated_types_in(ty) - } - fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { self.table.resolve_ty_shallow(ty) } + fn shallow_resolve(&self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> { + self.table.shallow_resolve(ty) + } + fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option) -> Ty { self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs new file mode 100644 index 0000000000000..77b1ae6a94a46 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs @@ -0,0 +1,54 @@ +//! Autoderef helpers for inference. + +use std::iter; + +use crate::{ + Adjust, Adjustment, OverloadedDeref, + autoderef::{Autoderef, AutoderefKind}, + infer::unify::InferenceTable, + next_solver::{ + Ty, + infer::{InferOk, traits::PredicateObligations}, + mapping::NextSolverToChalk, + }, +}; + +impl<'db> InferenceTable<'db> { + pub(crate) fn autoderef(&mut self, base_ty: Ty<'db>) -> Autoderef<'_, 'db> { + Autoderef::new(self, base_ty) + } +} + +impl<'db> Autoderef<'_, 'db> { + /// Returns the adjustment steps. + pub(crate) fn adjust_steps(mut self) -> Vec { + let infer_ok = self.adjust_steps_as_infer_ok(); + self.table.register_infer_ok(infer_ok) + } + + pub(crate) fn adjust_steps_as_infer_ok(&mut self) -> InferOk<'db, Vec> { + let steps = self.steps(); + if steps.is_empty() { + return InferOk { obligations: PredicateObligations::new(), value: vec![] }; + } + + let targets = steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.final_ty())); + let steps: Vec<_> = steps + .iter() + .map(|&(_source, kind)| { + if let AutoderefKind::Overloaded = kind { + Some(OverloadedDeref(Some(chalk_ir::Mutability::Not))) + } else { + None + } + }) + .zip(targets) + .map(|(autoderef, target)| Adjustment { + kind: Adjust::Deref(autoderef), + target: target.to_chalk(self.table.interner), + }) + .collect(); + + InferOk { obligations: self.take_obligations(), value: steps } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index bc3ee3c4c54d9..4cd6144a14cba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -4,12 +4,14 @@ use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy}; use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags}; use stdx::never; +use crate::infer::coerce::CoerceNever; use crate::{ - Adjustment, Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, - QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, + Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, QuantifiedWhereClauses, Ty, + TyExt, TyKind, TypeFlags, WhereClause, db::HirDatabase, from_chalk_trait_id, - infer::{coerce::CoerceNever, unify::InferenceTable}, + infer::{AllowTwoPhase, InferenceContext}, + next_solver::mapping::ChalkToNextSolver, }; #[derive(Debug)] @@ -93,23 +95,25 @@ impl CastCheck { Self { expr, source_expr, expr_ty, cast_ty } } - pub(super) fn check( + pub(super) fn check( &mut self, - table: &mut InferenceTable<'_>, - apply_adjustments: &mut F, - set_coercion_cast: &mut G, - ) -> Result<(), InferenceDiagnostic> - where - F: FnMut(ExprId, Vec), - G: FnMut(ExprId), - { - self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone()); - self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone()); + ctx: &mut InferenceContext<'_>, + ) -> Result<(), InferenceDiagnostic> { + self.expr_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone()); + self.cast_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone()); // This should always come first so that we apply the coercion, which impacts infer vars. - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty, CoerceNever::Yes) { - apply_adjustments(self.source_expr, adj); - set_coercion_cast(self.source_expr); + if ctx + .coerce( + self.source_expr.into(), + self.expr_ty.to_nextsolver(ctx.table.interner), + self.cast_ty.to_nextsolver(ctx.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .is_ok() + { + ctx.result.coercion_casts.insert(self.source_expr); return Ok(()); } @@ -118,7 +122,7 @@ impl CastCheck { } if !self.cast_ty.data(Interner).flags.contains(TypeFlags::HAS_TY_INFER) - && !table.is_sized(&self.cast_ty) + && !ctx.table.is_sized(&self.cast_ty) { return Err(InferenceDiagnostic::CastToUnsized { expr: self.expr, @@ -133,30 +137,31 @@ impl CastCheck { return Ok(()); } - self.do_check(table, apply_adjustments) + self.do_check(ctx) .map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone())) } - fn do_check( - &self, - table: &mut InferenceTable<'_>, - apply_adjustments: &mut F, - ) -> Result<(), CastError> - where - F: FnMut(ExprId, Vec), - { + fn do_check(&self, ctx: &mut InferenceContext<'_>) -> Result<(), CastError> { let (t_from, t_cast) = match ( - CastTy::from_ty(table.db, &self.expr_ty), - CastTy::from_ty(table.db, &self.cast_ty), + CastTy::from_ty(ctx.db, &self.expr_ty), + CastTy::from_ty(ctx.db, &self.cast_ty), ) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), (None, Some(t_cast)) => match self.expr_ty.kind(Interner) { TyKind::FnDef(..) => { - let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig"); - let sig = table.eagerly_normalize_and_resolve_shallow_in(sig); + let sig = self.expr_ty.callable_sig(ctx.db).expect("FnDef had no sig"); + let sig = ctx.table.eagerly_normalize_and_resolve_shallow_in(sig); let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner); - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes) { - apply_adjustments(self.source_expr, adj); + if ctx + .coerce( + self.source_expr.into(), + self.expr_ty.to_nextsolver(ctx.table.interner), + fn_ptr.to_nextsolver(ctx.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .is_ok() + { } else { return Err(CastError::IllegalCast); } @@ -176,11 +181,11 @@ impl CastCheck { }, // array-ptr-cast CastTy::Ptr(t, m) => { - let t = table.eagerly_normalize_and_resolve_shallow_in(t); - if !table.is_sized(&t) { + let t = ctx.table.eagerly_normalize_and_resolve_shallow_in(t); + if !ctx.table.is_sized(&t) { return Err(CastError::IllegalCast); } - self.check_ref_cast(table, inner_ty, *mutbl, &t, m, apply_adjustments) + self.check_ref_cast(ctx, inner_ty, *mutbl, &t, m) } _ => Err(CastError::NonScalar), }; @@ -202,12 +207,10 @@ impl CastCheck { } (CastTy::Int(Int::Bool | Int::CEnum | Int::Char) | CastTy::Float, CastTy::Ptr(..)) | (CastTy::Ptr(..) | CastTy::FnPtr, CastTy::Float) => Err(CastError::IllegalCast), - (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => { - self.check_ptr_ptr_cast(table, &src, &dst) - } - (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(table, &src), - (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(table, &dst), - (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(table, &dst), + (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => self.check_ptr_ptr_cast(ctx, &src, &dst), + (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(ctx, &src), + (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(ctx, &dst), + (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(ctx, &dst), (CastTy::Int(Int::CEnum), CastTy::Int(_)) => Ok(()), (CastTy::Int(Int::Char | Int::Bool), CastTy::Int(_)) => Ok(()), (CastTy::Int(_) | CastTy::Float, CastTy::Int(_) | CastTy::Float) => Ok(()), @@ -215,26 +218,30 @@ impl CastCheck { } } - fn check_ref_cast( + fn check_ref_cast( &self, - table: &mut InferenceTable<'_>, + ctx: &mut InferenceContext<'_>, t_expr: &Ty, m_expr: Mutability, t_cast: &Ty, m_cast: Mutability, - apply_adjustments: &mut F, - ) -> Result<(), CastError> - where - F: FnMut(ExprId, Vec), - { + ) -> Result<(), CastError> { // Mutability order is opposite to rustc. `Mut < Not` if m_expr <= m_cast && let TyKind::Array(ety, _) = t_expr.kind(Interner) { // Coerce to a raw pointer so that we generate RawPtr in MIR. let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner); - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes) { - apply_adjustments(self.source_expr, adj); + if ctx + .coerce( + self.source_expr.into(), + self.expr_ty.to_nextsolver(ctx.table.interner), + array_ptr_type.to_nextsolver(ctx.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .is_ok() + { } else { never!( "could not cast from reference to array to pointer to array ({:?} to {:?})", @@ -245,7 +252,16 @@ impl CastCheck { // This is a less strict condition than rustc's `demand_eqtype`, // but false negative is better than false positive - if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() { + if ctx + .coerce( + self.source_expr.into(), + ety.to_nextsolver(ctx.table.interner), + t_cast.to_nextsolver(ctx.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .is_ok() + { return Ok(()); } } @@ -255,12 +271,12 @@ impl CastCheck { fn check_ptr_ptr_cast( &self, - table: &mut InferenceTable<'_>, + ctx: &mut InferenceContext<'_>, src: &Ty, dst: &Ty, ) -> Result<(), CastError> { - let src_kind = pointer_kind(src, table).map_err(|_| CastError::Unknown)?; - let dst_kind = pointer_kind(dst, table).map_err(|_| CastError::Unknown)?; + let src_kind = pointer_kind(src, ctx).map_err(|_| CastError::Unknown)?; + let dst_kind = pointer_kind(dst, ctx).map_err(|_| CastError::Unknown)?; match (src_kind, dst_kind) { (Some(PointerKind::Error), _) | (_, Some(PointerKind::Error)) => Ok(()), @@ -285,9 +301,9 @@ impl CastCheck { return Ok(()); } let src_principal = - table.db.trait_signature(from_chalk_trait_id(src_principal)); + ctx.db.trait_signature(from_chalk_trait_id(src_principal)); let dst_principal = - table.db.trait_signature(from_chalk_trait_id(dst_principal)); + ctx.db.trait_signature(from_chalk_trait_id(dst_principal)); if src_principal.flags.contains(TraitFlags::AUTO) && dst_principal.flags.contains(TraitFlags::AUTO) { @@ -306,10 +322,10 @@ impl CastCheck { fn check_ptr_addr_cast( &self, - table: &mut InferenceTable<'_>, + ctx: &mut InferenceContext<'_>, expr_ty: &Ty, ) -> Result<(), CastError> { - match pointer_kind(expr_ty, table).map_err(|_| CastError::Unknown)? { + match pointer_kind(expr_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownExprPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -320,10 +336,10 @@ impl CastCheck { fn check_addr_ptr_cast( &self, - table: &mut InferenceTable<'_>, + ctx: &mut InferenceContext<'_>, cast_ty: &Ty, ) -> Result<(), CastError> { - match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? { + match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -336,10 +352,10 @@ impl CastCheck { fn check_fptr_ptr_cast( &self, - table: &mut InferenceTable<'_>, + ctx: &mut InferenceContext<'_>, cast_ty: &Ty, ) -> Result<(), CastError> { - match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? { + match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), None => Ok(()), Some(PointerKind::Error) => Ok(()), @@ -362,10 +378,10 @@ enum PointerKind { Error, } -fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result, ()> { - let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone()); +fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result, ()> { + let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty.clone()); - if table.is_sized(&ty) { + if ctx.table.is_sized(&ty) { return Ok(Some(PointerKind::Thin)); } @@ -378,11 +394,11 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result) -> Result { match subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) { None => Ok(Some(PointerKind::Thin)), - Some(ty) => pointer_kind(ty, table), + Some(ty) => pointer_kind(ty, ctx), } } TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index fd7e5a6a0e121..1d5d8dd13edd4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -1,143 +1,168 @@ //! Inference of closure parameter types based on the closure's expected type. -use std::{cmp, convert::Infallible, mem, ops::ControlFlow}; +pub(crate) mod analysis; + +use std::ops::ControlFlow; +use std::{iter, mem}; -use chalk_ir::{ - BoundVar, DebruijnIndex, FnSubst, GenericArg, Mutability, TyKind, - cast::Cast, - fold::{FallibleTypeFolder, Shift, TypeFoldable}, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; -use either::Either; use hir_def::{ - DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, - expr_store::path::Path, - hir::{ - Array, AsmOperand, BinaryOp, BindingId, CaptureBy, ClosureKind, Expr, ExprId, ExprOrPatId, - Pat, PatId, Statement, UnaryOp, - }, - item_tree::FieldsShape, + TraitId, + hir::{ClosureKind, ExprId, PatId}, lang_item::LangItem, - resolver::ValueNs, type_ref::TypeRefId, }; -use hir_def::{ItemContainerId, Lookup, TraitId}; -use hir_expand::name::Name; -use intern::sym; -use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::{SmallVec, smallvec}; -use stdx::{format_to, never}; -use syntax::utils::is_raw_identifier; +use rustc_type_ir::{ + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, + inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _}, +}; +use tracing::debug; +use crate::traits::FnTrait; use crate::{ - Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ClosureId, DynTy, DynTyExt, FnAbi, - FnPointer, FnSig, Interner, OpaqueTy, ProjectionTy, ProjectionTyExt, Substitution, Ty, - TyBuilder, TyExt, WhereClause, - db::{HirDatabase, InternedClosure, InternedCoroutine}, - error_lifetime, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx, - generics::Generics, - infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever}, - make_binders, - mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, - next_solver::mapping::ChalkToNextSolver, - to_assoc_type_id, - traits::FnTrait, - utils::{self, elaborate_clause_supertraits}, + FnAbi, + db::{InternedClosure, InternedCoroutine}, + infer::{BreakableKind, Diverges, coerce::CoerceMany}, + next_solver::{ + AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, + PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind, + abi::Safety, + infer::{ + BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult, + traits::{ObligationCause, PredicateObligations}, + }, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + util::explicit_item_bounds, + }, }; use super::{Expectation, InferenceContext}; #[derive(Debug)] -pub(super) struct ClosureSignature { - pub(super) ret_ty: Ty, - pub(super) expected_sig: FnPointer, +struct ClosureSignatures<'tcx> { + /// The signature users of the closure see. + bound_sig: PolyFnSig<'tcx>, + /// The signature within the function body. + /// This mostly differs in the sense that lifetimes are now early bound and any + /// opaque types from the signature expectation are overridden in case there are + /// explicit hidden types written by the user in the closure signature. + liberated_sig: FnSig<'tcx>, } impl<'db> InferenceContext<'db> { pub(super) fn infer_closure( &mut self, - body: &ExprId, + body: ExprId, args: &[PatId], - ret_type: &Option, + ret_type: Option, arg_types: &[Option], closure_kind: ClosureKind, tgt_expr: ExprId, expected: &Expectation, - ) -> Ty { + ) -> crate::Ty { assert_eq!(args.len(), arg_types.len()); + let interner = self.table.interner; let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) { - Some(expected_ty) => self.deduce_closure_signature(&expected_ty, closure_kind), + Some(expected_ty) => { + self.deduce_closure_signature(expected_ty.to_nextsolver(interner), closure_kind) + } None => (None, None), }; - let ClosureSignature { expected_sig: mut bound_sig, ret_ty: body_ret_ty } = - self.sig_of_closure(body, ret_type, arg_types, closure_kind, expected_sig); - bound_sig.substitution.0 = self - .normalize_associated_types_in::<_, crate::next_solver::GenericArgs<'db>>( - bound_sig.substitution.0, - ); - let bound_sig = bound_sig; - let sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner); + let ClosureSignatures { bound_sig, liberated_sig } = + self.sig_of_closure(arg_types, ret_type, expected_sig); + let body_ret_ty = bound_sig.output().skip_binder(); + let sig_ty = Ty::new_fn_ptr(interner, bound_sig); + let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into()); let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Coroutine(_) => { - let sig_tys = bound_sig.substitution.0.as_slice(Interner); - // FIXME: report error when there are more than 1 parameter. - let resume_ty = match sig_tys.first() { - // When `sig_tys.len() == 1` the first type is the return type, not the - // first parameter type. - Some(ty) if sig_tys.len() > 1 => ty.assert_ty_ref(Interner).clone(), - _ => self.result.standard_types.unit.clone(), + let yield_ty = self.table.next_ty_var(); + let resume_ty = liberated_sig + .inputs() + .get(0) + .unwrap_or(self.result.standard_types.unit.to_nextsolver(interner)); + + // FIXME: Infer the upvars later. + let parts = CoroutineArgsParts { + parent_args, + kind_ty: Ty::new_unit(interner), + resume_ty, + yield_ty, + return_ty: body_ret_ty, + tupled_upvars_ty: Ty::new_unit(interner), }; - let yield_ty = self.table.new_type_var(); - - let subst = TyBuilder::subst_for_coroutine(self.db, self.owner) - .push(resume_ty.clone()) - .push(yield_ty.clone()) - .push(body_ret_ty.clone()) - .build(); let coroutine_id = self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into(); - let coroutine_ty = TyKind::Coroutine(coroutine_id, subst).intern(Interner); + let coroutine_ty = Ty::new_coroutine( + interner, + coroutine_id, + CoroutineArgs::new(interner, parts).args, + ); - (None, coroutine_ty, Some((resume_ty, yield_ty))) + ( + None, + coroutine_ty, + Some((resume_ty.to_chalk(interner), yield_ty.to_chalk(interner))), + ) } + // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`. + // But for now we treat it as a closure. ClosureKind::Closure | ClosureKind::Async => { - let closure_id = - self.db.intern_closure(InternedClosure(self.owner, tgt_expr)).into(); - let closure_ty = TyKind::Closure( - closure_id, - TyBuilder::subst_for_closure(self.db, self.owner, sig_ty.clone()), - ) - .intern(Interner); + let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr)); + match expected_kind { + Some(kind) => { + self.result.closure_info.insert( + closure_id.into(), + ( + Vec::new(), + match kind { + rustc_type_ir::ClosureKind::Fn => FnTrait::Fn, + rustc_type_ir::ClosureKind::FnMut => FnTrait::FnMut, + rustc_type_ir::ClosureKind::FnOnce => FnTrait::FnOnce, + }, + ), + ); + } + None => {} + }; + // FIXME: Infer the kind and the upvars later when needed. + let parts = ClosureArgsParts { + parent_args, + closure_kind_ty: Ty::from_closure_kind( + interner, + expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), + ), + closure_sig_as_fn_ptr_ty: sig_ty, + tupled_upvars_ty: Ty::new_unit(interner), + }; + let closure_ty = Ty::new_closure( + interner, + closure_id.into(), + ClosureArgs::new(interner, parts).args, + ); self.deferred_closures.entry(closure_id).or_default(); self.add_current_closure_dependency(closure_id); (Some(closure_id), closure_ty, None) } }; - // Eagerly try to relate the closure type with the expected - // type, otherwise we often won't have enough information to - // infer the body. - self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected, expected_kind); - // Now go through the argument patterns - for (arg_pat, arg_ty) in args.iter().zip(bound_sig.substitution.0.as_slice(Interner).iter()) - { - self.infer_top_pat(*arg_pat, arg_ty.assert_ty_ref(Interner), None); + for (arg_pat, arg_ty) in args.iter().zip(bound_sig.skip_binder().inputs()) { + self.infer_top_pat(*arg_pat, &arg_ty.to_chalk(interner), None); } // FIXME: lift these out into a struct let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_closure = mem::replace(&mut self.current_closure, id); - let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty.clone()); + let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty.to_chalk(interner)); let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty)); let prev_resume_yield_tys = mem::replace(&mut self.resume_yield_tys, resume_yield_tys); self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { - this.infer_return(*body); + this.infer_return(body); }); self.diverges = prev_diverges; @@ -146,1696 +171,644 @@ impl<'db> InferenceContext<'db> { self.current_closure = prev_closure; self.resume_yield_tys = prev_resume_yield_tys; - self.table.normalize_associated_types_in(ty) + ty.to_chalk(interner) } - // This function handles both closures and coroutines. - pub(super) fn deduce_closure_type_from_expectations( - &mut self, - closure_expr: ExprId, - closure_ty: &Ty, - sig_ty: &Ty, - expectation: &Expectation, - expected_kind: Option, - ) { - let expected_ty = match expectation.to_option(&mut self.table) { - Some(ty) => ty, - None => return, - }; - - match (closure_ty.kind(Interner), expected_kind) { - (TyKind::Closure(closure_id, _), Some(closure_kind)) => { - self.result - .closure_info - .entry(*closure_id) - .or_insert_with(|| (Vec::new(), closure_kind)); - } - _ => {} - } - - // Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here. - let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty, CoerceNever::Yes); - - // Coroutines are not Fn* so return early. - if matches!(closure_ty.kind(Interner), TyKind::Coroutine(..)) { - return; + fn fn_trait_kind_from_def_id(&self, trait_id: TraitId) -> Option { + let lang_item = self.db.lang_attr(trait_id.into())?; + match lang_item { + LangItem::Fn => Some(rustc_type_ir::ClosureKind::Fn), + LangItem::FnMut => Some(rustc_type_ir::ClosureKind::FnMut), + LangItem::FnOnce => Some(rustc_type_ir::ClosureKind::FnOnce), + _ => None, } + } - // Deduction based on the expected `dyn Fn` is done separately. - if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) - && let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) - { - let expected_sig_ty = TyKind::Function(sig).intern(Interner); - - self.unify(sig_ty, &expected_sig_ty); + fn async_fn_trait_kind_from_def_id( + &self, + trait_id: TraitId, + ) -> Option { + let lang_item = self.db.lang_attr(trait_id.into())?; + match lang_item { + LangItem::AsyncFn => Some(rustc_type_ir::ClosureKind::Fn), + LangItem::AsyncFnMut => Some(rustc_type_ir::ClosureKind::FnMut), + LangItem::AsyncFnOnce => Some(rustc_type_ir::ClosureKind::FnOnce), + _ => None, } } - // Closure kind deductions are mostly from `rustc_hir_typeck/src/closure.rs`. - // Might need to port closure sig deductions too. - pub(super) fn deduce_closure_signature( + /// Given the expected type, figures out what it can about this closure we + /// are about to type check: + fn deduce_closure_signature( &mut self, - expected_ty: &Ty, + expected_ty: Ty<'db>, closure_kind: ClosureKind, - ) -> (Option>, Option) { - match expected_ty.kind(Interner) { - TyKind::Alias(AliasTy::Opaque(OpaqueTy { .. })) | TyKind::OpaqueType(..) => { - let clauses = expected_ty.impl_trait_bounds(self.db).into_iter().flatten().map( - |b: chalk_ir::Binders>| { - b.into_value_and_skipped_binders().0 - }, - ); - self.deduce_closure_kind_from_predicate_clauses(expected_ty, clauses, closure_kind) - } - TyKind::Dyn(dyn_ty) => { - let sig = - dyn_ty.bounds.skip_binders().as_slice(Interner).iter().find_map(|bound| { - if let WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection_ty), - ty: projected_ty, - }) = bound.skip_binders() - && let Some(sig) = self.deduce_sig_from_projection( - closure_kind, - projection_ty, - projected_ty, - ) - { - return Some(sig); - } - None - }); - - let kind = dyn_ty.principal().and_then(|principal_trait_ref| { - self.fn_trait_kind_from_trait_id(from_chalk_trait_id( - principal_trait_ref.skip_binders().skip_binders().trait_id, - )) + ) -> (Option>, Option) { + match expected_ty.kind() { + TyKind::Alias(rustc_type_ir::Opaque, AliasTy { def_id, args, .. }) => self + .deduce_closure_signature_from_predicates( + expected_ty, + closure_kind, + explicit_item_bounds(self.table.interner, def_id) + .iter_instantiated(self.table.interner, args) + .map(|clause| clause.as_predicate()), + ), + TyKind::Dynamic(object_type, ..) => { + let sig = object_type.projection_bounds().into_iter().find_map(|pb| { + let pb = + pb.with_self_ty(self.table.interner, Ty::new_unit(self.table.interner)); + self.deduce_sig_from_projection(closure_kind, pb) }); - + let kind = object_type + .principal_def_id() + .and_then(|did| self.fn_trait_kind_from_def_id(did.0)); (sig, kind) } - TyKind::InferenceVar(ty, chalk_ir::TyVariableKind::General) => { - let clauses = self.clauses_for_self_ty(*ty); - self.deduce_closure_kind_from_predicate_clauses( - expected_ty, - clauses.into_iter(), + TyKind::Infer(rustc_type_ir::TyVar(vid)) => self + .deduce_closure_signature_from_predicates( + Ty::new_var(self.table.interner, self.table.infer_ctxt.root_var(vid)), closure_kind, - ) - } - TyKind::Function(fn_ptr) => match closure_kind { - ClosureKind::Closure => (Some(fn_ptr.substitution.clone()), Some(FnTrait::Fn)), - ClosureKind::Async | ClosureKind::Coroutine(_) => (None, None), + self.table.obligations_for_self_ty(vid).into_iter().map(|obl| obl.predicate), + ), + TyKind::FnPtr(sig_tys, hdr) => match closure_kind { + ClosureKind::Closure => { + let expected_sig = sig_tys.with(hdr); + (Some(expected_sig), Some(rustc_type_ir::ClosureKind::Fn)) + } + ClosureKind::Coroutine(_) | ClosureKind::Async => (None, None), }, _ => (None, None), } } - fn deduce_closure_kind_from_predicate_clauses( + fn deduce_closure_signature_from_predicates( &mut self, - expected_ty: &Ty, - clauses: impl DoubleEndedIterator, + expected_ty: Ty<'db>, closure_kind: ClosureKind, - ) -> (Option>, Option) { + predicates: impl DoubleEndedIterator>, + ) -> (Option>, Option) { let mut expected_sig = None; let mut expected_kind = None; - for clause in elaborate_clause_supertraits(self.db, clauses.rev()) { + for pred in rustc_type_ir::elaborate::elaborate( + self.table.interner, + // Reverse the obligations here, since `elaborate_*` uses a stack, + // and we want to keep inference generally in the same order of + // the registered obligations. + predicates.rev(), + ) + // We only care about self bounds + .filter_only_self() + { + debug!(?pred); + let bound_predicate = pred.kind(); + + // Given a Projection predicate, we can potentially infer + // the complete signature. if expected_sig.is_none() - && let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) = - &clause + && let PredicateKind::Clause(ClauseKind::Projection(proj_predicate)) = + bound_predicate.skip_binder() { - let inferred_sig = self.deduce_sig_from_projection(closure_kind, projection, ty); + let inferred_sig = self.deduce_sig_from_projection( + closure_kind, + bound_predicate.rebind(proj_predicate), + ); + // Make sure that we didn't infer a signature that mentions itself. // This can happen when we elaborate certain supertrait bounds that - // mention projections containing the `Self` type. See rust-lang/rust#105401. - struct MentionsTy<'a> { - expected_ty: &'a Ty, + // mention projections containing the `Self` type. See #105401. + struct MentionsTy<'db> { + expected_ty: Ty<'db>, } - impl TypeVisitor for MentionsTy<'_> { - type BreakTy = (); - - fn interner(&self) -> Interner { - Interner - } + impl<'db> TypeVisitor> for MentionsTy<'db> { + type Result = ControlFlow<()>; - fn as_dyn( - &mut self, - ) -> &mut dyn TypeVisitor - { - self - } - - fn visit_ty(&mut self, t: &Ty, db: chalk_ir::DebruijnIndex) -> ControlFlow<()> { + fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result { if t == self.expected_ty { ControlFlow::Break(()) } else { - t.super_visit_with(self, db) + t.super_visit_with(self) } } } - if inferred_sig - .visit_with(&mut MentionsTy { expected_ty }, chalk_ir::DebruijnIndex::INNERMOST) - .is_continue() - { - expected_sig = inferred_sig; - } - } - let trait_id = match clause { - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection), .. - }) => projection.trait_(self.db), - WhereClause::Implemented(trait_ref) => from_chalk_trait_id(trait_ref.trait_id), - _ => continue, - }; - if let Some(closure_kind) = self.fn_trait_kind_from_trait_id(trait_id) { - // always use the closure kind that is more permissive. - match (expected_kind, closure_kind) { - (None, _) => expected_kind = Some(closure_kind), - (Some(FnTrait::FnMut), FnTrait::Fn) => expected_kind = Some(FnTrait::Fn), - (Some(FnTrait::FnOnce), FnTrait::Fn | FnTrait::FnMut) => { - expected_kind = Some(closure_kind) + // Don't infer a closure signature from a goal that names the closure type as this will + // (almost always) lead to occurs check errors later in type checking. + if let Some(inferred_sig) = inferred_sig { + // In the new solver it is difficult to explicitly normalize the inferred signature as we + // would have to manually handle universes and rewriting bound vars and placeholders back + // and forth. + // + // Instead we take advantage of the fact that we relating an inference variable with an alias + // will only instantiate the variable if the alias is rigid(*not quite). Concretely we: + // - Create some new variable `?sig` + // - Equate `?sig` with the unnormalized signature, e.g. `fn( as Trait>::Assoc)` + // - Depending on whether ` as Trait>::Assoc` is rigid, ambiguous or normalizeable, + // we will either wind up with `?sig= as Trait>::Assoc/?y/ConcreteTy` respectively. + // + // *: In cases where there are ambiguous aliases in the signature that make use of bound vars + // they will wind up present in `?sig` even though they are non-rigid. + // + // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty` + // even though the normalized form may not name `expected_ty`. However, this matches the existing + // behaviour of the old solver and would be technically a breaking change to fix. + let generalized_fnptr_sig = self.table.next_ty_var(); + let inferred_fnptr_sig = Ty::new_fn_ptr(self.table.interner, inferred_sig); + // FIXME: Report diagnostics. + _ = self + .table + .infer_ctxt + .at(&ObligationCause::new(), self.table.param_env) + .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); + + let resolved_sig = + self.table.infer_ctxt.resolve_vars_if_possible(generalized_fnptr_sig); + + if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + expected_sig = Some(resolved_sig.fn_sig(self.table.interner)); } - _ => {} + } else if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + expected_sig = inferred_sig; } } - } - - (expected_sig, expected_kind) - } - - fn deduce_sig_from_dyn_ty(&self, dyn_ty: &DynTy) -> Option { - // Search for a predicate like `<$self as FnX>::Output == Ret` - let fn_traits: SmallVec<[TraitId; 3]> = - utils::fn_traits(self.db, self.owner.module(self.db).krate()).collect(); - - let self_ty = self.result.standard_types.unknown.clone(); - let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]); - for bound in bounds.iter(Interner) { - // NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer` - if let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) = - bound.skip_binders() - { - let trait_ = - match from_assoc_type_id(projection.associated_ty_id).lookup(self.db).container - { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - if !fn_traits.contains(&trait_) { - return None; + // Even if we can't infer the full signature, we may be able to + // infer the kind. This can occur when we elaborate a predicate + // like `F : Fn`. Note that due to subtyping we could encounter + // many viable options, so pick the most restrictive. + let trait_def_id = match bound_predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Projection(data)) => { + Some(data.projection_term.trait_def_id(self.table.interner).0) } + PredicateKind::Clause(ClauseKind::Trait(data)) => Some(data.def_id().0), + _ => None, + }; + + if let Some(trait_def_id) = trait_def_id { + let found_kind = match closure_kind { + ClosureKind::Closure => self.fn_trait_kind_from_def_id(trait_def_id), + ClosureKind::Async => self + .async_fn_trait_kind_from_def_id(trait_def_id) + .or_else(|| self.fn_trait_kind_from_def_id(trait_def_id)), + _ => None, + }; - // Skip `Self`, get the type argument. - let arg = projection.substitution.as_slice(Interner).get(1)?; - if let Some(subst) = arg.ty(Interner)?.as_tuple() { - let generic_args = subst.as_slice(Interner); - let mut sig_tys = Vec::with_capacity(generic_args.len() + 1); - for arg in generic_args { - sig_tys.push(arg.ty(Interner)?.clone()); + if let Some(found_kind) = found_kind { + // always use the closure kind that is more permissive. + match (expected_kind, found_kind) { + (None, _) => expected_kind = Some(found_kind), + ( + Some(rustc_type_ir::ClosureKind::FnMut), + rustc_type_ir::ClosureKind::Fn, + ) => expected_kind = Some(rustc_type_ir::ClosureKind::Fn), + ( + Some(rustc_type_ir::ClosureKind::FnOnce), + rustc_type_ir::ClosureKind::Fn | rustc_type_ir::ClosureKind::FnMut, + ) => expected_kind = Some(found_kind), + _ => {} } - sig_tys.push(ty.clone()); - - cov_mark::hit!(dyn_fn_param_informs_call_site_closure_signature); - return Some(FnPointer { - num_binders: bound.len(Interner), - sig: FnSig { - abi: FnAbi::RustCall, - safety: chalk_ir::Safety::Safe, - variadic: false, - }, - substitution: FnSubst(Substitution::from_iter(Interner, sig_tys)), - }); } } } - None + (expected_sig, expected_kind) } + /// Given a projection like "::Result == Y", we can deduce + /// everything we need to know about a closure or coroutine. + /// + /// The `cause_span` should be the span that caused us to + /// have this expected signature, or `None` if we can't readily + /// know that. fn deduce_sig_from_projection( &mut self, closure_kind: ClosureKind, - projection_ty: &ProjectionTy, - projected_ty: &Ty, - ) -> Option> { - let container = - from_assoc_type_id(projection_ty.associated_ty_id).lookup(self.db).container; - let trait_ = match container { - hir_def::ItemContainerId::TraitId(trait_) => trait_, - _ => return None, - }; + projection: PolyProjectionPredicate<'db>, + ) -> Option> { + let SolverDefId::TypeAliasId(def_id) = projection.item_def_id() else { unreachable!() }; + let lang_item = self.db.lang_attr(def_id.into()); // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits, // for closures and async closures, respectively. - let fn_trait_kind = self.fn_trait_kind_from_trait_id(trait_)?; - if !matches!(closure_kind, ClosureKind::Closure | ClosureKind::Async) { - return None; - } - if fn_trait_kind.is_async() { - // If the expected trait is `AsyncFn(...) -> X`, we don't know what the return type is, - // but we do know it must implement `Future`. - self.extract_async_fn_sig_from_projection(projection_ty, projected_ty) - } else { - self.extract_sig_from_projection(projection_ty, projected_ty) + match closure_kind { + ClosureKind::Closure if lang_item == Some(LangItem::FnOnceOutput) => { + self.extract_sig_from_projection(projection) + } + ClosureKind::Async if lang_item == Some(LangItem::AsyncFnOnceOutput) => { + self.extract_sig_from_projection(projection) + } + // It's possible we've passed the closure to a (somewhat out-of-fashion) + // `F: FnOnce() -> Fut, Fut: Future` style bound. Let's still + // guide inference here, since it's beneficial for the user. + ClosureKind::Async if lang_item == Some(LangItem::FnOnceOutput) => { + self.extract_sig_from_projection_and_future_bound(projection) + } + _ => None, } } + /// Given an `FnOnce::Output` or `AsyncFn::Output` projection, extract the args + /// and return type to infer a [`ty::PolyFnSig`] for the closure. fn extract_sig_from_projection( &self, - projection_ty: &ProjectionTy, - projected_ty: &Ty, - ) -> Option> { - let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner); - - let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else { - return None; - }; + projection: PolyProjectionPredicate<'db>, + ) -> Option> { + let projection = self.table.infer_ctxt.resolve_vars_if_possible(projection); - let ret_param_ty = projected_ty; + let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); + debug!(?arg_param_ty); - Some(FnSubst(Substitution::from_iter( - Interner, - input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new( - Interner, - chalk_ir::GenericArgData::Ty(ret_param_ty.clone()), - ))), - ))) - } - - fn extract_async_fn_sig_from_projection( - &mut self, - projection_ty: &ProjectionTy, - projected_ty: &Ty, - ) -> Option> { - let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner); - - let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else { + let TyKind::Tuple(input_tys) = arg_param_ty.kind() else { return None; }; - let ret_param_future_output = projected_ty; - let ret_param_future = self.table.new_type_var(); - let future_output = - LangItem::FutureOutput.resolve_type_alias(self.db, self.resolver.krate())?; - let future_projection = crate::AliasTy::Projection(crate::ProjectionTy { - associated_ty_id: to_assoc_type_id(future_output), - substitution: Substitution::from1(Interner, ret_param_future.clone()), - }); - let goal: crate::Goal = - crate::AliasEq { alias: future_projection, ty: ret_param_future_output.clone() } - .cast(Interner); - self.table.register_obligation(goal.to_nextsolver(self.table.interner)); - - Some(FnSubst(Substitution::from_iter( - Interner, - input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new( - Interner, - chalk_ir::GenericArgData::Ty(ret_param_future), - ))), - ))) - } + // Since this is a return parameter type it is safe to unwrap. + let ret_param_ty = projection.skip_binder().term.expect_type(); + debug!(?ret_param_ty); + + let sig = projection.rebind(self.table.interner.mk_fn_sig( + input_tys, + ret_param_ty, + false, + Safety::Safe, + FnAbi::Rust, + )); - fn fn_trait_kind_from_trait_id(&self, trait_id: hir_def::TraitId) -> Option { - FnTrait::from_lang_item(self.db.lang_attr(trait_id.into())?) + Some(sig) } - fn supplied_sig_of_closure( + /// When an async closure is passed to a function that has a "two-part" `Fn` + /// and `Future` trait bound, like: + /// + /// ```rust + /// use std::future::Future; + /// + /// fn not_exactly_an_async_closure(_f: F) + /// where + /// F: FnOnce(String, u32) -> Fut, + /// Fut: Future, + /// {} + /// ``` + /// + /// The we want to be able to extract the signature to guide inference in the async + /// closure. We will have two projection predicates registered in this case. First, + /// we identify the `FnOnce` bound, and if the output type is + /// an inference variable `?Fut`, we check if that is bounded by a `Future` + /// projection. + /// + /// This function is actually best-effort with the return type; if we don't find a + /// `Future` projection, we still will return arguments that we extracted from the `FnOnce` + /// projection, and the output will be an unconstrained type variable instead. + fn extract_sig_from_projection_and_future_bound( &mut self, - body: &ExprId, - ret_type: &Option, - arg_types: &[Option], - closure_kind: ClosureKind, - ) -> ClosureSignature { - let mut sig_tys = Vec::with_capacity(arg_types.len() + 1); - - // collect explicitly written argument types - for arg_type in arg_types.iter() { - let arg_ty = match arg_type { - // FIXME: I think rustc actually lowers closure params with `LifetimeElisionKind::AnonymousCreateParameter` - // (but the return type with infer). - Some(type_ref) => self.make_body_ty(*type_ref), - None => self.table.new_type_var(), - }; - sig_tys.push(arg_ty); - } + projection: PolyProjectionPredicate<'db>, + ) -> Option> { + let projection = self.table.infer_ctxt.resolve_vars_if_possible(projection); - // add return type - let ret_ty = match ret_type { - Some(type_ref) => self.make_body_ty(*type_ref), - None => self.table.new_type_var(), - }; - if let ClosureKind::Async = closure_kind { - sig_tys.push(self.lower_async_block_type_impl_trait(ret_ty.clone(), *body)); - } else { - sig_tys.push(ret_ty.clone()); - } + let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); + debug!(?arg_param_ty); - let expected_sig = FnPointer { - num_binders: 0, - sig: FnSig { abi: FnAbi::RustCall, safety: chalk_ir::Safety::Safe, variadic: false }, - substitution: FnSubst( - Substitution::from_iter(Interner, sig_tys.iter().cloned()).shifted_in(Interner), - ), + let TyKind::Tuple(input_tys) = arg_param_ty.kind() else { + return None; }; - ClosureSignature { ret_ty, expected_sig } - } + // If the return type is a type variable, look for bounds on it. + // We could theoretically support other kinds of return types here, + // but none of them would be useful, since async closures return + // concrete anonymous future types, and their futures are not coerced + // into any other type within the body of the async closure. + let TyKind::Infer(rustc_type_ir::TyVar(return_vid)) = + projection.skip_binder().term.expect_type().kind() + else { + return None; + }; - /// The return type is the signature of the closure, and the return type - /// *as represented inside the body* (so, for async closures, the `Output` ty) - pub(super) fn sig_of_closure( + // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare. + let mut return_ty = None; + for bound in self.table.obligations_for_self_ty(return_vid) { + if let PredicateKind::Clause(ClauseKind::Projection(ret_projection)) = + bound.predicate.kind().skip_binder() + && let ret_projection = bound.predicate.kind().rebind(ret_projection) + && let Some(ret_projection) = ret_projection.no_bound_vars() + && let SolverDefId::TypeAliasId(assoc_type) = ret_projection.def_id() + && self.db.lang_attr(assoc_type.into()) == Some(LangItem::FutureOutput) + { + return_ty = Some(ret_projection.term.expect_type()); + break; + } + } + + // SUBTLE: If we didn't find a `Future` bound for the return + // vid, we still want to attempt to provide inference guidance for the async + // closure's arguments. Instantiate a new vid to plug into the output type. + // + // You may be wondering, what if it's higher-ranked? Well, given that we + // found a type variable for the `FnOnce::Output` projection above, we know + // that the output can't mention any of the vars. + // + // Also note that we use a fresh var here for the signature since the signature + // records the output of the *future*, and `return_vid` above is the type + // variable of the future, not its output. + // + // FIXME: We probably should store this signature inference output in a way + // that does not misuse a `FnSig` type, but that can be done separately. + let return_ty = return_ty.unwrap_or_else(|| self.table.next_ty_var()); + + let sig = projection.rebind(self.table.interner.mk_fn_sig( + input_tys, + return_ty, + false, + Safety::Safe, + FnAbi::Rust, + )); + + Some(sig) + } + + fn sig_of_closure( &mut self, - body: &ExprId, - ret_type: &Option, - arg_types: &[Option], - closure_kind: ClosureKind, - expected_sig: Option>, - ) -> ClosureSignature { + decl_inputs: &[Option], + decl_output: Option, + expected_sig: Option>, + ) -> ClosureSignatures<'db> { if let Some(e) = expected_sig { - self.sig_of_closure_with_expectation(body, ret_type, arg_types, closure_kind, e) + self.sig_of_closure_with_expectation(decl_inputs, decl_output, e) } else { - self.sig_of_closure_no_expectation(body, ret_type, arg_types, closure_kind) + self.sig_of_closure_no_expectation(decl_inputs, decl_output) } } + /// If there is no expected signature, then we will convert the + /// types that the user gave into a signature. fn sig_of_closure_no_expectation( &mut self, - body: &ExprId, - ret_type: &Option, - arg_types: &[Option], - closure_kind: ClosureKind, - ) -> ClosureSignature { - self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind) - } - - fn sig_of_closure_with_expectation( - &mut self, - body: &ExprId, - ret_type: &Option, - arg_types: &[Option], - closure_kind: ClosureKind, - expected_sig: FnSubst, - ) -> ClosureSignature { - let expected_sig = FnPointer { - num_binders: 0, - sig: FnSig { abi: FnAbi::RustCall, safety: chalk_ir::Safety::Safe, variadic: false }, - substitution: expected_sig, - }; - - // If the expected signature does not match the actual arg types, - // then just return the expected signature - if expected_sig.substitution.0.len(Interner) != arg_types.len() + 1 { - let ret_ty = match ret_type { - Some(type_ref) => self.make_body_ty(*type_ref), - None => self.table.new_type_var(), - }; - return ClosureSignature { expected_sig, ret_ty }; - } - - self.merge_supplied_sig_with_expectation( - body, - ret_type, - arg_types, - closure_kind, - expected_sig, - ) - } - - fn merge_supplied_sig_with_expectation( - &mut self, - body: &ExprId, - ret_type: &Option, - arg_types: &[Option], - closure_kind: ClosureKind, - expected_sig: FnPointer, - ) -> ClosureSignature { - let supplied_sig = self.supplied_sig_of_closure(body, ret_type, arg_types, closure_kind); - - let snapshot = self.table.snapshot(); - if !self.table.unify::<_, crate::next_solver::GenericArgs<'_>>( - &expected_sig.substitution.0, - &supplied_sig.expected_sig.substitution.0, - ) { - self.table.rollback_to(snapshot); - } - - supplied_sig - } -} - -// The below functions handle capture and closure kind (Fn, FnMut, ..) - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct HirPlace { - pub(crate) local: BindingId, - pub(crate) projections: Vec>, -} - -impl HirPlace { - fn ty(&self, ctx: &mut InferenceContext<'_>) -> Ty { - let mut ty = ctx.table.resolve_completely(ctx.result[self.local].clone()); - for p in &self.projections { - ty = p.projected_ty( - ty, - ctx.db, - |_, _, _| { - unreachable!("Closure field only happens in MIR"); - }, - ctx.owner.module(ctx.db).krate(), - ); - } - ty - } + decl_inputs: &[Option], + decl_output: Option, + ) -> ClosureSignatures<'db> { + let bound_sig = self.supplied_sig_of_closure(decl_inputs, decl_output); - fn capture_kind_of_truncated_place( - &self, - mut current_capture: CaptureKind, - len: usize, - ) -> CaptureKind { - if let CaptureKind::ByRef(BorrowKind::Mut { - kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow, - }) = current_capture - && self.projections[len..].contains(&ProjectionElem::Deref) - { - current_capture = - CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }); - } - current_capture + self.closure_sigs(bound_sig) } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum CaptureKind { - ByRef(BorrowKind), - ByValue, -} -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CapturedItem { - pub(crate) place: HirPlace, - pub(crate) kind: CaptureKind, - /// The inner vec is the stacks; the outer vec is for each capture reference. + /// Invoked to compute the signature of a closure expression. This + /// combines any user-provided type annotations (e.g., `|x: u32| + /// -> u32 { .. }`) with the expected signature. /// - /// Even though we always report only the last span (i.e. the most inclusive span), - /// we need to keep them all, since when a closure occurs inside a closure, we - /// copy all captures of the inner closure to the outer closure, and then we may - /// truncate them, and we want the correct span to be reported. - span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>, - pub(crate) ty: Binders, -} - -impl CapturedItem { - pub fn local(&self) -> BindingId { - self.place.local - } - - /// Returns whether this place has any field (aka. non-deref) projections. - pub fn has_field_projections(&self) -> bool { - self.place.projections.iter().any(|it| !matches!(it, ProjectionElem::Deref)) - } - - pub fn ty(&self, subst: &Substitution) -> Ty { - self.ty.clone().substitute(Interner, utils::ClosureSubst(subst).parent_subst()) - } - - pub fn kind(&self) -> CaptureKind { - self.kind - } - - pub fn spans(&self) -> SmallVec<[MirSpan; 3]> { - self.span_stacks.iter().map(|stack| *stack.last().expect("empty span stack")).collect() - } - - /// Converts the place to a name that can be inserted into source code. - pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); - let mut result = body[self.place.local].name.as_str().to_owned(); - for proj in &self.place.projections { - match proj { - ProjectionElem::Deref => {} - ProjectionElem::Field(Either::Left(f)) => { - let variant_data = f.parent.fields(db); - match variant_data.shape { - FieldsShape::Record => { - result.push('_'); - result.push_str(variant_data.fields()[f.local_id].name.as_str()) - } - FieldsShape::Tuple => { - let index = - variant_data.fields().iter().position(|it| it.0 == f.local_id); - if let Some(index) = index { - format_to!(result, "_{index}"); - } - } - FieldsShape::Unit => {} - } - } - ProjectionElem::Field(Either::Right(f)) => format_to!(result, "_{}", f.index), - &ProjectionElem::ClosureField(field) => format_to!(result, "_{field}"), - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast(_) => { - never!("Not happen in closure capture"); - continue; - } - } - } - if is_raw_identifier(&result, owner.module(db).krate().data(db).edition) { - result.insert_str(0, "r#"); - } - result - } - - pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); - let krate = owner.krate(db); - let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); - for proj in &self.place.projections { - match proj { - // In source code autoderef kicks in. - ProjectionElem::Deref => {} - ProjectionElem::Field(Either::Left(f)) => { - let variant_data = f.parent.fields(db); - match variant_data.shape { - FieldsShape::Record => format_to!( - result, - ".{}", - variant_data.fields()[f.local_id].name.display(db, edition) - ), - FieldsShape::Tuple => format_to!( - result, - ".{}", - variant_data - .fields() - .iter() - .position(|it| it.0 == f.local_id) - .unwrap_or_default() - ), - FieldsShape::Unit => {} - } - } - ProjectionElem::Field(Either::Right(f)) => { - let field = f.index; - format_to!(result, ".{field}"); - } - &ProjectionElem::ClosureField(field) => { - format_to!(result, ".{field}"); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast(_) => { - never!("Not happen in closure capture"); - continue; - } - } - } - let final_derefs_count = self - .place - .projections - .iter() - .rev() - .take_while(|proj| matches!(proj, ProjectionElem::Deref)) - .count(); - result.insert_str(0, &"*".repeat(final_derefs_count)); - result - } - - pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); - let krate = owner.krate(db); - let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); - let mut field_need_paren = false; - for proj in &self.place.projections { - match proj { - ProjectionElem::Deref => { - result = format!("*{result}"); - field_need_paren = true; - } - ProjectionElem::Field(Either::Left(f)) => { - if field_need_paren { - result = format!("({result})"); - } - let variant_data = f.parent.fields(db); - let field = match variant_data.shape { - FieldsShape::Record => { - variant_data.fields()[f.local_id].name.as_str().to_owned() - } - FieldsShape::Tuple => variant_data - .fields() - .iter() - .position(|it| it.0 == f.local_id) - .unwrap_or_default() - .to_string(), - FieldsShape::Unit => "[missing field]".to_owned(), - }; - result = format!("{result}.{field}"); - field_need_paren = false; - } - ProjectionElem::Field(Either::Right(f)) => { - let field = f.index; - if field_need_paren { - result = format!("({result})"); - } - result = format!("{result}.{field}"); - field_need_paren = false; - } - &ProjectionElem::ClosureField(field) => { - if field_need_paren { - result = format!("({result})"); - } - result = format!("{result}.{field}"); - field_need_paren = false; - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast(_) => { - never!("Not happen in closure capture"); - continue; - } - } - } - result - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct CapturedItemWithoutTy { - pub(crate) place: HirPlace, - pub(crate) kind: CaptureKind, - /// The inner vec is the stacks; the outer vec is for each capture reference. - pub(crate) span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>, -} - -impl CapturedItemWithoutTy { - fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem { - let ty = self.place.ty(ctx); - let ty = match &self.kind { - CaptureKind::ByValue => ty, - CaptureKind::ByRef(bk) => { - let m = match bk { - BorrowKind::Mut { .. } => Mutability::Mut, - _ => Mutability::Not, - }; - TyKind::Ref(m, error_lifetime(), ty).intern(Interner) - } - }; - return CapturedItem { - place: self.place, - kind: self.kind, - span_stacks: self.span_stacks, - ty: replace_placeholder_with_binder(ctx, ty), - }; - - fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders { - struct Filler<'a> { - db: &'a dyn HirDatabase, - generics: &'a Generics, - } - impl FallibleTypeFolder for Filler<'_> { - type Error = (); - - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn try_fold_free_placeholder_const( - &mut self, - ty: chalk_ir::Ty, - idx: chalk_ir::PlaceholderIndex, - outer_binder: DebruijnIndex, - ) -> Result, Self::Error> { - let x = from_placeholder_idx(self.db, idx).0; - let Some(idx) = self.generics.type_or_const_param_idx(x) else { - return Err(()); - }; - Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty)) - } - - fn try_fold_free_placeholder_ty( - &mut self, - idx: chalk_ir::PlaceholderIndex, - outer_binder: DebruijnIndex, - ) -> std::result::Result { - let x = from_placeholder_idx(self.db, idx).0; - let Some(idx) = self.generics.type_or_const_param_idx(x) else { - return Err(()); - }; - Ok(BoundVar::new(outer_binder, idx).to_ty(Interner)) - } - } - let filler = &mut Filler { db: ctx.db, generics: ctx.generics() }; - let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); - make_binders(ctx.db, filler.generics, result) - } - } -} - -impl InferenceContext<'_> { - fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option { - let r = self.place_of_expr_without_adjust(tgt_expr)?; - let adjustments = - self.result.expr_adjustments.get(&tgt_expr).map(|it| &**it).unwrap_or_default(); - apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments) - } - - /// Pushes the span into `current_capture_span_stack`, *without clearing it first*. - fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { - if path.type_anchor().is_some() { - return None; - } - let hygiene = self.body.expr_or_pat_path_hygiene(id); - self.resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).and_then(|result| { - match result { - ValueNs::LocalBinding(binding) => { - let mir_span = match id { - ExprOrPatId::ExprId(id) => MirSpan::ExprId(id), - ExprOrPatId::PatId(id) => MirSpan::PatId(id), - }; - self.current_capture_span_stack.push(mir_span); - Some(HirPlace { local: binding, projections: Vec::new() }) - } - _ => None, - } - }) - } + /// The approach is as follows: + /// + /// - Let `S` be the (higher-ranked) signature that we derive from the user's annotations. + /// - Let `E` be the (higher-ranked) signature that we derive from the expectations, if any. + /// - If we have no expectation `E`, then the signature of the closure is `S`. + /// - Otherwise, the signature of the closure is E. Moreover: + /// - Skolemize the late-bound regions in `E`, yielding `E'`. + /// - Instantiate all the late-bound regions bound in the closure within `S` + /// with fresh (existential) variables, yielding `S'` + /// - Require that `E' = S'` + /// - We could use some kind of subtyping relationship here, + /// I imagine, but equality is easier and works fine for + /// our purposes. + /// + /// The key intuition here is that the user's types must be valid + /// from "the inside" of the closure, but the expectation + /// ultimately drives the overall signature. + /// + /// # Examples + /// + /// ```ignore (illustrative) + /// fn with_closure(_: F) + /// where F: Fn(&u32) -> &u32 { .. } + /// + /// with_closure(|x: &u32| { ... }) + /// ``` + /// + /// Here: + /// - E would be `fn(&u32) -> &u32`. + /// - S would be `fn(&u32) -> ?T` + /// - E' is `&'!0 u32 -> &'!0 u32` + /// - S' is `&'?0 u32 -> ?T` + /// + /// S' can be unified with E' with `['?0 = '!0, ?T = &'!10 u32]`. + /// + /// # Arguments + /// + /// - `expr_def_id`: the `LocalDefId` of the closure expression + /// - `decl`: the HIR declaration of the closure + /// - `body`: the body of the closure + /// - `expected_sig`: the expected signature (if any). Note that + /// this is missing a binder: that is, there may be late-bound + /// regions with depth 1, which are bound then by the closure. + fn sig_of_closure_with_expectation( + &mut self, + decl_inputs: &[Option], + decl_output: Option, + expected_sig: PolyFnSig<'db>, + ) -> ClosureSignatures<'db> { + // Watch out for some surprises and just ignore the + // expectation if things don't see to match up with what we + // expect. + if expected_sig.c_variadic() { + return self.sig_of_closure_no_expectation(decl_inputs, decl_output); + } else if expected_sig.skip_binder().inputs_and_output.len() != decl_inputs.len() + 1 { + return self + .sig_of_closure_with_mismatched_number_of_arguments(decl_inputs, decl_output); + } + + // Create a `PolyFnSig`. Note the oddity that late bound + // regions appearing free in `expected_sig` are now bound up + // in this binder we are creating. + assert!(!expected_sig.skip_binder().has_vars_bound_above(rustc_type_ir::INNERMOST)); + let bound_sig = expected_sig.map_bound(|sig| { + self.table.interner.mk_fn_sig( + sig.inputs(), + sig.output(), + sig.c_variadic, + Safety::Safe, + FnAbi::RustCall, + ) + }); - /// Changes `current_capture_span_stack` to contain the stack of spans for this expr. - fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option { - self.current_capture_span_stack.clear(); - match &self.body[tgt_expr] { - Expr::Path(p) => { - let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); - let result = self.path_place(p, tgt_expr.into()); - self.resolver.reset_to_guard(resolver_guard); - return result; - } - Expr::Field { expr, name: _ } => { - let mut place = self.place_of_expr(*expr)?; - let field = self.result.field_resolution(tgt_expr)?; - self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); - place.projections.push(ProjectionElem::Field(field)); - return Some(place); - } - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if matches!( - self.expr_ty_after_adjustments(*expr).kind(Interner), - TyKind::Ref(..) | TyKind::Raw(..) - ) { - let mut place = self.place_of_expr(*expr)?; - self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); - place.projections.push(ProjectionElem::Deref); - return Some(place); - } - } - _ => (), - } - None - } + // `deduce_expectations_from_expected_type` introduces + // late-bound lifetimes defined elsewhere, which we now + // anonymize away, so as not to confuse the user. + let bound_sig = self.table.interner.anonymize_bound_vars(bound_sig); - fn push_capture(&mut self, place: HirPlace, kind: CaptureKind) { - self.current_captures.push(CapturedItemWithoutTy { - place, - kind, - span_stacks: smallvec![self.current_capture_span_stack.iter().copied().collect()], - }); - } + let closure_sigs = self.closure_sigs(bound_sig); - fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut truncate_to: usize) { - // The first span is the identifier, and it must always remain. - truncate_to += 1; - for span_stack in &mut capture.span_stacks { - let mut remained = truncate_to; - let mut actual_truncate_to = 0; - for &span in &*span_stack { - actual_truncate_to += 1; - if !span.is_ref_span(self.body) { - remained -= 1; - if remained == 0 { - break; - } - } - } - if actual_truncate_to < span_stack.len() - && span_stack[actual_truncate_to].is_ref_span(self.body) - { - // Include the ref operator if there is one, we will fix it later (in `strip_captures_ref_span()`) if it's incorrect. - actual_truncate_to += 1; - } - span_stack.truncate(actual_truncate_to); + // Up till this point, we have ignored the annotations that the user + // gave. This function will check that they unify successfully. + // Along the way, it also writes out entries for types that the user + // wrote into our typeck results, which are then later used by the privacy + // check. + match self.merge_supplied_sig_with_expectation(decl_inputs, decl_output, closure_sigs) { + Ok(infer_ok) => self.table.register_infer_ok(infer_ok), + Err(_) => self.sig_of_closure_no_expectation(decl_inputs, decl_output), } } - fn ref_expr(&mut self, expr: ExprId, place: Option) { - if let Some(place) = place { - self.add_capture(place, CaptureKind::ByRef(BorrowKind::Shared)); - } - self.walk_expr(expr); - } + fn sig_of_closure_with_mismatched_number_of_arguments( + &mut self, + decl_inputs: &[Option], + decl_output: Option, + ) -> ClosureSignatures<'db> { + let error_sig = self.error_sig_of_closure(decl_inputs, decl_output); - fn add_capture(&mut self, place: HirPlace, kind: CaptureKind) { - if self.is_upvar(&place) { - self.push_capture(place, kind); - } + self.closure_sigs(error_sig) } - fn mutate_path_pat(&mut self, path: &Path, id: PatId) { - if let Some(place) = self.path_place(path, id.into()) { - self.add_capture( - place, - CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + /// Enforce the user's types against the expectation. See + /// `sig_of_closure_with_expectation` for details on the overall + /// strategy. + fn merge_supplied_sig_with_expectation( + &mut self, + decl_inputs: &[Option], + decl_output: Option, + mut expected_sigs: ClosureSignatures<'db>, + ) -> InferResult<'db, ClosureSignatures<'db>> { + // Get the signature S that the user gave. + // + // (See comment on `sig_of_closure_with_expectation` for the + // meaning of these letters.) + let supplied_sig = self.supplied_sig_of_closure(decl_inputs, decl_output); + + debug!(?supplied_sig); + + // FIXME(#45727): As discussed in [this comment][c1], naively + // forcing equality here actually results in suboptimal error + // messages in some cases. For now, if there would have been + // an obvious error, we fallback to declaring the type of the + // closure to be the one the user gave, which allows other + // error message code to trigger. + // + // However, I think [there is potential to do even better + // here][c2], since in *this* code we have the precise span of + // the type parameter in question in hand when we report the + // error. + // + // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706 + // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 + self.table.commit_if_ok(|table| { + let mut all_obligations = PredicateObligations::new(); + let supplied_sig = table.infer_ctxt.instantiate_binder_with_fresh_vars( + BoundRegionConversionTime::FnCall, + supplied_sig, ); - self.current_capture_span_stack.pop(); // Remove the pattern span. - } - } - fn mutate_expr(&mut self, expr: ExprId, place: Option) { - if let Some(place) = place { - self.add_capture( - place, - CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + // The liberated version of this signature should be a subtype + // of the liberated form of the expectation. + for (supplied_ty, expected_ty) in + iter::zip(supplied_sig.inputs(), expected_sigs.liberated_sig.inputs()) + { + // Check that E' = S'. + let cause = ObligationCause::new(); + let InferOk { value: (), obligations } = table + .infer_ctxt + .at(&cause, table.param_env) + .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?; + all_obligations.extend(obligations); + } + + let supplied_output_ty = supplied_sig.output(); + let cause = ObligationCause::new(); + let InferOk { value: (), obligations } = + table.infer_ctxt.at(&cause, table.param_env).eq( + DefineOpaqueTypes::Yes, + expected_sigs.liberated_sig.output(), + supplied_output_ty, + )?; + all_obligations.extend(obligations); + + let inputs = supplied_sig + .inputs() + .into_iter() + .map(|ty| table.infer_ctxt.resolve_vars_if_possible(ty)); + + expected_sigs.liberated_sig = table.interner.mk_fn_sig( + inputs, + supplied_output_ty, + expected_sigs.liberated_sig.c_variadic, + Safety::Safe, + FnAbi::RustCall, ); - } - self.walk_expr(expr); - } - fn consume_expr(&mut self, expr: ExprId) { - if let Some(place) = self.place_of_expr(expr) { - self.consume_place(place); - } - self.walk_expr(expr); + Ok(InferOk { value: expected_sigs, obligations: all_obligations }) + }) } - fn consume_place(&mut self, place: HirPlace) { - if self.is_upvar(&place) { - let ty = place.ty(self); - let kind = if self.is_ty_copy(ty) { - CaptureKind::ByRef(BorrowKind::Shared) - } else { - CaptureKind::ByValue - }; - self.push_capture(place, kind); - } - } + /// If there is no expected signature, then we will convert the + /// types that the user gave into a signature. + /// + /// Also, record this closure signature for later. + fn supplied_sig_of_closure( + &mut self, + decl_inputs: &[Option], + decl_output: Option, + ) -> PolyFnSig<'db> { + let interner = self.table.interner; - fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) { - if let Some((last, rest)) = adjustment.split_last() { - match &last.kind { - Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => { - self.walk_expr_with_adjust(tgt_expr, rest) - } - Adjust::Deref(Some(m)) => match m.0 { - Some(m) => { - self.ref_capture_with_adjusts(m, tgt_expr, rest); - } - None => unreachable!(), - }, - Adjust::Borrow(b) => { - self.ref_capture_with_adjusts(b.mutability(), tgt_expr, rest); - } + let supplied_return = match decl_output { + Some(output) => { + let output = self.make_body_ty(output); + self.process_user_written_ty(output).to_nextsolver(interner) } - } else { - self.walk_expr_without_adjust(tgt_expr); - } - } - - fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) { - let capture_kind = match m { - Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), - Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared), + None => self.table.next_ty_var(), }; - if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) - && let Some(place) = - apply_adjusts_to_place(&mut self.current_capture_span_stack, place, rest) - { - self.add_capture(place, capture_kind); - } - self.walk_expr_with_adjust(tgt_expr, rest); - } - - fn walk_expr(&mut self, tgt_expr: ExprId) { - if let Some(it) = self.result.expr_adjustments.get_mut(&tgt_expr) { - // FIXME: this take is completely unneeded, and just is here to make borrow checker - // happy. Remove it if you can. - let x_taken = mem::take(it); - self.walk_expr_with_adjust(tgt_expr, &x_taken); - *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken; - } else { - self.walk_expr_without_adjust(tgt_expr); - } - } - - fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { - match &self.body[tgt_expr] { - Expr::OffsetOf(_) => (), - Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op { - AsmOperand::In { expr, .. } - | AsmOperand::Out { expr: Some(expr), .. } - | AsmOperand::InOut { expr, .. } => self.walk_expr_without_adjust(*expr), - AsmOperand::SplitInOut { in_expr, out_expr, .. } => { - self.walk_expr_without_adjust(*in_expr); - if let Some(out_expr) = out_expr { - self.walk_expr_without_adjust(*out_expr); - } - } - AsmOperand::Out { expr: None, .. } - | AsmOperand::Const(_) - | AsmOperand::Label(_) - | AsmOperand::Sym(_) => (), - }), - Expr::If { condition, then_branch, else_branch } => { - self.consume_expr(*condition); - self.consume_expr(*then_branch); - if let &Some(expr) = else_branch { - self.consume_expr(expr); - } - } - Expr::Async { statements, tail, .. } - | Expr::Unsafe { statements, tail, .. } - | Expr::Block { statements, tail, .. } => { - for s in statements.iter() { - match s { - Statement::Let { pat, type_ref: _, initializer, else_branch } => { - if let Some(else_branch) = else_branch { - self.consume_expr(*else_branch); - } - if let Some(initializer) = initializer { - if else_branch.is_some() { - self.consume_expr(*initializer); - } else { - self.walk_expr(*initializer); - } - if let Some(place) = self.place_of_expr(*initializer) { - self.consume_with_pat(place, *pat); - } - } - } - Statement::Expr { expr, has_semi: _ } => { - self.consume_expr(*expr); - } - Statement::Item(_) => (), - } - } - if let Some(tail) = tail { - self.consume_expr(*tail); - } - } - Expr::Call { callee, args } => { - self.consume_expr(*callee); - self.consume_exprs(args.iter().copied()); - } - Expr::MethodCall { receiver, args, .. } => { - self.consume_expr(*receiver); - self.consume_exprs(args.iter().copied()); - } - Expr::Match { expr, arms } => { - for arm in arms.iter() { - self.consume_expr(arm.expr); - if let Some(guard) = arm.guard { - self.consume_expr(guard); - } - } - self.walk_expr(*expr); - if let Some(discr_place) = self.place_of_expr(*expr) - && self.is_upvar(&discr_place) - { - let mut capture_mode = None; - for arm in arms.iter() { - self.walk_pat(&mut capture_mode, arm.pat); - } - if let Some(c) = capture_mode { - self.push_capture(discr_place, c); - } - } - } - Expr::Break { expr, label: _ } - | Expr::Return { expr } - | Expr::Yield { expr } - | Expr::Yeet { expr } => { - if let &Some(expr) = expr { - self.consume_expr(expr); - } - } - &Expr::Become { expr } => { - self.consume_expr(expr); - } - Expr::RecordLit { fields, spread, .. } => { - if let &Some(expr) = spread { - self.consume_expr(expr); - } - self.consume_exprs(fields.iter().map(|it| it.expr)); - } - Expr::Field { expr, name: _ } => self.select_from_expr(*expr), - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if matches!( - self.expr_ty_after_adjustments(*expr).kind(Interner), - TyKind::Ref(..) | TyKind::Raw(..) - ) { - self.select_from_expr(*expr); - } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) { - let mutability = 'b: { - if let Some(deref_trait) = - self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) - && let Some(deref_fn) = deref_trait - .trait_items(self.db) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) - { - break 'b deref_fn == f; - } - false - }; - let place = self.place_of_expr(*expr); - if mutability { - self.mutate_expr(*expr, place); - } else { - self.ref_expr(*expr, place); - } - } else { - self.select_from_expr(*expr); - } - } - Expr::Let { pat, expr } => { - self.walk_expr(*expr); - if let Some(place) = self.place_of_expr(*expr) { - self.consume_with_pat(place, *pat); - } - } - Expr::UnaryOp { expr, op: _ } - | Expr::Array(Array::Repeat { initializer: expr, repeat: _ }) - | Expr::Await { expr } - | Expr::Loop { body: expr, label: _ } - | Expr::Box { expr } - | Expr::Cast { expr, type_ref: _ } => { - self.consume_expr(*expr); - } - Expr::Ref { expr, rawness: _, mutability } => { - // We need to do this before we push the span so the order will be correct. - let place = self.place_of_expr(*expr); - self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); - match mutability { - hir_def::type_ref::Mutability::Shared => self.ref_expr(*expr, place), - hir_def::type_ref::Mutability::Mut => self.mutate_expr(*expr, place), - } - } - Expr::BinaryOp { lhs, rhs, op } => { - let Some(op) = op else { - return; - }; - if matches!(op, BinaryOp::Assignment { .. }) { - let place = self.place_of_expr(*lhs); - self.mutate_expr(*lhs, place); - self.consume_expr(*rhs); - return; - } - self.consume_expr(*lhs); - self.consume_expr(*rhs); - } - Expr::Range { lhs, rhs, range_type: _ } => { - if let &Some(expr) = lhs { - self.consume_expr(expr); - } - if let &Some(expr) = rhs { - self.consume_expr(expr); - } - } - Expr::Index { base, index } => { - self.select_from_expr(*base); - self.consume_expr(*index); - } - Expr::Closure { .. } => { - let ty = self.expr_ty(tgt_expr); - let TyKind::Closure(id, _) = ty.kind(Interner) else { - never!("closure type is always closure"); - return; - }; - let (captures, _) = - self.result.closure_info.get(id).expect( - "We sort closures, so we should always have data for inner closures", - ); - let mut cc = mem::take(&mut self.current_captures); - cc.extend(captures.iter().filter(|it| self.is_upvar(&it.place)).map(|it| { - CapturedItemWithoutTy { - place: it.place.clone(), - kind: it.kind, - span_stacks: it.span_stacks.clone(), - } - })); - self.current_captures = cc; - } - Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => { - self.consume_exprs(exprs.iter().copied()) - } - &Expr::Assignment { target, value } => { - self.walk_expr(value); - let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); - match self.place_of_expr(value) { - Some(rhs_place) => { - self.inside_assignment = true; - self.consume_with_pat(rhs_place, target); - self.inside_assignment = false; - } - None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] { - Pat::Path(path) => self.mutate_path_pat(path, pat), - &Pat::Expr(expr) => { - let place = self.place_of_expr(expr); - self.mutate_expr(expr, place); - } - _ => {} - }), - } - self.resolver.reset_to_guard(resolver_guard); - } - - Expr::Missing - | Expr::Continue { .. } - | Expr::Path(_) - | Expr::Literal(_) - | Expr::Const(_) - | Expr::Underscore => (), - } - } - - fn walk_pat(&mut self, result: &mut Option, pat: PatId) { - let mut update_result = |ck: CaptureKind| match result { - Some(r) => { - *r = cmp::max(*r, ck); + // First, convert the types that the user supplied (if any). + let supplied_arguments = decl_inputs.iter().map(|&input| match input { + Some(input) => { + let input = self.make_body_ty(input); + self.process_user_written_ty(input).to_nextsolver(interner) } - None => *result = Some(ck), - }; + None => self.table.next_ty_var(), + }); - self.walk_pat_inner( - pat, - &mut update_result, - BorrowKind::Mut { kind: MutBorrowKind::Default }, - ); + Binder::dummy(interner.mk_fn_sig( + supplied_arguments, + supplied_return, + false, + Safety::Safe, + FnAbi::RustCall, + )) } - fn walk_pat_inner( + /// Converts the types that the user supplied, in case that doing + /// so should yield an error, but returns back a signature where + /// all parameters are of type `ty::Error`. + fn error_sig_of_closure( &mut self, - p: PatId, - update_result: &mut impl FnMut(CaptureKind), - mut for_mut: BorrowKind, - ) { - match &self.body[p] { - Pat::Ref { .. } - | Pat::Box { .. } - | Pat::Missing - | Pat::Wild - | Pat::Tuple { .. } - | Pat::Expr(_) - | Pat::Or(_) => (), - Pat::TupleStruct { .. } | Pat::Record { .. } => { - if let Some(variant) = self.result.variant_resolution_for_pat(p) { - let adt = variant.adt_id(self.db); - let is_multivariant = match adt { - hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1, - _ => false, - }; - if is_multivariant { - update_result(CaptureKind::ByRef(BorrowKind::Shared)); - } - } - } - Pat::Slice { .. } - | Pat::ConstBlock(_) - | Pat::Path(_) - | Pat::Lit(_) - | Pat::Range { .. } => { - update_result(CaptureKind::ByRef(BorrowKind::Shared)); - } - Pat::Bind { id, .. } => match self.result.binding_modes[p] { - crate::BindingMode::Move => { - if self.is_ty_copy(self.result.type_of_binding[*id].clone()) { - update_result(CaptureKind::ByRef(BorrowKind::Shared)); - } else { - update_result(CaptureKind::ByValue); - } - } - crate::BindingMode::Ref(r) => match r { - Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)), - Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)), - }, - }, - } - if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) { - for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }; - } - self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); - } - - fn expr_ty(&self, expr: ExprId) -> Ty { - self.result[expr].clone() - } - - fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { - let mut ty = None; - if let Some(it) = self.result.expr_adjustments.get(&e) - && let Some(it) = it.last() - { - ty = Some(it.target.clone()); - } - ty.unwrap_or_else(|| self.expr_ty(e)) - } - - fn is_upvar(&self, place: &HirPlace) -> bool { - if let Some(c) = self.current_closure { - let InternedClosure(_, root) = self.db.lookup_intern_closure(c.into()); - return self.body.is_binding_upvar(place.local, root); - } - false - } - - fn is_ty_copy(&mut self, ty: Ty) -> bool { - if let TyKind::Closure(id, _) = ty.kind(Interner) { - // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We - // should probably let chalk know which closures are copy, but I don't know how doing it - // without creating query cycles. - return self.result.closure_info.get(id).map(|it| it.1 == FnTrait::Fn).unwrap_or(true); - } - self.table.resolve_completely(ty).is_copy(self.db, self.owner) - } - - fn select_from_expr(&mut self, expr: ExprId) { - self.walk_expr(expr); - } - - fn restrict_precision_for_unsafe(&mut self) { - // FIXME: Borrow checker problems without this. - let mut current_captures = std::mem::take(&mut self.current_captures); - for capture in &mut current_captures { - let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone()); - if ty.as_raw_ptr().is_some() || ty.is_union() { - capture.kind = CaptureKind::ByRef(BorrowKind::Shared); - self.truncate_capture_spans(capture, 0); - capture.place.projections.truncate(0); - continue; - } - for (i, p) in capture.place.projections.iter().enumerate() { - ty = p.projected_ty( - ty, - self.db, - |_, _, _| { - unreachable!("Closure field only happens in MIR"); - }, - self.owner.module(self.db).krate(), - ); - if ty.as_raw_ptr().is_some() || ty.is_union() { - capture.kind = CaptureKind::ByRef(BorrowKind::Shared); - self.truncate_capture_spans(capture, i + 1); - capture.place.projections.truncate(i + 1); - break; - } - } - } - self.current_captures = current_captures; - } + decl_inputs: &[Option], + decl_output: Option, + ) -> PolyFnSig<'db> { + let interner = self.table.interner; + let err_ty = Ty::new_error(interner, ErrorGuaranteed); - fn adjust_for_move_closure(&mut self) { - // FIXME: Borrow checker won't allow without this. - let mut current_captures = std::mem::take(&mut self.current_captures); - for capture in &mut current_captures { - if let Some(first_deref) = - capture.place.projections.iter().position(|proj| *proj == ProjectionElem::Deref) - { - self.truncate_capture_spans(capture, first_deref); - capture.place.projections.truncate(first_deref); - } - capture.kind = CaptureKind::ByValue; + if let Some(output) = decl_output { + self.make_body_ty(output); } - self.current_captures = current_captures; - } - - fn minimize_captures(&mut self) { - self.current_captures.sort_unstable_by_key(|it| it.place.projections.len()); - let mut hash_map = FxHashMap::::default(); - let result = mem::take(&mut self.current_captures); - for mut item in result { - let mut lookup_place = HirPlace { local: item.place.local, projections: vec![] }; - let mut it = item.place.projections.iter(); - let prev_index = loop { - if let Some(k) = hash_map.get(&lookup_place) { - break Some(*k); - } - match it.next() { - Some(it) => { - lookup_place.projections.push(it.clone()); - } - None => break None, - } - }; - match prev_index { - Some(p) => { - let prev_projections_len = self.current_captures[p].place.projections.len(); - self.truncate_capture_spans(&mut item, prev_projections_len); - self.current_captures[p].span_stacks.extend(item.span_stacks); - let len = self.current_captures[p].place.projections.len(); - let kind_after_truncate = - item.place.capture_kind_of_truncated_place(item.kind, len); - self.current_captures[p].kind = - cmp::max(kind_after_truncate, self.current_captures[p].kind); - } - None => { - hash_map.insert(item.place.clone(), self.current_captures.len()); - self.current_captures.push(item); - } + let supplied_arguments = decl_inputs.iter().map(|&input| match input { + Some(input) => { + self.make_body_ty(input); + err_ty } - } - } - - fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { - let adjustments_count = - self.result.pat_adjustments.get(&tgt_pat).map(|it| it.len()).unwrap_or_default(); - place.projections.extend((0..adjustments_count).map(|_| ProjectionElem::Deref)); - self.current_capture_span_stack - .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat))); - 'reset_span_stack: { - match &self.body[tgt_pat] { - Pat::Missing | Pat::Wild => (), - Pat::Tuple { args, ellipsis } => { - let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); - let field_count = match self.result[tgt_pat].kind(Interner) { - TyKind::Tuple(_, s) => s.len(Interner), - _ => break 'reset_span_stack, - }; - let fields = 0..field_count; - let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); - for (&arg, i) in it { - let mut p = place.clone(); - self.current_capture_span_stack.push(MirSpan::PatId(arg)); - p.projections.push(ProjectionElem::Field(Either::Right(TupleFieldId { - tuple: TupleId(!0), // dummy this, as its unused anyways - index: i as u32, - }))); - self.consume_with_pat(p, arg); - self.current_capture_span_stack.pop(); - } - } - Pat::Or(pats) => { - for pat in pats.iter() { - self.consume_with_pat(place.clone(), *pat); - } - } - Pat::Record { args, .. } => { - let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else { - break 'reset_span_stack; - }; - match variant { - VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { - self.consume_place(place) - } - VariantId::StructId(s) => { - let vd = s.fields(self.db); - for field_pat in args.iter() { - let arg = field_pat.pat; - let Some(local_id) = vd.field(&field_pat.name) else { - continue; - }; - let mut p = place.clone(); - self.current_capture_span_stack.push(MirSpan::PatId(arg)); - p.projections.push(ProjectionElem::Field(Either::Left(FieldId { - parent: variant, - local_id, - }))); - self.consume_with_pat(p, arg); - self.current_capture_span_stack.pop(); - } - } - } - } - Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => { - self.consume_place(place) - } - Pat::Path(path) => { - if self.inside_assignment { - self.mutate_path_pat(path, tgt_pat); - } - self.consume_place(place); - } - &Pat::Bind { id, subpat: _ } => { - let mode = self.result.binding_modes[tgt_pat]; - let capture_kind = match mode { - BindingMode::Move => { - self.consume_place(place); - break 'reset_span_stack; - } - BindingMode::Ref(Mutability::Not) => BorrowKind::Shared, - BindingMode::Ref(Mutability::Mut) => { - BorrowKind::Mut { kind: MutBorrowKind::Default } - } - }; - self.current_capture_span_stack.push(MirSpan::BindingId(id)); - self.add_capture(place, CaptureKind::ByRef(capture_kind)); - self.current_capture_span_stack.pop(); - } - Pat::TupleStruct { path: _, args, ellipsis } => { - let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else { - break 'reset_span_stack; - }; - match variant { - VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { - self.consume_place(place) - } - VariantId::StructId(s) => { - let vd = s.fields(self.db); - let (al, ar) = - args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); - let fields = vd.fields().iter(); - let it = al - .iter() - .zip(fields.clone()) - .chain(ar.iter().rev().zip(fields.rev())); - for (&arg, (i, _)) in it { - let mut p = place.clone(); - self.current_capture_span_stack.push(MirSpan::PatId(arg)); - p.projections.push(ProjectionElem::Field(Either::Left(FieldId { - parent: variant, - local_id: i, - }))); - self.consume_with_pat(p, arg); - self.current_capture_span_stack.pop(); - } - } - } - } - Pat::Ref { pat, mutability: _ } => { - self.current_capture_span_stack.push(MirSpan::PatId(tgt_pat)); - place.projections.push(ProjectionElem::Deref); - self.consume_with_pat(place, *pat); - self.current_capture_span_stack.pop(); - } - Pat::Box { .. } => (), // not supported - &Pat::Expr(expr) => { - self.consume_place(place); - let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack); - let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); - let lhs_place = self.place_of_expr(expr); - self.mutate_expr(expr, lhs_place); - self.inside_assignment = old_inside_assignment; - self.current_capture_span_stack = pat_capture_span_stack; - } - } - } - self.current_capture_span_stack - .truncate(self.current_capture_span_stack.len() - adjustments_count); - } - - fn consume_exprs(&mut self, exprs: impl Iterator) { - for expr in exprs { - self.consume_expr(expr); - } - } - - fn closure_kind(&self) -> FnTrait { - let mut r = FnTrait::Fn; - for it in &self.current_captures { - r = cmp::min( - r, - match &it.kind { - CaptureKind::ByRef(BorrowKind::Mut { .. }) => FnTrait::FnMut, - CaptureKind::ByRef(BorrowKind::Shallow | BorrowKind::Shared) => FnTrait::Fn, - CaptureKind::ByValue => FnTrait::FnOnce, - }, - ) - } - r - } + None => err_ty, + }); - fn analyze_closure(&mut self, closure: ClosureId) -> FnTrait { - let InternedClosure(_, root) = self.db.lookup_intern_closure(closure.into()); - self.current_closure = Some(closure); - let Expr::Closure { body, capture_by, .. } = &self.body[root] else { - unreachable!("Closure expression id is always closure"); - }; - self.consume_expr(*body); - for item in &self.current_captures { - if matches!( - item.kind, - CaptureKind::ByRef(BorrowKind::Mut { - kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow - }) - ) && !item.place.projections.contains(&ProjectionElem::Deref) - { - // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in - // MIR. I didn't do that due duplicate diagnostics. - self.result.mutated_bindings_in_closure.insert(item.place.local); - } - } - self.restrict_precision_for_unsafe(); - // `closure_kind` should be done before adjust_for_move_closure - // If there exists pre-deduced kind of a closure, use it instead of one determined by capture, as rustc does. - // rustc also does diagnostics here if the latter is not a subtype of the former. - let closure_kind = self - .result - .closure_info - .get(&closure) - .map_or_else(|| self.closure_kind(), |info| info.1); - match capture_by { - CaptureBy::Value => self.adjust_for_move_closure(), - CaptureBy::Ref => (), - } - self.minimize_captures(); - self.strip_captures_ref_span(); - let result = mem::take(&mut self.current_captures); - let captures = result.into_iter().map(|it| it.with_ty(self)).collect::>(); - self.result.closure_info.insert(closure, (captures, closure_kind)); - closure_kind - } + let result = Binder::dummy(interner.mk_fn_sig( + supplied_arguments, + err_ty, + false, + Safety::Safe, + FnAbi::RustCall, + )); - fn strip_captures_ref_span(&mut self) { - // FIXME: Borrow checker won't allow without this. - let mut captures = std::mem::take(&mut self.current_captures); - for capture in &mut captures { - if matches!(capture.kind, CaptureKind::ByValue) { - for span_stack in &mut capture.span_stacks { - if span_stack[span_stack.len() - 1].is_ref_span(self.body) { - span_stack.truncate(span_stack.len() - 1); - } - } - } - } - self.current_captures = captures; - } + debug!("supplied_sig_of_closure: result={:?}", result); - pub(crate) fn infer_closures(&mut self) { - let deferred_closures = self.sort_closures(); - for (closure, exprs) in deferred_closures.into_iter().rev() { - self.current_captures = vec![]; - let kind = self.analyze_closure(closure); - - for (derefed_callee, callee_ty, params, expr) in exprs { - if let &Expr::Call { callee, .. } = &self.body[expr] { - let mut adjustments = - self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); - self.write_fn_trait_method_resolution( - kind, - &derefed_callee, - &mut adjustments, - &callee_ty, - ¶ms, - expr, - ); - self.result.expr_adjustments.insert(callee, adjustments.into_boxed_slice()); - } - } - } - } - - /// We want to analyze some closures before others, to have a correct analysis: - /// * We should analyze nested closures before the parent, since the parent should capture some of - /// the things that its children captures. - /// * If a closure calls another closure, we need to analyze the callee, to find out how we should - /// capture it (e.g. by move for FnOnce) - /// - /// These dependencies are collected in the main inference. We do a topological sort in this function. It - /// will consume the `deferred_closures` field and return its content in a sorted vector. - fn sort_closures(&mut self) -> Vec<(ClosureId, Vec<(Ty, Ty, Vec, ExprId)>)> { - let mut deferred_closures = mem::take(&mut self.deferred_closures); - let mut dependents_count: FxHashMap = - deferred_closures.keys().map(|it| (*it, 0)).collect(); - for deps in self.closure_dependencies.values() { - for dep in deps { - *dependents_count.entry(*dep).or_default() += 1; - } - } - let mut queue: Vec<_> = - deferred_closures.keys().copied().filter(|it| dependents_count[it] == 0).collect(); - let mut result = vec![]; - while let Some(it) = queue.pop() { - if let Some(d) = deferred_closures.remove(&it) { - result.push((it, d)); - } - for dep in self.closure_dependencies.get(&it).into_iter().flat_map(|it| it.iter()) { - let cnt = dependents_count.get_mut(dep).unwrap(); - *cnt -= 1; - if *cnt == 0 { - queue.push(*dep); - } - } - } - assert!(deferred_closures.is_empty(), "we should have analyzed all closures"); result } - pub(super) fn add_current_closure_dependency(&mut self, dep: ClosureId) { - if let Some(c) = self.current_closure - && !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep) - { - self.closure_dependencies.entry(c).or_default().push(dep); - } - - fn dep_creates_cycle( - closure_dependencies: &FxHashMap>, - visited: &mut FxHashSet, - from: ClosureId, - to: ClosureId, - ) -> bool { - if !visited.insert(from) { - return false; - } - - if from == to { - return true; - } - - if let Some(deps) = closure_dependencies.get(&to) { - for dep in deps { - if dep_creates_cycle(closure_dependencies, visited, from, *dep) { - return true; - } - } - } - - false - } - } -} - -/// Call this only when the last span in the stack isn't a split. -fn apply_adjusts_to_place( - current_capture_span_stack: &mut Vec, - mut r: HirPlace, - adjustments: &[Adjustment], -) -> Option { - let span = *current_capture_span_stack.last().expect("empty capture span stack"); - for adj in adjustments { - match &adj.kind { - Adjust::Deref(None) => { - current_capture_span_stack.push(span); - r.projections.push(ProjectionElem::Deref); - } - _ => return None, - } + fn closure_sigs(&self, bound_sig: PolyFnSig<'db>) -> ClosureSignatures<'db> { + let liberated_sig = bound_sig.skip_binder(); + // FIXME: When we lower HRTB we'll need to actually liberate regions here. + ClosureSignatures { bound_sig, liberated_sig } } - Some(r) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs new file mode 100644 index 0000000000000..fd14b9e2de571 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -0,0 +1,1298 @@ +//! Post-inference closure analysis: captures and closure kind. + +use std::{cmp, convert::Infallible, mem}; + +use chalk_ir::{ + BoundVar, DebruijnIndex, Mutability, TyKind, + fold::{FallibleTypeFolder, TypeFoldable}, +}; +use either::Either; +use hir_def::{ + DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, + expr_store::path::Path, + hir::{ + Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, + Statement, UnaryOp, + }, + item_tree::FieldsShape, + lang_item::LangItem, + resolver::ValueNs, +}; +use hir_expand::name::Name; +use intern::sym; +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::{SmallVec, smallvec}; +use stdx::{format_to, never}; +use syntax::utils::is_raw_identifier; + +use crate::db::InternedClosureId; +use crate::infer::InferenceContext; +use crate::{ + Adjust, Adjustment, Binders, BindingMode, ClosureId, Interner, Substitution, Ty, TyExt, + db::{HirDatabase, InternedClosure}, + error_lifetime, from_placeholder_idx, + generics::Generics, + make_binders, + mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, + traits::FnTrait, + utils, +}; + +// The below functions handle capture and closure kind (Fn, FnMut, ..) + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct HirPlace { + pub(crate) local: BindingId, + pub(crate) projections: Vec>, +} + +impl HirPlace { + fn ty(&self, ctx: &mut InferenceContext<'_>) -> Ty { + let mut ty = ctx.table.resolve_completely(ctx.result[self.local].clone()); + for p in &self.projections { + ty = p.projected_ty( + ty, + ctx.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + ctx.owner.module(ctx.db).krate(), + ); + } + ty + } + + fn capture_kind_of_truncated_place( + &self, + mut current_capture: CaptureKind, + len: usize, + ) -> CaptureKind { + if let CaptureKind::ByRef(BorrowKind::Mut { + kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow, + }) = current_capture + && self.projections[len..].contains(&ProjectionElem::Deref) + { + current_capture = + CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }); + } + current_capture + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum CaptureKind { + ByRef(BorrowKind), + ByValue, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CapturedItem { + pub(crate) place: HirPlace, + pub(crate) kind: CaptureKind, + /// The inner vec is the stacks; the outer vec is for each capture reference. + /// + /// Even though we always report only the last span (i.e. the most inclusive span), + /// we need to keep them all, since when a closure occurs inside a closure, we + /// copy all captures of the inner closure to the outer closure, and then we may + /// truncate them, and we want the correct span to be reported. + span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>, + pub(crate) ty: Binders, +} + +impl CapturedItem { + pub fn local(&self) -> BindingId { + self.place.local + } + + /// Returns whether this place has any field (aka. non-deref) projections. + pub fn has_field_projections(&self) -> bool { + self.place.projections.iter().any(|it| !matches!(it, ProjectionElem::Deref)) + } + + pub fn ty(&self, db: &dyn HirDatabase, subst: &Substitution) -> Ty { + self.ty.clone().substitute(Interner, &utils::ClosureSubst(subst).parent_subst(db)) + } + + pub fn kind(&self) -> CaptureKind { + self.kind + } + + pub fn spans(&self) -> SmallVec<[MirSpan; 3]> { + self.span_stacks.iter().map(|stack| *stack.last().expect("empty span stack")).collect() + } + + /// Converts the place to a name that can be inserted into source code. + pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { + let body = db.body(owner); + let mut result = body[self.place.local].name.as_str().to_owned(); + for proj in &self.place.projections { + match proj { + ProjectionElem::Deref => {} + ProjectionElem::Field(Either::Left(f)) => { + let variant_data = f.parent.fields(db); + match variant_data.shape { + FieldsShape::Record => { + result.push('_'); + result.push_str(variant_data.fields()[f.local_id].name.as_str()) + } + FieldsShape::Tuple => { + let index = + variant_data.fields().iter().position(|it| it.0 == f.local_id); + if let Some(index) = index { + format_to!(result, "_{index}"); + } + } + FieldsShape::Unit => {} + } + } + ProjectionElem::Field(Either::Right(f)) => format_to!(result, "_{}", f.index), + &ProjectionElem::ClosureField(field) => format_to!(result, "_{field}"), + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast(_) => { + never!("Not happen in closure capture"); + continue; + } + } + } + if is_raw_identifier(&result, owner.module(db).krate().data(db).edition) { + result.insert_str(0, "r#"); + } + result + } + + pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { + let body = db.body(owner); + let krate = owner.krate(db); + let edition = krate.data(db).edition; + let mut result = body[self.place.local].name.display(db, edition).to_string(); + for proj in &self.place.projections { + match proj { + // In source code autoderef kicks in. + ProjectionElem::Deref => {} + ProjectionElem::Field(Either::Left(f)) => { + let variant_data = f.parent.fields(db); + match variant_data.shape { + FieldsShape::Record => format_to!( + result, + ".{}", + variant_data.fields()[f.local_id].name.display(db, edition) + ), + FieldsShape::Tuple => format_to!( + result, + ".{}", + variant_data + .fields() + .iter() + .position(|it| it.0 == f.local_id) + .unwrap_or_default() + ), + FieldsShape::Unit => {} + } + } + ProjectionElem::Field(Either::Right(f)) => { + let field = f.index; + format_to!(result, ".{field}"); + } + &ProjectionElem::ClosureField(field) => { + format_to!(result, ".{field}"); + } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast(_) => { + never!("Not happen in closure capture"); + continue; + } + } + } + let final_derefs_count = self + .place + .projections + .iter() + .rev() + .take_while(|proj| matches!(proj, ProjectionElem::Deref)) + .count(); + result.insert_str(0, &"*".repeat(final_derefs_count)); + result + } + + pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { + let body = db.body(owner); + let krate = owner.krate(db); + let edition = krate.data(db).edition; + let mut result = body[self.place.local].name.display(db, edition).to_string(); + let mut field_need_paren = false; + for proj in &self.place.projections { + match proj { + ProjectionElem::Deref => { + result = format!("*{result}"); + field_need_paren = true; + } + ProjectionElem::Field(Either::Left(f)) => { + if field_need_paren { + result = format!("({result})"); + } + let variant_data = f.parent.fields(db); + let field = match variant_data.shape { + FieldsShape::Record => { + variant_data.fields()[f.local_id].name.as_str().to_owned() + } + FieldsShape::Tuple => variant_data + .fields() + .iter() + .position(|it| it.0 == f.local_id) + .unwrap_or_default() + .to_string(), + FieldsShape::Unit => "[missing field]".to_owned(), + }; + result = format!("{result}.{field}"); + field_need_paren = false; + } + ProjectionElem::Field(Either::Right(f)) => { + let field = f.index; + if field_need_paren { + result = format!("({result})"); + } + result = format!("{result}.{field}"); + field_need_paren = false; + } + &ProjectionElem::ClosureField(field) => { + if field_need_paren { + result = format!("({result})"); + } + result = format!("{result}.{field}"); + field_need_paren = false; + } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast(_) => { + never!("Not happen in closure capture"); + continue; + } + } + } + result + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct CapturedItemWithoutTy { + pub(crate) place: HirPlace, + pub(crate) kind: CaptureKind, + /// The inner vec is the stacks; the outer vec is for each capture reference. + pub(crate) span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>, +} + +impl CapturedItemWithoutTy { + fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem { + let ty = self.place.ty(ctx); + let ty = match &self.kind { + CaptureKind::ByValue => ty, + CaptureKind::ByRef(bk) => { + let m = match bk { + BorrowKind::Mut { .. } => Mutability::Mut, + _ => Mutability::Not, + }; + TyKind::Ref(m, error_lifetime(), ty).intern(Interner) + } + }; + return CapturedItem { + place: self.place, + kind: self.kind, + span_stacks: self.span_stacks, + ty: replace_placeholder_with_binder(ctx, ty), + }; + + fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders { + struct Filler<'a> { + db: &'a dyn HirDatabase, + generics: &'a Generics, + } + impl FallibleTypeFolder for Filler<'_> { + type Error = (); + + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { + self + } + + fn interner(&self) -> Interner { + Interner + } + + fn try_fold_free_placeholder_const( + &mut self, + ty: chalk_ir::Ty, + idx: chalk_ir::PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> Result, Self::Error> { + let x = from_placeholder_idx(self.db, idx).0; + let Some(idx) = self.generics.type_or_const_param_idx(x) else { + return Err(()); + }; + Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty)) + } + + fn try_fold_free_placeholder_ty( + &mut self, + idx: chalk_ir::PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> std::result::Result { + let x = from_placeholder_idx(self.db, idx).0; + let Some(idx) = self.generics.type_or_const_param_idx(x) else { + return Err(()); + }; + Ok(BoundVar::new(outer_binder, idx).to_ty(Interner)) + } + } + let filler = &mut Filler { db: ctx.db, generics: ctx.generics() }; + let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); + make_binders(ctx.db, filler.generics, result) + } + } +} + +impl InferenceContext<'_> { + fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option { + let r = self.place_of_expr_without_adjust(tgt_expr)?; + let adjustments = + self.result.expr_adjustments.get(&tgt_expr).map(|it| &**it).unwrap_or_default(); + apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments) + } + + /// Pushes the span into `current_capture_span_stack`, *without clearing it first*. + fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { + if path.type_anchor().is_some() { + return None; + } + let hygiene = self.body.expr_or_pat_path_hygiene(id); + self.resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).and_then(|result| { + match result { + ValueNs::LocalBinding(binding) => { + let mir_span = match id { + ExprOrPatId::ExprId(id) => MirSpan::ExprId(id), + ExprOrPatId::PatId(id) => MirSpan::PatId(id), + }; + self.current_capture_span_stack.push(mir_span); + Some(HirPlace { local: binding, projections: Vec::new() }) + } + _ => None, + } + }) + } + + /// Changes `current_capture_span_stack` to contain the stack of spans for this expr. + fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option { + self.current_capture_span_stack.clear(); + match &self.body[tgt_expr] { + Expr::Path(p) => { + let resolver_guard = + self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); + let result = self.path_place(p, tgt_expr.into()); + self.resolver.reset_to_guard(resolver_guard); + return result; + } + Expr::Field { expr, name: _ } => { + let mut place = self.place_of_expr(*expr)?; + let field = self.result.field_resolution(tgt_expr)?; + self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); + place.projections.push(ProjectionElem::Field(field)); + return Some(place); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if matches!( + self.expr_ty_after_adjustments(*expr).kind(Interner), + TyKind::Ref(..) | TyKind::Raw(..) + ) { + let mut place = self.place_of_expr(*expr)?; + self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); + place.projections.push(ProjectionElem::Deref); + return Some(place); + } + } + _ => (), + } + None + } + + fn push_capture(&mut self, place: HirPlace, kind: CaptureKind) { + self.current_captures.push(CapturedItemWithoutTy { + place, + kind, + span_stacks: smallvec![self.current_capture_span_stack.iter().copied().collect()], + }); + } + + fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut truncate_to: usize) { + // The first span is the identifier, and it must always remain. + truncate_to += 1; + for span_stack in &mut capture.span_stacks { + let mut remained = truncate_to; + let mut actual_truncate_to = 0; + for &span in &*span_stack { + actual_truncate_to += 1; + if !span.is_ref_span(self.body) { + remained -= 1; + if remained == 0 { + break; + } + } + } + if actual_truncate_to < span_stack.len() + && span_stack[actual_truncate_to].is_ref_span(self.body) + { + // Include the ref operator if there is one, we will fix it later (in `strip_captures_ref_span()`) if it's incorrect. + actual_truncate_to += 1; + } + span_stack.truncate(actual_truncate_to); + } + } + + fn ref_expr(&mut self, expr: ExprId, place: Option) { + if let Some(place) = place { + self.add_capture(place, CaptureKind::ByRef(BorrowKind::Shared)); + } + self.walk_expr(expr); + } + + fn add_capture(&mut self, place: HirPlace, kind: CaptureKind) { + if self.is_upvar(&place) { + self.push_capture(place, kind); + } + } + + fn mutate_path_pat(&mut self, path: &Path, id: PatId) { + if let Some(place) = self.path_place(path, id.into()) { + self.add_capture( + place, + CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + ); + self.current_capture_span_stack.pop(); // Remove the pattern span. + } + } + + fn mutate_expr(&mut self, expr: ExprId, place: Option) { + if let Some(place) = place { + self.add_capture( + place, + CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + ); + } + self.walk_expr(expr); + } + + fn consume_expr(&mut self, expr: ExprId) { + if let Some(place) = self.place_of_expr(expr) { + self.consume_place(place); + } + self.walk_expr(expr); + } + + fn consume_place(&mut self, place: HirPlace) { + if self.is_upvar(&place) { + let ty = place.ty(self); + let kind = if self.is_ty_copy(ty) { + CaptureKind::ByRef(BorrowKind::Shared) + } else { + CaptureKind::ByValue + }; + self.push_capture(place, kind); + } + } + + fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) { + if let Some((last, rest)) = adjustment.split_last() { + match &last.kind { + Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => { + self.walk_expr_with_adjust(tgt_expr, rest) + } + Adjust::Deref(Some(m)) => match m.0 { + Some(m) => { + self.ref_capture_with_adjusts(m, tgt_expr, rest); + } + None => unreachable!(), + }, + Adjust::Borrow(b) => { + self.ref_capture_with_adjusts(b.mutability(), tgt_expr, rest); + } + } + } else { + self.walk_expr_without_adjust(tgt_expr); + } + } + + fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) { + let capture_kind = match m { + Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), + Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared), + }; + if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) + && let Some(place) = + apply_adjusts_to_place(&mut self.current_capture_span_stack, place, rest) + { + self.add_capture(place, capture_kind); + } + self.walk_expr_with_adjust(tgt_expr, rest); + } + + fn walk_expr(&mut self, tgt_expr: ExprId) { + if let Some(it) = self.result.expr_adjustments.get_mut(&tgt_expr) { + // FIXME: this take is completely unneeded, and just is here to make borrow checker + // happy. Remove it if you can. + let x_taken = mem::take(it); + self.walk_expr_with_adjust(tgt_expr, &x_taken); + *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken; + } else { + self.walk_expr_without_adjust(tgt_expr); + } + } + + fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { + match &self.body[tgt_expr] { + Expr::OffsetOf(_) => (), + Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => self.walk_expr_without_adjust(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + self.walk_expr_without_adjust(*in_expr); + if let Some(out_expr) = out_expr { + self.walk_expr_without_adjust(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + self.consume_expr(*condition); + self.consume_expr(*then_branch); + if let &Some(expr) = else_branch { + self.consume_expr(expr); + } + } + Expr::Async { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Block { statements, tail, .. } => { + for s in statements.iter() { + match s { + Statement::Let { pat, type_ref: _, initializer, else_branch } => { + if let Some(else_branch) = else_branch { + self.consume_expr(*else_branch); + } + if let Some(initializer) = initializer { + if else_branch.is_some() { + self.consume_expr(*initializer); + } else { + self.walk_expr(*initializer); + } + if let Some(place) = self.place_of_expr(*initializer) { + self.consume_with_pat(place, *pat); + } + } + } + Statement::Expr { expr, has_semi: _ } => { + self.consume_expr(*expr); + } + Statement::Item(_) => (), + } + } + if let Some(tail) = tail { + self.consume_expr(*tail); + } + } + Expr::Call { callee, args } => { + self.consume_expr(*callee); + self.consume_exprs(args.iter().copied()); + } + Expr::MethodCall { receiver, args, .. } => { + self.consume_expr(*receiver); + self.consume_exprs(args.iter().copied()); + } + Expr::Match { expr, arms } => { + for arm in arms.iter() { + self.consume_expr(arm.expr); + if let Some(guard) = arm.guard { + self.consume_expr(guard); + } + } + self.walk_expr(*expr); + if let Some(discr_place) = self.place_of_expr(*expr) + && self.is_upvar(&discr_place) + { + let mut capture_mode = None; + for arm in arms.iter() { + self.walk_pat(&mut capture_mode, arm.pat); + } + if let Some(c) = capture_mode { + self.push_capture(discr_place, c); + } + } + } + Expr::Break { expr, label: _ } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + self.consume_expr(expr); + } + } + &Expr::Become { expr } => { + self.consume_expr(expr); + } + Expr::RecordLit { fields, spread, .. } => { + if let &Some(expr) = spread { + self.consume_expr(expr); + } + self.consume_exprs(fields.iter().map(|it| it.expr)); + } + Expr::Field { expr, name: _ } => self.select_from_expr(*expr), + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if matches!( + self.expr_ty_after_adjustments(*expr).kind(Interner), + TyKind::Ref(..) | TyKind::Raw(..) + ) { + self.select_from_expr(*expr); + } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) { + let mutability = 'b: { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) + && let Some(deref_fn) = deref_trait + .trait_items(self.db) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + { + break 'b deref_fn == f; + } + false + }; + let place = self.place_of_expr(*expr); + if mutability { + self.mutate_expr(*expr, place); + } else { + self.ref_expr(*expr, place); + } + } else { + self.select_from_expr(*expr); + } + } + Expr::Let { pat, expr } => { + self.walk_expr(*expr); + if let Some(place) = self.place_of_expr(*expr) { + self.consume_with_pat(place, *pat); + } + } + Expr::UnaryOp { expr, op: _ } + | Expr::Array(Array::Repeat { initializer: expr, repeat: _ }) + | Expr::Await { expr } + | Expr::Loop { body: expr, label: _ } + | Expr::Box { expr } + | Expr::Cast { expr, type_ref: _ } => { + self.consume_expr(*expr); + } + Expr::Ref { expr, rawness: _, mutability } => { + // We need to do this before we push the span so the order will be correct. + let place = self.place_of_expr(*expr); + self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); + match mutability { + hir_def::type_ref::Mutability::Shared => self.ref_expr(*expr, place), + hir_def::type_ref::Mutability::Mut => self.mutate_expr(*expr, place), + } + } + Expr::BinaryOp { lhs, rhs, op } => { + let Some(op) = op else { + return; + }; + if matches!(op, BinaryOp::Assignment { .. }) { + let place = self.place_of_expr(*lhs); + self.mutate_expr(*lhs, place); + self.consume_expr(*rhs); + return; + } + self.consume_expr(*lhs); + self.consume_expr(*rhs); + } + Expr::Range { lhs, rhs, range_type: _ } => { + if let &Some(expr) = lhs { + self.consume_expr(expr); + } + if let &Some(expr) = rhs { + self.consume_expr(expr); + } + } + Expr::Index { base, index } => { + self.select_from_expr(*base); + self.consume_expr(*index); + } + Expr::Closure { .. } => { + let ty = self.expr_ty(tgt_expr); + let TyKind::Closure(id, _) = ty.kind(Interner) else { + never!("closure type is always closure"); + return; + }; + let (captures, _) = + self.result.closure_info.get(id).expect( + "We sort closures, so we should always have data for inner closures", + ); + let mut cc = mem::take(&mut self.current_captures); + cc.extend(captures.iter().filter(|it| self.is_upvar(&it.place)).map(|it| { + CapturedItemWithoutTy { + place: it.place.clone(), + kind: it.kind, + span_stacks: it.span_stacks.clone(), + } + })); + self.current_captures = cc; + } + Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => { + self.consume_exprs(exprs.iter().copied()) + } + &Expr::Assignment { target, value } => { + self.walk_expr(value); + let resolver_guard = + self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); + match self.place_of_expr(value) { + Some(rhs_place) => { + self.inside_assignment = true; + self.consume_with_pat(rhs_place, target); + self.inside_assignment = false; + } + None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] { + Pat::Path(path) => self.mutate_path_pat(path, pat), + &Pat::Expr(expr) => { + let place = self.place_of_expr(expr); + self.mutate_expr(expr, place); + } + _ => {} + }), + } + self.resolver.reset_to_guard(resolver_guard); + } + + Expr::Missing + | Expr::Continue { .. } + | Expr::Path(_) + | Expr::Literal(_) + | Expr::Const(_) + | Expr::Underscore => (), + } + } + + fn walk_pat(&mut self, result: &mut Option, pat: PatId) { + let mut update_result = |ck: CaptureKind| match result { + Some(r) => { + *r = cmp::max(*r, ck); + } + None => *result = Some(ck), + }; + + self.walk_pat_inner( + pat, + &mut update_result, + BorrowKind::Mut { kind: MutBorrowKind::Default }, + ); + } + + fn walk_pat_inner( + &mut self, + p: PatId, + update_result: &mut impl FnMut(CaptureKind), + mut for_mut: BorrowKind, + ) { + match &self.body[p] { + Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Missing + | Pat::Wild + | Pat::Tuple { .. } + | Pat::Expr(_) + | Pat::Or(_) => (), + Pat::TupleStruct { .. } | Pat::Record { .. } => { + if let Some(variant) = self.result.variant_resolution_for_pat(p) { + let adt = variant.adt_id(self.db); + let is_multivariant = match adt { + hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1, + _ => false, + }; + if is_multivariant { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } + } + } + Pat::Slice { .. } + | Pat::ConstBlock(_) + | Pat::Path(_) + | Pat::Lit(_) + | Pat::Range { .. } => { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } + Pat::Bind { id, .. } => match self.result.binding_modes[p] { + crate::BindingMode::Move => { + if self.is_ty_copy(self.result.type_of_binding[*id].clone()) { + update_result(CaptureKind::ByRef(BorrowKind::Shared)); + } else { + update_result(CaptureKind::ByValue); + } + } + crate::BindingMode::Ref(r) => match r { + Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)), + Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)), + }, + }, + } + if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) { + for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }; + } + self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); + } + + fn expr_ty(&self, expr: ExprId) -> Ty { + self.result[expr].clone() + } + + fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { + let mut ty = None; + if let Some(it) = self.result.expr_adjustments.get(&e) + && let Some(it) = it.last() + { + ty = Some(it.target.clone()); + } + ty.unwrap_or_else(|| self.expr_ty(e)) + } + + fn is_upvar(&self, place: &HirPlace) -> bool { + if let Some(c) = self.current_closure { + let InternedClosure(_, root) = self.db.lookup_intern_closure(c); + return self.body.is_binding_upvar(place.local, root); + } + false + } + + fn is_ty_copy(&mut self, ty: Ty) -> bool { + if let TyKind::Closure(id, _) = ty.kind(Interner) { + // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We + // should probably let chalk know which closures are copy, but I don't know how doing it + // without creating query cycles. + return self.result.closure_info.get(id).map(|it| it.1 == FnTrait::Fn).unwrap_or(true); + } + self.table.resolve_completely(ty).is_copy(self.db, self.owner) + } + + fn select_from_expr(&mut self, expr: ExprId) { + self.walk_expr(expr); + } + + fn restrict_precision_for_unsafe(&mut self) { + // FIXME: Borrow checker problems without this. + let mut current_captures = std::mem::take(&mut self.current_captures); + for capture in &mut current_captures { + let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone()); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + self.truncate_capture_spans(capture, 0); + capture.place.projections.truncate(0); + continue; + } + for (i, p) in capture.place.projections.iter().enumerate() { + ty = p.projected_ty( + ty, + self.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + self.owner.module(self.db).krate(), + ); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + self.truncate_capture_spans(capture, i + 1); + capture.place.projections.truncate(i + 1); + break; + } + } + } + self.current_captures = current_captures; + } + + fn adjust_for_move_closure(&mut self) { + // FIXME: Borrow checker won't allow without this. + let mut current_captures = std::mem::take(&mut self.current_captures); + for capture in &mut current_captures { + if let Some(first_deref) = + capture.place.projections.iter().position(|proj| *proj == ProjectionElem::Deref) + { + self.truncate_capture_spans(capture, first_deref); + capture.place.projections.truncate(first_deref); + } + capture.kind = CaptureKind::ByValue; + } + self.current_captures = current_captures; + } + + fn minimize_captures(&mut self) { + self.current_captures.sort_unstable_by_key(|it| it.place.projections.len()); + let mut hash_map = FxHashMap::::default(); + let result = mem::take(&mut self.current_captures); + for mut item in result { + let mut lookup_place = HirPlace { local: item.place.local, projections: vec![] }; + let mut it = item.place.projections.iter(); + let prev_index = loop { + if let Some(k) = hash_map.get(&lookup_place) { + break Some(*k); + } + match it.next() { + Some(it) => { + lookup_place.projections.push(it.clone()); + } + None => break None, + } + }; + match prev_index { + Some(p) => { + let prev_projections_len = self.current_captures[p].place.projections.len(); + self.truncate_capture_spans(&mut item, prev_projections_len); + self.current_captures[p].span_stacks.extend(item.span_stacks); + let len = self.current_captures[p].place.projections.len(); + let kind_after_truncate = + item.place.capture_kind_of_truncated_place(item.kind, len); + self.current_captures[p].kind = + cmp::max(kind_after_truncate, self.current_captures[p].kind); + } + None => { + hash_map.insert(item.place.clone(), self.current_captures.len()); + self.current_captures.push(item); + } + } + } + } + + fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { + let adjustments_count = + self.result.pat_adjustments.get(&tgt_pat).map(|it| it.len()).unwrap_or_default(); + place.projections.extend((0..adjustments_count).map(|_| ProjectionElem::Deref)); + self.current_capture_span_stack + .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat))); + 'reset_span_stack: { + match &self.body[tgt_pat] { + Pat::Missing | Pat::Wild => (), + Pat::Tuple { args, ellipsis } => { + let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); + let field_count = match self.result[tgt_pat].kind(Interner) { + TyKind::Tuple(_, s) => s.len(Interner), + _ => break 'reset_span_stack, + }; + let fields = 0..field_count; + let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev())); + for (&arg, i) in it { + let mut p = place.clone(); + self.current_capture_span_stack.push(MirSpan::PatId(arg)); + p.projections.push(ProjectionElem::Field(Either::Right(TupleFieldId { + tuple: TupleId(!0), // dummy this, as its unused anyways + index: i as u32, + }))); + self.consume_with_pat(p, arg); + self.current_capture_span_stack.pop(); + } + } + Pat::Or(pats) => { + for pat in pats.iter() { + self.consume_with_pat(place.clone(), *pat); + } + } + Pat::Record { args, .. } => { + let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else { + break 'reset_span_stack; + }; + match variant { + VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { + self.consume_place(place) + } + VariantId::StructId(s) => { + let vd = s.fields(self.db); + for field_pat in args.iter() { + let arg = field_pat.pat; + let Some(local_id) = vd.field(&field_pat.name) else { + continue; + }; + let mut p = place.clone(); + self.current_capture_span_stack.push(MirSpan::PatId(arg)); + p.projections.push(ProjectionElem::Field(Either::Left(FieldId { + parent: variant, + local_id, + }))); + self.consume_with_pat(p, arg); + self.current_capture_span_stack.pop(); + } + } + } + } + Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => { + self.consume_place(place) + } + Pat::Path(path) => { + if self.inside_assignment { + self.mutate_path_pat(path, tgt_pat); + } + self.consume_place(place); + } + &Pat::Bind { id, subpat: _ } => { + let mode = self.result.binding_modes[tgt_pat]; + let capture_kind = match mode { + BindingMode::Move => { + self.consume_place(place); + break 'reset_span_stack; + } + BindingMode::Ref(Mutability::Not) => BorrowKind::Shared, + BindingMode::Ref(Mutability::Mut) => { + BorrowKind::Mut { kind: MutBorrowKind::Default } + } + }; + self.current_capture_span_stack.push(MirSpan::BindingId(id)); + self.add_capture(place, CaptureKind::ByRef(capture_kind)); + self.current_capture_span_stack.pop(); + } + Pat::TupleStruct { path: _, args, ellipsis } => { + let Some(variant) = self.result.variant_resolution_for_pat(tgt_pat) else { + break 'reset_span_stack; + }; + match variant { + VariantId::EnumVariantId(_) | VariantId::UnionId(_) => { + self.consume_place(place) + } + VariantId::StructId(s) => { + let vd = s.fields(self.db); + let (al, ar) = + args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); + let fields = vd.fields().iter(); + let it = al + .iter() + .zip(fields.clone()) + .chain(ar.iter().rev().zip(fields.rev())); + for (&arg, (i, _)) in it { + let mut p = place.clone(); + self.current_capture_span_stack.push(MirSpan::PatId(arg)); + p.projections.push(ProjectionElem::Field(Either::Left(FieldId { + parent: variant, + local_id: i, + }))); + self.consume_with_pat(p, arg); + self.current_capture_span_stack.pop(); + } + } + } + } + Pat::Ref { pat, mutability: _ } => { + self.current_capture_span_stack.push(MirSpan::PatId(tgt_pat)); + place.projections.push(ProjectionElem::Deref); + self.consume_with_pat(place, *pat); + self.current_capture_span_stack.pop(); + } + Pat::Box { .. } => (), // not supported + &Pat::Expr(expr) => { + self.consume_place(place); + let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack); + let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); + let lhs_place = self.place_of_expr(expr); + self.mutate_expr(expr, lhs_place); + self.inside_assignment = old_inside_assignment; + self.current_capture_span_stack = pat_capture_span_stack; + } + } + } + self.current_capture_span_stack + .truncate(self.current_capture_span_stack.len() - adjustments_count); + } + + fn consume_exprs(&mut self, exprs: impl Iterator) { + for expr in exprs { + self.consume_expr(expr); + } + } + + fn closure_kind(&self) -> FnTrait { + let mut r = FnTrait::Fn; + for it in &self.current_captures { + r = cmp::min( + r, + match &it.kind { + CaptureKind::ByRef(BorrowKind::Mut { .. }) => FnTrait::FnMut, + CaptureKind::ByRef(BorrowKind::Shallow | BorrowKind::Shared) => FnTrait::Fn, + CaptureKind::ByValue => FnTrait::FnOnce, + }, + ) + } + r + } + + fn analyze_closure(&mut self, closure: ClosureId) -> FnTrait { + let InternedClosure(_, root) = self.db.lookup_intern_closure(closure.into()); + self.current_closure = Some(closure.into()); + let Expr::Closure { body, capture_by, .. } = &self.body[root] else { + unreachable!("Closure expression id is always closure"); + }; + self.consume_expr(*body); + for item in &self.current_captures { + if matches!( + item.kind, + CaptureKind::ByRef(BorrowKind::Mut { + kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow + }) + ) && !item.place.projections.contains(&ProjectionElem::Deref) + { + // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in + // MIR. I didn't do that due duplicate diagnostics. + self.result.mutated_bindings_in_closure.insert(item.place.local); + } + } + self.restrict_precision_for_unsafe(); + // `closure_kind` should be done before adjust_for_move_closure + // If there exists pre-deduced kind of a closure, use it instead of one determined by capture, as rustc does. + // rustc also does diagnostics here if the latter is not a subtype of the former. + let closure_kind = self + .result + .closure_info + .get(&closure) + .map_or_else(|| self.closure_kind(), |info| info.1); + match capture_by { + CaptureBy::Value => self.adjust_for_move_closure(), + CaptureBy::Ref => (), + } + self.minimize_captures(); + self.strip_captures_ref_span(); + let result = mem::take(&mut self.current_captures); + let captures = result.into_iter().map(|it| it.with_ty(self)).collect::>(); + self.result.closure_info.insert(closure, (captures, closure_kind)); + closure_kind + } + + fn strip_captures_ref_span(&mut self) { + // FIXME: Borrow checker won't allow without this. + let mut captures = std::mem::take(&mut self.current_captures); + for capture in &mut captures { + if matches!(capture.kind, CaptureKind::ByValue) { + for span_stack in &mut capture.span_stacks { + if span_stack[span_stack.len() - 1].is_ref_span(self.body) { + span_stack.truncate(span_stack.len() - 1); + } + } + } + } + self.current_captures = captures; + } + + pub(crate) fn infer_closures(&mut self) { + let deferred_closures = self.sort_closures(); + for (closure, exprs) in deferred_closures.into_iter().rev() { + self.current_captures = vec![]; + let kind = self.analyze_closure(closure); + + for (derefed_callee, callee_ty, params, expr) in exprs { + if let &Expr::Call { callee, .. } = &self.body[expr] { + let mut adjustments = + self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); + self.write_fn_trait_method_resolution( + kind, + &derefed_callee, + &mut adjustments, + &callee_ty, + ¶ms, + expr, + ); + self.result.expr_adjustments.insert(callee, adjustments.into_boxed_slice()); + } + } + } + } + + /// We want to analyze some closures before others, to have a correct analysis: + /// * We should analyze nested closures before the parent, since the parent should capture some of + /// the things that its children captures. + /// * If a closure calls another closure, we need to analyze the callee, to find out how we should + /// capture it (e.g. by move for FnOnce) + /// + /// These dependencies are collected in the main inference. We do a topological sort in this function. It + /// will consume the `deferred_closures` field and return its content in a sorted vector. + fn sort_closures(&mut self) -> Vec<(ClosureId, Vec<(Ty, Ty, Vec, ExprId)>)> { + let mut deferred_closures = mem::take(&mut self.deferred_closures); + let mut dependents_count: FxHashMap = + deferred_closures.keys().map(|it| ((*it).into(), 0)).collect(); + for deps in self.closure_dependencies.values() { + for dep in deps { + *dependents_count.entry((*dep).into()).or_default() += 1; + } + } + let mut queue: Vec<_> = deferred_closures + .keys() + .copied() + .filter(|&it| dependents_count[&it.into()] == 0) + .collect(); + let mut result = vec![]; + while let Some(it) = queue.pop() { + if let Some(d) = deferred_closures.remove(&it) { + result.push((it.into(), d)); + } + for &dep in self.closure_dependencies.get(&it).into_iter().flat_map(|it| it.iter()) { + let cnt = dependents_count.get_mut(&dep.into()).unwrap(); + *cnt -= 1; + if *cnt == 0 { + queue.push(dep); + } + } + } + assert!(deferred_closures.is_empty(), "we should have analyzed all closures"); + result + } + + pub(crate) fn add_current_closure_dependency(&mut self, dep: InternedClosureId) { + if let Some(c) = self.current_closure + && !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep) + { + self.closure_dependencies.entry(c).or_default().push(dep); + } + + fn dep_creates_cycle( + closure_dependencies: &FxHashMap>, + visited: &mut FxHashSet, + from: InternedClosureId, + to: InternedClosureId, + ) -> bool { + if !visited.insert(from) { + return false; + } + + if from == to { + return true; + } + + if let Some(deps) = closure_dependencies.get(&to) { + for dep in deps { + if dep_creates_cycle(closure_dependencies, visited, from, *dep) { + return true; + } + } + } + + false + } + } +} + +/// Call this only when the last span in the stack isn't a split. +fn apply_adjusts_to_place( + current_capture_span_stack: &mut Vec, + mut r: HirPlace, + adjustments: &[Adjustment], +) -> Option { + let span = *current_capture_span_stack.last().expect("empty capture span stack"); + for adj in adjustments { + match &adj.kind { + Adjust::Deref(None) => { + current_capture_span_stack.push(span); + r.projections.push(ProjectionElem::Deref); + } + _ => return None, + } + } + Some(r) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index df516662bfd37..88b10e87e531e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -1,452 +1,388 @@ -//! Coercion logic. Coercions are certain type conversions that can implicitly -//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions -//! like going from `&Vec` to `&[T]`. +//! # Type Coercion //! -//! See and -//! `rustc_hir_analysis/check/coercion.rs`. - -use std::iter; - -use chalk_ir::{BoundVar, Mutability, TyKind, TyVariableKind, cast::Cast}; -use hir_def::{hir::ExprId, lang_item::LangItem}; -use rustc_type_ir::solve::Certainty; -use stdx::always; +//! Under certain circumstances we will coerce from one type to another, +//! for example by auto-borrowing. This occurs in situations where the +//! compiler has a firm 'expected type' that was supplied from the user, +//! and where the actual type is similar to that expected type in purpose +//! but not in representation (so actual subtyping is inappropriate). +//! +//! ## Reborrowing +//! +//! Note that if we are expecting a reference, we will *reborrow* +//! even if the argument provided was already a reference. This is +//! useful for freezing mut things (that is, when the expected type is &T +//! but you have &mut T) and also for avoiding the linearity +//! of mut things (when the expected is &mut T and you have &mut T). See +//! the various `tests/ui/coerce/*.rs` tests for +//! examples of where this is useful. +//! +//! ## Subtle note +//! +//! When inferring the generic arguments of functions, the argument +//! order is relevant, which can lead to the following edge case: +//! +//! ```ignore (illustrative) +//! fn foo(a: T, b: T) { +//! // ... +//! } +//! +//! foo(&7i32, &mut 7i32); +//! // This compiles, as we first infer `T` to be `&i32`, +//! // and then coerce `&mut 7i32` to `&7i32`. +//! +//! foo(&mut 7i32, &7i32); +//! // This does not compile, as we first infer `T` to be `&mut i32` +//! // and are then unable to coerce `&7i32` to `&mut i32`. +//! ``` + +use chalk_ir::cast::Cast; +use hir_def::{ + CallableDefId, + hir::{ExprId, ExprOrPatId}, + lang_item::LangItem, + signatures::FunctionSignature, +}; +use intern::sym; +use rustc_ast_ir::Mutability; +use rustc_type_ir::{ + TypeAndMut, + error::TypeError, + inherent::{IntoKind, Safety, Ty as _}, +}; +use smallvec::{SmallVec, smallvec}; +use tracing::{debug, instrument}; use triomphe::Arc; use crate::{ - Canonical, FnAbi, FnPointer, FnSig, Goal, Interner, Lifetime, Substitution, TraitEnvironment, - Ty, TyBuilder, TyExt, - autoderef::{Autoderef, AutoderefKind}, - db::HirDatabase, - infer::{ - Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, - TypeError, TypeMismatch, + Adjust, Adjustment, AutoBorrow, Interner, PointerCast, TargetFeatures, TraitEnvironment, + autoderef::Autoderef, + db::{HirDatabase, InternedClosureId}, + infer::{AllowTwoPhase, InferenceContext, TypeMismatch, unify::InferenceTable}, + next_solver::{ + Binder, CallableIdWrapper, ClauseKind, CoercePredicate, DbInterner, ErrorGuaranteed, + GenericArgs, PolyFnSig, PredicateKind, Region, SolverDefId, TraitRef, Ty, TyKind, + infer::{ + DefineOpaqueTypes, InferCtxt, InferOk, InferResult, + relate::RelateResult, + select::{ImplSource, SelectionError}, + traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations}, + }, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + obligation_ctxt::ObligationCtxt, }, - next_solver, - utils::ClosureSubst, + utils::TargetFeatureIsSafeInTarget, }; -use super::unify::InferenceTable; - -pub(crate) type CoerceResult<'db> = Result, Ty)>, TypeError>; - -/// Do not require any adjustments, i.e. coerce `x -> x`. -fn identity(_: Ty) -> Vec { - vec![] +struct Coerce<'a, 'b, 'db> { + table: &'a mut InferenceTable<'db>, + has_errors: &'a mut bool, + target_features: &'a mut dyn FnMut() -> (&'b TargetFeatures, TargetFeatureIsSafeInTarget), + use_lub: bool, + /// Determines whether or not allow_two_phase_borrow is set on any + /// autoref adjustments we create while coercing. We don't want to + /// allow deref coercions to create two-phase borrows, at least initially, + /// but we do need two-phase borrows for function argument reborrows. + /// See rust#47489 and rust#48598 + /// See docs on the "AllowTwoPhase" type for a more detailed discussion + allow_two_phase: AllowTwoPhase, + /// Whether we allow `NeverToAny` coercions. This is unsound if we're + /// coercing a place expression without it counting as a read in the MIR. + /// This is a side-effect of HIR not really having a great distinction + /// between places and values. + coerce_never: bool, + cause: ObligationCause, } -fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec { - move |target| vec![Adjustment { kind, target }] +type CoerceResult<'db> = InferResult<'db, (Vec, Ty<'db>)>; + +/// Coercing a mutable reference to an immutable works, while +/// coercing `&T` to `&mut T` should be forbidden. +fn coerce_mutbls<'db>(from_mutbl: Mutability, to_mutbl: Mutability) -> RelateResult<'db, ()> { + if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } } /// This always returns `Ok(...)`. fn success<'db>( adj: Vec, - target: Ty, - goals: Vec>>, + target: Ty<'db>, + obligations: PredicateObligations<'db>, ) -> CoerceResult<'db> { - Ok(InferOk { goals, value: (adj, target) }) -} - -pub(super) enum CoercionCause { - // FIXME: Make better use of this. Right now things like return and break without a value - // use it to point to themselves, causing us to report a mismatch on those expressions even - // though technically they themselves are `!` - Expr(ExprId), -} - -#[derive(Clone, Debug)] -pub(super) struct CoerceMany { - expected_ty: Ty, - final_ty: Option, - expressions: Vec, + Ok(InferOk { value: (adj, target), obligations }) } -impl CoerceMany { - pub(super) fn new(expected: Ty) -> Self { - CoerceMany { expected_ty: expected, final_ty: None, expressions: vec![] } - } - - /// Returns the "expected type" with which this coercion was - /// constructed. This represents the "downward propagated" type - /// that was given to us at the start of typing whatever construct - /// we are typing (e.g., the match expression). - /// - /// Typically, this is used as the expected type when - /// type-checking each of the alternative expressions whose types - /// we are trying to merge. - pub(super) fn expected_ty(&self) -> Ty { - self.expected_ty.clone() - } - - /// Returns the current "merged type", representing our best-guess - /// at the LUB of the expressions we've seen so far (if any). This - /// isn't *final* until you call `self.complete()`, which will return - /// the merged type. - pub(super) fn merged_ty(&self) -> Ty { - self.final_ty.clone().unwrap_or_else(|| self.expected_ty.clone()) +impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { + #[inline] + fn set_tainted_by_errors(&mut self) { + *self.has_errors = true; } - pub(super) fn complete(self, ctx: &mut InferenceContext<'_>) -> Ty { - if let Some(final_ty) = self.final_ty { - final_ty - } else { - ctx.result.standard_types.never.clone() - } + #[inline] + fn interner(&self) -> DbInterner<'db> { + self.table.interner } - pub(super) fn coerce_forced_unit( - &mut self, - ctx: &mut InferenceContext<'_>, - cause: CoercionCause, - ) { - self.coerce(ctx, None, &ctx.result.standard_types.unit.clone(), cause) + #[inline] + fn infer_ctxt(&self) -> &InferCtxt<'db> { + &self.table.infer_ctxt } - /// Merge two types from different branches, with possible coercion. - /// - /// Mostly this means trying to coerce one to the other, but - /// - if we have two function types for different functions or closures, we need to - /// coerce both to function pointers; - /// - if we were concerned with lifetime subtyping, we'd need to look for a - /// least upper bound. - pub(super) fn coerce<'db>( + pub(crate) fn commit_if_ok( &mut self, - ctx: &mut InferenceContext<'db>, - expr: Option, - expr_ty: &Ty, - cause: CoercionCause, - ) { - let expr_ty = ctx.resolve_ty_shallow(expr_ty); - self.expected_ty = ctx.resolve_ty_shallow(&self.expected_ty); - - // Special case: two function types. Try to coerce both to - // pointers to have a chance at getting a match. See - // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 - let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) { - (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) - if x == y && ctx.table.unify(&self.merged_ty(), &expr_ty) => - { - None - } - (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None, - (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => { - // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, - // we should be coercing the closure to a fn pointer of the safety of the FnDef - cov_mark::hit!(coerce_fn_reification); - let sig = - self.merged_ty().callable_sig(ctx.db).expect("FnDef without callable sig"); - Some(sig) - } - _ => None, - }; - if let Some(sig) = sig { - let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner); - let result1 = ctx.table.coerce_inner(self.merged_ty(), &target_ty, CoerceNever::Yes); - let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty, CoerceNever::Yes); - if let (Ok(result1), Ok(result2)) = (result1, result2) { - ctx.table.register_infer_ok(InferOk { value: (), goals: result1.goals }); - for &e in &self.expressions { - ctx.write_expr_adj(e, result1.value.0.clone().into_boxed_slice()); - } - ctx.table.register_infer_ok(InferOk { value: (), goals: result2.goals }); - if let Some(expr) = expr { - ctx.write_expr_adj(expr, result2.value.0.into_boxed_slice()); - self.expressions.push(expr); - } - return self.final_ty = Some(target_ty); + f: impl FnOnce(&mut Self) -> Result, + ) -> Result { + let snapshot = self.table.snapshot(); + let result = f(self); + match result { + Ok(_) => {} + Err(_) => { + self.table.rollback_to(snapshot); } } + result + } - // It might not seem like it, but order is important here: If the expected - // type is a type variable and the new one is `!`, trying it the other - // way around first would mean we make the type variable `!`, instead of - // just marking it as possibly diverging. - // - // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335) - // First try to coerce the new expression to the type of the previous ones, - // but only if the new expression has no coercion already applied to it. - if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) - && let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) - { - self.final_ty = Some(res); - if let Some(expr) = expr { - self.expressions.push(expr); - } - return; - } + fn unify_raw(&mut self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> { + debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); + self.commit_if_ok(|this| { + let at = this.infer_ctxt().at(&this.cause, this.table.param_env); - if let Ok((adjustments, res)) = - ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes) - { - self.final_ty = Some(res); - for &e in &self.expressions { - ctx.write_expr_adj(e, adjustments.clone().into_boxed_slice()); - } - } else { - match cause { - CoercionCause::Expr(id) => { - ctx.result.type_mismatches.insert( - id.into(), - TypeMismatch { expected: self.merged_ty(), actual: expr_ty.clone() }, - ); + let res = if this.use_lub { + at.lub(b, a) + } else { + at.sup(DefineOpaqueTypes::Yes, b, a) + .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations }) + }; + + // In the new solver, lazy norm may allow us to shallowly equate + // more types, but we emit possibly impossible-to-satisfy obligations. + // Filter these cases out to make sure our coercion is more accurate. + match res { + Ok(InferOk { value, obligations }) => { + let mut ocx = ObligationCtxt::new(this.infer_ctxt()); + ocx.register_obligations(obligations); + if ocx.select_where_possible().is_empty() { + Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) + } else { + Err(TypeError::Mismatch) + } } + res => res, } - cov_mark::hit!(coerce_merge_fail_fallback); - } - if let Some(expr) = expr { - self.expressions.push(expr); - } + }) } -} - -pub fn could_coerce( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> bool { - coerce(db, env, tys).is_ok() -} - -pub(crate) fn coerce( - db: &dyn HirDatabase, - env: Arc, - tys: &Canonical<(Ty, Ty)>, -) -> Result<(Vec, Ty), TypeError> { - let mut table = InferenceTable::new(db, env); - let vars = table.fresh_subst(tys.binders.as_slice(Interner)); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); - let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); - let (adjustments, ty) = table.coerce(&ty1_with_vars, &ty2_with_vars, CoerceNever::Yes)?; - // default any type vars that weren't unified back to their original bound vars - // (kind of hacky) - let find_var = |iv| { - vars.iter(Interner).position(|v| match v.interned() { - chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner), - chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), - } == Some(iv)) - }; - let fallback = |iv, kind, default, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), - chalk_ir::VariableKind::Lifetime => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)), - chalk_ir::VariableKind::Const(ty) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)), - }; - // FIXME also map the types in the adjustments - Ok((adjustments, table.resolve_with_fallback(ty, &fallback))) -} -#[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) enum CoerceNever { - Yes, - No, -} - -impl InferenceContext<'_> { - /// Unify two types, but may coerce the first one to the second one - /// using "implicit coercion rules" if needed. - pub(super) fn coerce( - &mut self, - expr: Option, - from_ty: &Ty, - to_ty: &Ty, - // [Comment from rustc](https://github.com/rust-lang/rust/blob/4cc494bbfe9911d24f3ee521f98d5c6bb7e3ffe8/compiler/rustc_hir_typeck/src/coercion.rs#L85-L89) - // Whether we allow `NeverToAny` coercions. This is unsound if we're - // coercing a place expression without it counting as a read in the MIR. - // This is a side-effect of HIR not really having a great distinction - // between places and values. - coerce_never: CoerceNever, - ) -> Result { - let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?; - if let Some(expr) = expr { - self.write_expr_adj(expr, adjustments.into_boxed_slice()); - } - Ok(ty) + /// Unify two types (using sub or lub). + fn unify(&mut self, a: Ty<'db>, b: Ty<'db>) -> CoerceResult<'db> { + self.unify_raw(a, b) + .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations)) } - fn coerce_inner( + /// Unify two types (using sub or lub) and produce a specific coercion. + fn unify_and( &mut self, - from_ty: &Ty, - to_ty: &Ty, - coerce_never: CoerceNever, - ) -> Result<(Vec, Ty), TypeError> { - let from_ty = self.resolve_ty_shallow(from_ty); - let to_ty = self.resolve_ty_shallow(to_ty); - self.table.coerce(&from_ty, &to_ty, coerce_never) + a: Ty<'db>, + b: Ty<'db>, + adjustments: impl IntoIterator, + final_adjustment: Adjust, + ) -> CoerceResult<'db> { + self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| { + success( + adjustments + .into_iter() + .chain(std::iter::once(Adjustment { + target: ty.to_chalk(self.interner()), + kind: final_adjustment, + })) + .collect(), + ty, + obligations, + ) + }) } -} -impl<'db> InferenceTable<'db> { - /// Unify two types, but may coerce the first one to the second one - /// using "implicit coercion rules" if needed. - pub(crate) fn coerce( - &mut self, - from_ty: &Ty, - to_ty: &Ty, - coerce_never: CoerceNever, - ) -> Result<(Vec, Ty), TypeError> { - let from_ty = self.structurally_resolve_type(from_ty); - let to_ty = self.structurally_resolve_type(to_ty); - match self.coerce_inner(from_ty, &to_ty, coerce_never) { - Ok(InferOk { value: (adjustments, ty), goals }) => { - self.register_infer_ok(InferOk { value: (), goals }); - Ok((adjustments, ty)) - } - Err(e) => { - // FIXME deal with error - Err(e) + #[instrument(skip(self))] + fn coerce(&mut self, a: Ty<'db>, b: Ty<'db>) -> CoerceResult<'db> { + // First, remove any resolved type variables (at the top level, at least): + let a = self.table.shallow_resolve(a); + let b = self.table.shallow_resolve(b); + debug!("Coerce.tys({:?} => {:?})", a, b); + + // Coercing from `!` to any type is allowed: + if a.is_never() { + // If we're coercing into an inference var, mark it as possibly diverging. + // FIXME: rustc does this differently. + if let TyKind::Infer(rustc_type_ir::TyVar(b)) = b.kind() { + self.table.set_diverging(b.as_u32().into(), chalk_ir::TyVariableKind::General); } - } - } - fn coerce_inner( - &mut self, - from_ty: Ty, - to_ty: &Ty, - coerce_never: CoerceNever, - ) -> CoerceResult<'db> { - if from_ty.is_never() { - if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) { - self.set_diverging(*tv, TyVariableKind::General); - } - if coerce_never == CoerceNever::Yes { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]); + if self.coerce_never { + return success( + vec![Adjustment { + kind: Adjust::NeverToAny, + target: b.to_chalk(self.interner()), + }], + b, + PredicateObligations::new(), + ); } else { - return self.unify_and(&from_ty, to_ty, identity); + // Otherwise the only coercion we can do is unification. + return self.unify(a, b); } } // If we are coercing into a TAIT, coerce into its proxy inference var, instead. - let mut to_ty = to_ty; - let _to; - if let Some(tait_table) = &self.tait_coercion_table - && let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) - && !matches!(from_ty.kind(Interner), TyKind::InferenceVar(..) | TyKind::OpaqueType(..)) - && let Some(ty) = tait_table.get(opaque_ty_id) + // FIXME(next-solver): This should not be here. This is not how rustc does thing, and it also not allows us + // to normalize opaques defined in our scopes. Instead, we should properly register + // `TypingMode::Analysis::defining_opaque_types_and_generators`, and rely on the solver to reveal + // them for us (we'll also need some global-like registry for the values, something we cannot + // really implement, therefore we can really support only RPITs and ITIAT or the new `#[define_opaque]` + // TAIT, not the old global TAIT). + let mut b = b; + if let Some(tait_table) = &self.table.tait_coercion_table + && let TyKind::Alias(rustc_type_ir::Opaque, opaque_ty) = b.kind() + && let SolverDefId::InternedOpaqueTyId(opaque_ty_id) = opaque_ty.def_id + && !matches!(a.kind(), TyKind::Infer(..) | TyKind::Alias(rustc_type_ir::Opaque, _)) + && let Some(ty) = tait_table.get(&opaque_ty_id.into()) { - _to = ty.clone(); - to_ty = &_to; + b = ty.to_nextsolver(self.interner()); + b = self.table.shallow_resolve(b); + } + let b = b; + + // Coercing *from* an unresolved inference variable means that + // we have no information about the source type. This will always + // ultimately fall back to some form of subtyping. + if a.is_infer() { + return self.coerce_from_inference_variable(a, b); } // Consider coercing the subtype to a DST - if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) { - return Ok(ret); + // + // NOTE: this is wrapped in a `commit_if_ok` because it creates + // a "spurious" type variable, and we don't want to have that + // type variable in memory if the coercion fails. + let unsize = self.commit_if_ok(|this| this.coerce_unsized(a, b)); + match unsize { + Ok(_) => { + debug!("coerce: unsize successful"); + return unsize; + } + Err(error) => { + debug!(?error, "coerce: unsize failed"); + } } - // Examine the supertype and consider auto-borrowing. - match to_ty.kind(Interner) { - TyKind::Raw(mt, _) => return self.coerce_ptr(from_ty, to_ty, *mt), - TyKind::Ref(mt, lt, _) => return self.coerce_ref(from_ty, to_ty, *mt, lt), + // Examine the supertype and consider type-specific coercions, such + // as auto-borrowing, coercing pointer mutability, a `dyn*` coercion, + // or pin-ergonomics. + match b.kind() { + TyKind::RawPtr(_, b_mutbl) => { + return self.coerce_raw_ptr(a, b, b_mutbl); + } + TyKind::Ref(r_b, _, mutbl_b) => { + return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); + } _ => {} } - match from_ty.kind(Interner) { + match a.kind() { TyKind::FnDef(..) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). // Additionally, we permit coercion of function // items to drop the unsafe qualifier. - self.coerce_from_fn_item(from_ty, to_ty) + self.coerce_from_fn_item(a, b) } - TyKind::Function(from_fn_ptr) => { + TyKind::FnPtr(a_sig_tys, a_hdr) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. - self.coerce_from_fn_pointer(from_ty.clone(), from_fn_ptr, to_ty) + self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b) } - TyKind::Closure(_, from_substs) => { + TyKind::Closure(closure_def_id_a, args_a) => { // Non-capturing closures are coercible to // function pointers or unsafe function pointers. // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(from_ty.clone(), from_substs, to_ty) + self.coerce_closure_to_fn(a, closure_def_id_a.0, args_a, b) } _ => { // Otherwise, just use unification rules. - self.unify_and(&from_ty, to_ty, identity) + self.unify(a, b) } } } - /// Unify two types (using sub or lub) and produce a specific coercion. - fn unify_and(&mut self, t1: &Ty, t2: &Ty, f: F) -> CoerceResult<'db> - where - F: FnOnce(Ty) -> Vec, - { - self.try_unify(t1, t2) - .and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals)) - } - - fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult<'db> { - let (is_ref, from_mt, from_inner) = match from_ty.kind(Interner) { - TyKind::Ref(mt, _, ty) => (true, mt, ty), - TyKind::Raw(mt, ty) => (false, mt, ty), - _ => return self.unify_and(&from_ty, to_ty, identity), - }; - - coerce_mutabilities(*from_mt, to_mt)?; - - // Check that the types which they point at are compatible. - let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(Interner); + /// Coercing *from* an inference variable. In this case, we have no information + /// about the source type, so we can't really do a true coercion and we always + /// fall back to subtyping (`unify_and`). + fn coerce_from_inference_variable(&mut self, a: Ty<'db>, b: Ty<'db>) -> CoerceResult<'db> { + debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); + debug_assert!(a.is_infer() && self.table.shallow_resolve(a) == a); + debug_assert!(self.table.shallow_resolve(b) == b); + + if b.is_infer() { + // Two unresolved type variables: create a `Coerce` predicate. + let target_ty = if self.use_lub { self.table.next_ty_var() } else { b }; + + let mut obligations = PredicateObligations::with_capacity(2); + for &source_ty in &[a, b] { + if source_ty != target_ty { + obligations.push(Obligation::new( + self.interner(), + self.cause.clone(), + self.table.param_env, + Binder::dummy(PredicateKind::Coerce(CoercePredicate { + a: source_ty, + b: target_ty, + })), + )); + } + } - // Although references and raw ptrs have the same - // representation, we still register an Adjust::DerefRef so that - // regionck knows that the region for `a` must be valid here. - if is_ref { - self.unify_and(&from_raw, to_ty, |target| { - vec![ - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)), target }, - ] - }) - } else if *from_mt != to_mt { - self.unify_and( - &from_raw, - to_ty, - simple(Adjust::Pointer(PointerCast::MutToConstPointer)), - ) + debug!( + "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", + target_ty, obligations + ); + success(vec![], target_ty, obligations) } else { - self.unify_and(&from_raw, to_ty, identity) + // One unresolved type variable: just apply subtyping, we may be able + // to do something useful. + self.unify(a, b) } } /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_ref( + fn coerce_borrowed_pointer( &mut self, - from_ty: Ty, - to_ty: &Ty, - to_mt: Mutability, - to_lt: &Lifetime, + a: Ty<'db>, + b: Ty<'db>, + r_b: Region<'db>, + mutbl_b: Mutability, ) -> CoerceResult<'db> { - let (_from_lt, from_mt) = match from_ty.kind(Interner) { - TyKind::Ref(mt, lt, _) => { - coerce_mutabilities(*mt, to_mt)?; - (lt.clone(), *mt) // clone is probably not good? + debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); + debug_assert!(self.table.shallow_resolve(a) == a); + debug_assert!(self.table.shallow_resolve(b) == b); + + // If we have a parameter of type `&M T_a` and the value + // provided is `expr`, we will be adding an implicit borrow, + // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore, + // to type check, we will construct the type that `&M*expr` would + // yield. + + let (r_a, mt_a) = match a.kind() { + TyKind::Ref(r_a, ty, mutbl) => { + let mt_a = TypeAndMut::> { ty, mutbl }; + coerce_mutbls(mt_a.mutbl, mutbl_b)?; + (r_a, mt_a) } - _ => return self.unify_and(&from_ty, to_ty, identity), + _ => return self.unify(a, b), }; - // NOTE: this code is mostly copied and adapted from rustc, and - // currently more complicated than necessary, carrying errors around - // etc.. This complication will become necessary when we actually track - // details of coercion errors though, so I think it's useful to leave - // the structure like it is. - - let snapshot = self.snapshot(); - - let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false); let mut first_error = None; + let mut r_borrow_var = None; + let mut autoderef = Autoderef::new(self.table, a); let mut found = None; while let Some((referent_ty, autoderefs)) = autoderef.next() { @@ -456,7 +392,7 @@ impl<'db> InferenceTable<'db> { continue; } - // At this point, we have deref'd `a` to `referent_ty`. So + // At this point, we have deref'd `a` to `referent_ty`. So // imagine we are coercing from `&'a mut Vec` to `&'b mut [T]`. // In the autoderef loop for `&'a mut Vec`, we would get // three callbacks: @@ -478,11 +414,85 @@ impl<'db> InferenceTable<'db> { // compare those. Note that this means we use the target // mutability [1], since it may be that we are coercing // from `&mut T` to `&U`. - let lt = to_lt; // FIXME: Involve rustc LUB and SUB flag checks - let derefd_from_ty = TyKind::Ref(to_mt, lt.clone(), referent_ty).intern(Interner); - match autoderef.table.try_unify(&derefd_from_ty, to_ty) { - Ok(result) => { - found = Some(result.map(|()| derefd_from_ty)); + // + // One fine point concerns the region that we use. We + // choose the region such that the region of the final + // type that results from `unify` will be the region we + // want for the autoref: + // + // - if in sub mode, that means we want to use `'b` (the + // region from the target reference) for both + // pointers [2]. This is because sub mode (somewhat + // arbitrarily) returns the subtype region. In the case + // where we are coercing to a target type, we know we + // want to use that target type region (`'b`) because -- + // for the program to type-check -- it must be the + // smaller of the two. + // - One fine point. It may be surprising that we can + // use `'b` without relating `'a` and `'b`. The reason + // that this is ok is that what we produce is + // effectively a `&'b *x` expression (if you could + // annotate the region of a borrow), and regionck has + // code that adds edges from the region of a borrow + // (`'b`, here) into the regions in the borrowed + // expression (`*x`, here). (Search for "link".) + // - if in lub mode, things can get fairly complicated. The + // easiest thing is just to make a fresh + // region variable [4], which effectively means we defer + // the decision to region inference (and regionck, which will add + // some more edges to this variable). However, this can wind up + // creating a crippling number of variables in some cases -- + // e.g., #32278 -- so we optimize one particular case [3]. + // Let me try to explain with some examples: + // - The "running example" above represents the simple case, + // where we have one `&` reference at the outer level and + // ownership all the rest of the way down. In this case, + // we want `LUB('a, 'b)` as the resulting region. + // - However, if there are nested borrows, that region is + // too strong. Consider a coercion from `&'a &'x Rc` to + // `&'b T`. In this case, `'a` is actually irrelevant. + // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)` + // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`). + // (The errors actually show up in borrowck, typically, because + // this extra edge causes the region `'a` to be inferred to something + // too big, which then results in borrowck errors.) + // - We could track the innermost shared reference, but there is already + // code in regionck that has the job of creating links between + // the region of a borrow and the regions in the thing being + // borrowed (here, `'a` and `'x`), and it knows how to handle + // all the various cases. So instead we just make a region variable + // and let regionck figure it out. + let r = if !self.use_lub { + r_b // [2] above + } else if autoderefs == 1 { + r_a // [3] above + } else { + if r_borrow_var.is_none() { + // create var lazily, at most once + let r = autoderef.table.next_region_var(); + r_borrow_var = Some(r); // [4] above + } + r_borrow_var.unwrap() + }; + let derefd_ty_a = Ty::new_ref( + autoderef.table.interner, + r, + referent_ty, + mutbl_b, // [1] above + ); + // We need to construct a new `Coerce` because of lifetimes. + let mut coerce = Coerce { + table: autoderef.table, + has_errors: self.has_errors, + target_features: self.target_features, + use_lub: self.use_lub, + allow_two_phase: self.allow_two_phase, + coerce_never: self.coerce_never, + cause: self.cause.clone(), + }; + match coerce.unify_raw(derefd_ty_a, b) { + Ok(ok) => { + found = Some(ok); break; } Err(err) => { @@ -498,18 +508,24 @@ impl<'db> InferenceTable<'db> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let InferOk { value: ty, goals } = match found { - Some(d) => d, - None => { - self.rollback_to(snapshot); - let err = first_error.expect("coerce_borrowed_pointer had no error"); - return Err(err); + let Some(InferOk { value: ty, mut obligations }) = found else { + if let Some(first_error) = first_error { + debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error); + return Err(first_error); + } else { + // This may happen in the new trait solver since autoderef requires + // the pointee to be structurally normalizable, or else it'll just bail. + // So when we have a type like `&`, then we get no + // autoderef steps (even though there should be at least one). That means + // we get no type mismatches, since the loop above just exits early. + return Err(TypeError::Mismatch); } }; - if ty == from_ty && from_mt == Mutability::Not && autoderef.step_count() == 1 { + + if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as - // we started with. In that case, just skip it + // we started with. In that case, just skip it // altogether. This is just an optimization. // // Note that for `&mut`, we DO want to reborrow -- @@ -518,259 +534,1091 @@ impl<'db> InferenceTable<'db> { // `self.x` both have `&mut `type would be a move of // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. - always!(to_mt == Mutability::Not); // can only coerce &T -> &U - return success(vec![], ty, goals); + assert!(mutbl_b.is_not()); // can only coerce &T -> &U + return success(vec![], ty, obligations); } - let mut adjustments = auto_deref_adjust_steps(&autoderef); + let InferOk { value: mut adjustments, obligations: o } = + autoderef.adjust_steps_as_infer_ok(); + obligations.extend(o); + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. + let TyKind::Ref(region, _, _) = ty.kind() else { + panic!("expected a ref type, got {:?}", ty); + }; adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(to_lt.clone(), to_mt)), - target: ty.clone(), + kind: Adjust::Borrow(AutoBorrow::Ref( + region.to_chalk(self.interner()), + mutbl_b.to_chalk(self.interner()), + )), + target: ty.to_chalk(self.interner()), }); - success(adjustments, ty, goals) + debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, adjustments); + + success(adjustments, ty, obligations) } - /// Attempts to coerce from the type of a Rust function item into a function pointer. - fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult<'db> { - match to_ty.kind(Interner) { - TyKind::Function(_) => { - let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig"); - - // FIXME check ABI: Intrinsics are not coercible to function pointers - // FIXME Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396) - - // FIXME rustc normalizes assoc types in the sig here, not sure if necessary - - let from_sig = from_sig.to_fn_ptr(); - let from_fn_pointer = TyKind::Function(from_sig.clone()).intern(Interner); - let ok = self.coerce_from_safe_fn( - from_fn_pointer.clone(), - &from_sig, - to_ty, - |unsafe_ty| { - vec![ - Adjustment { - kind: Adjust::Pointer(PointerCast::ReifyFnPointer), - target: from_fn_pointer, - }, - Adjustment { - kind: Adjust::Pointer(PointerCast::UnsafeFnPointer), - target: unsafe_ty, - }, - ] + /// Performs [unsized coercion] by emulating a fulfillment loop on a + /// `CoerceUnsized` goal until all `CoerceUnsized` and `Unsize` goals + /// are successfully selected. + /// + /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) + #[instrument(skip(self), level = "debug")] + fn coerce_unsized(&mut self, source: Ty<'db>, target: Ty<'db>) -> CoerceResult<'db> { + debug!(?source, ?target); + debug_assert!(self.table.shallow_resolve(source) == source); + debug_assert!(self.table.shallow_resolve(target) == target); + + // We don't apply any coercions incase either the source or target + // aren't sufficiently well known but tend to instead just equate + // them both. + if source.is_infer() { + debug!("coerce_unsized: source is a TyVar, bailing out"); + return Err(TypeError::Mismatch); + } + if target.is_infer() { + debug!("coerce_unsized: target is a TyVar, bailing out"); + return Err(TypeError::Mismatch); + } + + // This is an optimization because coercion is one of the most common + // operations that we do in typeck, since it happens at every assignment + // and call arg (among other positions). + // + // These targets are known to never be RHS in `LHS: CoerceUnsized`. + // That's because these are built-in types for which a core-provided impl + // doesn't exist, and for which a user-written impl is invalid. + // + // This is technically incomplete when users write impossible bounds like + // `where T: CoerceUnsized`, for example, but that trait is unstable + // and coercion is allowed to be incomplete. The only case where this matters + // is impossible bounds. + // + // Note that some of these types implement `LHS: Unsize`, but they + // do not implement *`CoerceUnsized`* which is the root obligation of the + // check below. + match target.kind() { + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Infer(rustc_type_ir::IntVar(_) | rustc_type_ir::FloatVar(_)) + | TyKind::Str + | TyKind::Array(_, _) + | TyKind::Slice(_) + | TyKind::FnDef(_, _) + | TyKind::FnPtr(_, _) + | TyKind::Dynamic(_, _, _) + | TyKind::Closure(_, _) + | TyKind::CoroutineClosure(_, _) + | TyKind::Coroutine(_, _) + | TyKind::CoroutineWitness(_, _) + | TyKind::Never + | TyKind::Tuple(_) => return Err(TypeError::Mismatch), + _ => {} + } + // Additionally, we ignore `&str -> &str` coercions, which happen very + // commonly since strings are one of the most used argument types in Rust, + // we do coercions when type checking call expressions. + if let TyKind::Ref(_, source_pointee, Mutability::Not) = source.kind() + && source_pointee.is_str() + && let TyKind::Ref(_, target_pointee, Mutability::Not) = target.kind() + && target_pointee.is_str() + { + return Err(TypeError::Mismatch); + } + + let traits = ( + LangItem::Unsize.resolve_trait(self.table.db, self.table.trait_env.krate), + LangItem::CoerceUnsized.resolve_trait(self.table.db, self.table.trait_env.krate), + ); + let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { + debug!("missing Unsize or CoerceUnsized traits"); + return Err(TypeError::Mismatch); + }; + + // Note, we want to avoid unnecessary unsizing. We don't want to coerce to + // a DST unless we have to. This currently comes out in the wash since + // we can't unify [T] with U. But to properly support DST, we need to allow + // that, at which point we will need extra checks on the target here. + + // Handle reborrows before selecting `Source: CoerceUnsized`. + let reborrow = match (source.kind(), target.kind()) { + (TyKind::Ref(_, ty_a, mutbl_a), TyKind::Ref(_, _, mutbl_b)) => { + coerce_mutbls(mutbl_a, mutbl_b)?; + + let r_borrow = self.table.next_region_var(); + + // We don't allow two-phase borrows here, at least for initial + // implementation. If it happens that this coercion is a function argument, + // the reborrow in coerce_borrowed_ptr will pick it up. + // let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No); + let mutbl = mutbl_b.to_chalk(self.interner()); + + Some(( + Adjustment { + kind: Adjust::Deref(None), + target: ty_a.to_chalk(self.interner()), + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref( + r_borrow.to_chalk(self.interner()), + mutbl, + )), + target: Ty::new_ref(self.interner(), r_borrow, ty_a, mutbl_b) + .to_chalk(self.interner()), }, - simple(Adjust::Pointer(PointerCast::ReifyFnPointer)), - )?; + )) + } + (TyKind::Ref(_, ty_a, mt_a), TyKind::RawPtr(_, mt_b)) => { + coerce_mutbls(mt_a, mt_b)?; - Ok(ok) + Some(( + Adjustment { + kind: Adjust::Deref(None), + target: ty_a.to_chalk(self.interner()), + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b.to_chalk(self.interner()))), + target: Ty::new_ptr(self.interner(), ty_a, mt_b).to_chalk(self.interner()), + }, + )) + } + _ => None, + }; + let coerce_source = + reborrow.as_ref().map_or(source, |(_, r)| r.target.to_nextsolver(self.interner())); + + // Setup either a subtyping or a LUB relationship between + // the `CoerceUnsized` target type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let coerce_target = self.table.next_ty_var(); + + let mut coercion = self.unify_and( + coerce_target, + target, + reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]), + Adjust::Pointer(PointerCast::Unsize), + )?; + + // Create an obligation for `Source: CoerceUnsized`. + let cause = self.cause.clone(); + + // Use a FIFO queue for this custom fulfillment procedure. + // + // A Vec (or SmallVec) is not a natural choice for a queue. However, + // this code path is hot, and this queue usually has a max length of 1 + // and almost never more than 3. By using a SmallVec we avoid an + // allocation, at the (very small) cost of (occasionally) having to + // shift subsequent elements down when removing the front element. + let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new( + self.interner(), + cause, + self.table.param_env, + TraitRef::new( + self.interner(), + coerce_unsized_did.into(), + [coerce_source, coerce_target] + ) + )]; + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid + // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where + // inference might unify those two inner type variables later. + let traits = [coerce_unsized_did, unsize_did]; + while !queue.is_empty() { + let obligation = queue.remove(0); + let trait_pred = match obligation.predicate.kind().no_bound_vars() { + Some(PredicateKind::Clause(ClauseKind::Trait(trait_pred))) + if traits.contains(&trait_pred.def_id().0) => + { + self.infer_ctxt().resolve_vars_if_possible(trait_pred) + } + // Eagerly process alias-relate obligations in new trait solver, + // since these can be emitted in the process of solving trait goals, + // but we need to constrain vars before processing goals mentioning + // them. + Some(PredicateKind::AliasRelate(..)) => { + let mut ocx = ObligationCtxt::new(self.infer_ctxt()); + ocx.register_obligation(obligation); + if !ocx.select_where_possible().is_empty() { + return Err(TypeError::Mismatch); + } + coercion.obligations.extend(ocx.into_pending_obligations()); + continue; + } + _ => { + coercion.obligations.push(obligation); + continue; + } + }; + debug!("coerce_unsized resolve step: {:?}", trait_pred); + match self.infer_ctxt().select(&obligation.with(self.interner(), trait_pred)) { + // Uncertain or unimplemented. + Ok(None) => { + if trait_pred.def_id().0 == unsize_did { + let self_ty = trait_pred.self_ty(); + let unsize_ty = trait_pred.trait_ref.args.inner()[1].expect_ty(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); + match (self_ty.kind(), unsize_ty.kind()) { + (TyKind::Infer(rustc_type_ir::TyVar(v)), TyKind::Dynamic(..)) + if self.table.type_var_is_sized(v) => + { + debug!("coerce_unsized: have sized infer {:?}", v); + coercion.obligations.push(obligation); + // `$0: Unsize` where we know that `$0: Sized`, try going + // for unsizing. + } + _ => { + // Some other case for `$0: Unsize`. Note that we + // hit this case even if `Something` is a sized type, so just + // don't do the coercion. + debug!("coerce_unsized: ambiguous unsize"); + return Err(TypeError::Mismatch); + } + } + } else { + debug!("coerce_unsized: early return - ambiguous"); + if !coerce_source.references_non_lt_error() + && !coerce_target.references_non_lt_error() + { + // rustc always early-returns here, even when the types contains errors. However not bailing + // improves error recovery, and while we don't implement generic consts properly, it also helps + // correct code. + return Err(TypeError::Mismatch); + } + } + } + Err(SelectionError::Unimplemented) => { + debug!("coerce_unsized: early return - can't prove obligation"); + return Err(TypeError::Mismatch); + } + + Err(SelectionError::TraitDynIncompatible(_)) => { + // Dyn compatibility errors in coercion will *always* be due to the + // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` + // written in source somewhere (otherwise we will never have lowered + // the dyn trait from HIR to middle). + // + // There's no reason to emit yet another dyn compatibility error, + // especially since the span will differ slightly and thus not be + // deduplicated at all! + self.set_tainted_by_errors(); + } + Err(_err) => { + // FIXME: Report an error: + // let guar = self.err_ctxt().report_selection_error( + // obligation.clone(), + // &obligation, + // &err, + // ); + self.set_tainted_by_errors(); + // Treat this like an obligation and follow through + // with the unsizing - the lack of a coercion should + // be silent, as it causes a type mismatch later. + } + + Ok(Some(ImplSource::UserDefined(impl_source))) => { + queue.extend(impl_source.nested); + } + Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } - _ => self.unify_and(&from_ty, to_ty, identity), } + + Ok(coercion) } - fn coerce_from_fn_pointer( + fn coerce_from_safe_fn( &mut self, - from_ty: Ty, - from_f: &FnPointer, - to_ty: &Ty, + fn_ty_a: PolyFnSig<'db>, + b: Ty<'db>, + adjustment: Option, ) -> CoerceResult<'db> { - self.coerce_from_safe_fn( - from_ty, - from_f, - to_ty, - simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), - identity, - ) + debug_assert!(self.table.shallow_resolve(b) == b); + + self.commit_if_ok(|this| { + if let TyKind::FnPtr(_, hdr_b) = b.kind() + && fn_ty_a.safety().is_safe() + && !hdr_b.safety.is_safe() + { + let unsafe_a = Ty::safe_to_unsafe_fn_ty(this.interner(), fn_ty_a); + this.unify_and( + unsafe_a, + b, + adjustment.map(|kind| Adjustment { + kind, + target: Ty::new_fn_ptr(this.interner(), fn_ty_a).to_chalk(this.interner()), + }), + Adjust::Pointer(PointerCast::UnsafeFnPointer), + ) + } else { + let a = Ty::new_fn_ptr(this.interner(), fn_ty_a); + match adjustment { + Some(adjust) => this.unify_and(a, b, [], adjust), + None => this.unify(a, b), + } + } + }) } - fn coerce_from_safe_fn( - &mut self, - from_ty: Ty, - from_fn_ptr: &FnPointer, - to_ty: &Ty, - to_unsafe: F, - normal: G, - ) -> CoerceResult<'db> - where - F: FnOnce(Ty) -> Vec, - G: FnOnce(Ty) -> Vec, - { - if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner) - && let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) = - (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety) - { - let from_unsafe = - TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner); - return self.unify_and(&from_unsafe, to_ty, to_unsafe); + fn coerce_from_fn_pointer(&mut self, fn_ty_a: PolyFnSig<'db>, b: Ty<'db>) -> CoerceResult<'db> { + debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); + debug_assert!(self.table.shallow_resolve(b) == b); + + self.coerce_from_safe_fn(fn_ty_a, b, None) + } + + fn coerce_from_fn_item(&mut self, a: Ty<'db>, b: Ty<'db>) -> CoerceResult<'db> { + debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); + debug_assert!(self.table.shallow_resolve(a) == a); + debug_assert!(self.table.shallow_resolve(b) == b); + + match b.kind() { + TyKind::FnPtr(_, b_hdr) => { + let a_sig = a.fn_sig(self.interner()); + if let TyKind::FnDef(def_id, _) = a.kind() { + // Intrinsics are not coercible to function pointers + if let CallableDefId::FunctionId(def_id) = def_id.0 { + if FunctionSignature::is_intrinsic(self.table.db, def_id) { + return Err(TypeError::IntrinsicCast); + } + + let attrs = self.table.db.attrs(def_id.into()); + if attrs.by_key(sym::rustc_force_inline).exists() { + return Err(TypeError::ForceInlineCast); + } + + if b_hdr.safety.is_safe() && attrs.by_key(sym::target_feature).exists() { + let fn_target_features = + TargetFeatures::from_attrs_no_implications(&attrs); + // Allow the coercion if the current function has all the features that would be + // needed to call the coercee safely. + let (target_features, target_feature_is_safe) = + (self.target_features)(); + if target_feature_is_safe == TargetFeatureIsSafeInTarget::No + && !target_features.enabled.is_superset(&fn_target_features.enabled) + { + return Err(TypeError::TargetFeatureCast( + CallableIdWrapper(def_id.into()).into(), + )); + } + } + } + } + + self.coerce_from_safe_fn( + a_sig, + b, + Some(Adjust::Pointer(PointerCast::ReifyFnPointer)), + ) + } + _ => self.unify(a, b), } - self.unify_and(&from_ty, to_ty, normal) } - /// Attempts to coerce from the type of a non-capturing closure into a - /// function pointer. + /// Attempts to coerce from the type of a non-capturing closure + /// into a function pointer. fn coerce_closure_to_fn( &mut self, - from_ty: Ty, - from_substs: &Substitution, - to_ty: &Ty, + a: Ty<'db>, + _closure_def_id_a: InternedClosureId, + args_a: GenericArgs<'db>, + b: Ty<'db>, ) -> CoerceResult<'db> { - match to_ty.kind(Interner) { - // if from_substs is non-capturing (FIXME) - TyKind::Function(fn_ty) => { + debug_assert!(self.table.shallow_resolve(a) == a); + debug_assert!(self.table.shallow_resolve(b) == b); + + match b.kind() { + // FIXME: We need to have an `upvars_mentioned()` query: + // At this point we haven't done capture analysis, which means + // that the ClosureArgs just contains an inference variable instead + // of tuple of captured types. + // + // All we care here is if any variable is being captured and not the exact paths, + // so we check `upvars_mentioned` for root variables being captured. + TyKind::FnPtr(_, hdr) => + // if self + // .db + // .upvars_mentioned(closure_def_id_a.expect_local()) + // .is_none_or(|u| u.is_empty()) => + { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to // `fn(arg0,arg1,...) -> _` // or // `unsafe fn(arg0,arg1,...) -> _` - let safety = fn_ty.sig.safety; - let pointer_ty = coerce_closure_fn_ty(from_substs, safety); + let safety = hdr.safety; + let closure_sig = args_a.closure_sig_untupled().map_bound(|mut sig| { + sig.safety = hdr.safety; + sig + }); + let pointer_ty = Ty::new_fn_ptr(self.interner(), closure_sig); + debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); self.unify_and( - &pointer_ty, - to_ty, - simple(Adjust::Pointer(PointerCast::ClosureFnPointer(safety))), + pointer_ty, + b, + [], + Adjust::Pointer(PointerCast::ClosureFnPointer( + safety.to_chalk(self.interner()), + )), ) } - _ => self.unify_and(&from_ty, to_ty, identity), + _ => self.unify(a, b), } } - /// Coerce a type using `from_ty: CoerceUnsized` - /// - /// See: - fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult<'db> { - // These 'if' statements require some explanation. - // The `CoerceUnsized` trait is special - it is only - // possible to write `impl CoerceUnsized for A` where - // A and B have 'matching' fields. This rules out the following - // two types of blanket impls: - // - // `impl CoerceUnsized for SomeType` - // `impl CoerceUnsized for T` - // - // Both of these trigger a special `CoerceUnsized`-related error (E0376) - // - // We can take advantage of this fact to avoid performing unnecessary work. - // If either `source` or `target` is a type variable, then any applicable impl - // would need to be generic over the self-type (`impl CoerceUnsized for T`) - // or generic over the `CoerceUnsized` type parameter (`impl CoerceUnsized for - // SomeType`). - // - // However, these are exactly the kinds of impls which are forbidden by - // the compiler! Therefore, we can be sure that coercion will always fail - // when either the source or target type is a type variable. This allows us - // to skip performing any trait selection, and immediately bail out. - if from_ty.is_ty_var() { - return Err(TypeError); + fn coerce_raw_ptr(&mut self, a: Ty<'db>, b: Ty<'db>, mutbl_b: Mutability) -> CoerceResult<'db> { + debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b); + debug_assert!(self.table.shallow_resolve(a) == a); + debug_assert!(self.table.shallow_resolve(b) == b); + + let (is_ref, mt_a) = match a.kind() { + TyKind::Ref(_, ty, mutbl) => (true, TypeAndMut::> { ty, mutbl }), + TyKind::RawPtr(ty, mutbl) => (false, TypeAndMut { ty, mutbl }), + _ => return self.unify(a, b), + }; + coerce_mutbls(mt_a.mutbl, mutbl_b)?; + + // Check that the types which they point at are compatible. + let a_raw = Ty::new_ptr(self.interner(), mt_a.ty, mutbl_b); + // Although references and raw ptrs have the same + // representation, we still register an Adjust::DerefRef so that + // regionck knows that the region for `a` must be valid here. + if is_ref { + self.unify_and( + a_raw, + b, + [Adjustment { + kind: Adjust::Deref(None), + target: mt_a.ty.to_chalk(self.interner()), + }], + Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b.to_chalk(self.interner()))), + ) + } else if mt_a.mutbl != mutbl_b { + self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCast::MutToConstPointer)) + } else { + self.unify(a_raw, b) } - if to_ty.is_ty_var() { - return Err(TypeError); + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum CoerceNever { + No, + Yes, +} + +impl<'db> InferenceContext<'db> { + /// Attempt to coerce an expression to a type, and return the + /// adjusted type of the expression, if successful. + /// Adjustments are only recorded if the coercion succeeded. + /// The expressions *must not* have any preexisting adjustments. + pub(crate) fn coerce( + &mut self, + expr: ExprOrPatId, + expr_ty: Ty<'db>, + mut target: Ty<'db>, + allow_two_phase: AllowTwoPhase, + coerce_never: CoerceNever, + ) -> RelateResult<'db, Ty<'db>> { + let source = self.table.try_structurally_resolve_type(expr_ty); + target = self.table.try_structurally_resolve_type(target); + debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + + let cause = ObligationCause::new(); + let krate = self.krate(); + let mut coerce = Coerce { + table: &mut self.table, + has_errors: &mut self.result.has_errors, + cause, + allow_two_phase, + coerce_never: matches!(coerce_never, CoerceNever::Yes), + use_lub: false, + target_features: &mut || { + Self::target_features(self.db, &self.target_features, self.owner, krate) + }, + }; + let ok = coerce.commit_if_ok(|coerce| coerce.coerce(source, target))?; + + let (adjustments, _) = self.table.register_infer_ok(ok); + match expr { + ExprOrPatId::ExprId(expr) => self.write_expr_adj(expr, adjustments.into_boxed_slice()), + ExprOrPatId::PatId(pat) => self + .write_pat_adj(pat, adjustments.into_iter().map(|adjust| adjust.target).collect()), } + Ok(target) + } - // Handle reborrows before trying to solve `Source: CoerceUnsized`. - let reborrow = match (from_ty.kind(Interner), to_ty.kind(Interner)) { - (TyKind::Ref(from_mt, _, from_inner), &TyKind::Ref(to_mt, _, _)) => { - coerce_mutabilities(*from_mt, to_mt)?; + /// Given some expressions, their known unified type and another expression, + /// tries to unify the types, potentially inserting coercions on any of the + /// provided expressions and returns their LUB (aka "common supertype"). + /// + /// This is really an internal helper. From outside the coercion + /// module, you should instantiate a `CoerceMany` instance. + fn try_find_coercion_lub( + &mut self, + exprs: &[ExprId], + prev_ty: Ty<'db>, + new: ExprId, + new_ty: Ty<'db>, + ) -> RelateResult<'db, Ty<'db>> { + let prev_ty = self.table.try_structurally_resolve_type(prev_ty); + let new_ty = self.table.try_structurally_resolve_type(new_ty); + debug!( + "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", + prev_ty, + new_ty, + exprs.len() + ); + + // The following check fixes #88097, where the compiler erroneously + // attempted to coerce a closure type to itself via a function pointer. + if prev_ty == new_ty { + return Ok(prev_ty); + } - let lt = self.new_lifetime_var(); - Some(( - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), to_mt)), - target: TyKind::Ref(to_mt, lt, from_inner.clone()).intern(Interner), - }, - )) + let is_force_inline = |ty: Ty<'db>| { + if let TyKind::FnDef(CallableIdWrapper(CallableDefId::FunctionId(did)), _) = ty.kind() { + self.db.attrs(did.into()).by_key(sym::rustc_force_inline).exists() + } else { + false } - (TyKind::Ref(from_mt, _, from_inner), &TyKind::Raw(to_mt, _)) => { - coerce_mutabilities(*from_mt, to_mt)?; + }; + if is_force_inline(prev_ty) || is_force_inline(new_ty) { + return Err(TypeError::ForceInlineCast); + } - Some(( - Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() }, - Adjustment { - kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)), - target: TyKind::Raw(to_mt, from_inner.clone()).intern(Interner), - }, - )) + // Special-case that coercion alone cannot handle: + // Function items or non-capturing closures of differing IDs or GenericArgs. + let (a_sig, b_sig) = { + let is_capturing_closure = |_ty: Ty<'db>| { + // FIXME: + // if let TyKind::Closure(closure_def_id, _args) = ty.kind() { + // self.db.upvars_mentioned(closure_def_id.expect_local()).is_some() + // } else { + // false + // } + false + }; + if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) { + (None, None) + } else { + match (prev_ty.kind(), new_ty.kind()) { + (TyKind::FnDef(..), TyKind::FnDef(..)) => { + // Don't reify if the function types have a LUB, i.e., they + // are the same function and their parameters have a LUB. + match self.table.commit_if_ok(|table| { + // We need to eagerly handle nested obligations due to lazy norm. + let mut ocx = ObligationCtxt::new(&table.infer_ctxt); + let value = + ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?; + if ocx.select_where_possible().is_empty() { + Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) + } else { + Err(TypeError::Mismatch) + } + }) { + // We have a LUB of prev_ty and new_ty, just return it. + Ok(ok) => return Ok(self.table.register_infer_ok(ok)), + Err(_) => ( + Some(prev_ty.fn_sig(self.table.interner)), + Some(new_ty.fn_sig(self.table.interner)), + ), + } + } + (TyKind::Closure(_, args), TyKind::FnDef(..)) => { + let b_sig = new_ty.fn_sig(self.table.interner); + let a_sig = args.closure_sig_untupled().map_bound(|mut sig| { + sig.safety = b_sig.safety(); + sig + }); + (Some(a_sig), Some(b_sig)) + } + (TyKind::FnDef(..), TyKind::Closure(_, args)) => { + let a_sig = prev_ty.fn_sig(self.table.interner); + let b_sig = args.closure_sig_untupled().map_bound(|mut sig| { + sig.safety = a_sig.safety(); + sig + }); + (Some(a_sig), Some(b_sig)) + } + (TyKind::Closure(_, args_a), TyKind::Closure(_, args_b)) => { + (Some(args_a.closure_sig_untupled()), Some(args_b.closure_sig_untupled())) + } + _ => (None, None), + } } - _ => None, }; - let coerce_from = - reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone()); + if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { + // The signature must match. + let sig = self + .table + .infer_ctxt + .at(&ObligationCause::new(), self.table.param_env) + .lub(a_sig, b_sig) + .map(|ok| self.table.register_infer_ok(ok))?; + + // Reify both sides and return the reified fn pointer type. + let fn_ptr = Ty::new_fn_ptr(self.table.interner, sig); + let prev_adjustment = match prev_ty.kind() { + TyKind::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer( + a_sig.safety().to_chalk(self.table.interner), + )), + TyKind::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + _ => panic!("should not try to coerce a {prev_ty:?} to a fn pointer"), + }; + let next_adjustment = match new_ty.kind() { + TyKind::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer( + b_sig.safety().to_chalk(self.table.interner), + )), + TyKind::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + _ => panic!("should not try to coerce a {new_ty:?} to a fn pointer"), + }; + for &expr in exprs { + self.write_expr_adj( + expr, + Box::new([Adjustment { + kind: prev_adjustment.clone(), + target: fn_ptr.to_chalk(self.table.interner), + }]), + ); + } + self.write_expr_adj( + new, + Box::new([Adjustment { + kind: next_adjustment, + target: fn_ptr.to_chalk(self.table.interner), + }]), + ); + return Ok(fn_ptr); + } - let krate = self.trait_env.krate; - let coerce_unsized_trait = match LangItem::CoerceUnsized.resolve_trait(self.db, krate) { - Some(trait_) => trait_, - _ => return Err(TypeError), + // Configure a Coerce instance to compute the LUB. + // We don't allow two-phase borrows on any autorefs this creates since we + // probably aren't processing function arguments here and even if we were, + // they're going to get autorefed again anyway and we can apply 2-phase borrows + // at that time. + // + // NOTE: we set `coerce_never` to `true` here because coercion LUBs only + // operate on values and not places, so a never coercion is valid. + let krate = self.krate(); + let mut coerce = Coerce { + table: &mut self.table, + has_errors: &mut self.result.has_errors, + cause: ObligationCause::new(), + allow_two_phase: AllowTwoPhase::No, + coerce_never: true, + use_lub: true, + target_features: &mut || { + Self::target_features(self.db, &self.target_features, self.owner, krate) + }, }; - let coerce_unsized_tref = { - let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait); - if b.remaining() != 2 { - // The CoerceUnsized trait should have two generic params: Self and T. - return Err(TypeError); + // First try to coerce the new expression to the type of the previous ones, + // but only if the new expression has no coercion already applied to it. + let mut first_error = None; + if !self.result.expr_adjustments.contains_key(&new) { + let result = coerce.commit_if_ok(|coerce| coerce.coerce(new_ty, prev_ty)); + match result { + Ok(ok) => { + let (adjustments, target) = self.table.register_infer_ok(ok); + self.write_expr_adj(new, adjustments.into_boxed_slice()); + debug!( + "coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})", + new_ty, prev_ty, target + ); + return Ok(target); + } + Err(e) => first_error = Some(e), } - b.push(coerce_from).push(to_ty.clone()).build() - }; + } + + match coerce.commit_if_ok(|coerce| coerce.coerce(prev_ty, new_ty)) { + Err(_) => { + // Avoid giving strange errors on failed attempts. + if let Some(e) = first_error { + Err(e) + } else { + Err(self + .table + .commit_if_ok(|table| { + table + .infer_ctxt + .at(&ObligationCause::new(), table.param_env) + .lub(prev_ty, new_ty) + }) + .unwrap_err()) + } + } + Ok(ok) => { + let (adjustments, target) = self.table.register_infer_ok(ok); + for &expr in exprs { + self.write_expr_adj(expr, adjustments.as_slice().into()); + } + debug!( + "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})", + prev_ty, new_ty, target + ); + Ok(target) + } + } + } +} - let goal: Goal = coerce_unsized_tref.cast(Interner); +/// CoerceMany encapsulates the pattern you should use when you have +/// many expressions that are all getting coerced to a common +/// type. This arises, for example, when you have a match (the result +/// of each arm is coerced to a common type). It also arises in less +/// obvious places, such as when you have many `break foo` expressions +/// that target the same loop, or the various `return` expressions in +/// a function. +/// +/// The basic protocol is as follows: +/// +/// - Instantiate the `CoerceMany` with an initial `expected_ty`. +/// This will also serve as the "starting LUB". The expectation is +/// that this type is something which all of the expressions *must* +/// be coercible to. Use a fresh type variable if needed. +/// - For each expression whose result is to be coerced, invoke `coerce()` with. +/// - In some cases we wish to coerce "non-expressions" whose types are implicitly +/// unit. This happens for example if you have a `break` with no expression, +/// or an `if` with no `else`. In that case, invoke `coerce_forced_unit()`. +/// - `coerce()` and `coerce_forced_unit()` may report errors. They hide this +/// from you so that you don't have to worry your pretty head about it. +/// But if an error is reported, the final type will be `err`. +/// - Invoking `coerce()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// - When all done, invoke `complete()`. This will return the LUB of +/// all your expressions. +/// - WARNING: I don't believe this final type is guaranteed to be +/// related to your initial `expected_ty` in any particular way, +/// although it will typically be a subtype, so you should check it. +/// - Invoking `complete()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// +/// Example: +/// +/// ```ignore (illustrative) +/// let mut coerce = CoerceMany::new(expected_ty); +/// for expr in exprs { +/// let expr_ty = fcx.check_expr_with_expectation(expr, expected); +/// coerce.coerce(fcx, &cause, expr, expr_ty); +/// } +/// let final_ty = coerce.complete(fcx); +/// ``` +#[derive(Debug, Clone)] +pub(crate) struct CoerceMany<'db, 'exprs> { + expected_ty: Ty<'db>, + final_ty: Option>, + expressions: Expressions<'exprs>, + pushed: usize, +} - self.commit_if_ok(|table| match table.solve_obligation(goal) { - Ok(Certainty::Yes) => Ok(()), - _ => Err(TypeError), - })?; +/// The type of a `CoerceMany` that is storing up the expressions into +/// a buffer. We use this for things like `break`. +pub(crate) type DynamicCoerceMany<'db> = CoerceMany<'db, 'db>; - let unsize = - Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() }; - let adjustments = match reborrow { - None => vec![unsize], - Some((deref, autoref)) => vec![deref, autoref, unsize], - }; - success(adjustments, to_ty.clone(), vec![]) - } +#[derive(Debug, Clone)] +enum Expressions<'exprs> { + Dynamic(SmallVec<[ExprId; 4]>), + UpFront(&'exprs [ExprId]), } -fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty { - let closure_sig = ClosureSubst(closure_substs).sig_ty().clone(); - match closure_sig.kind(Interner) { - TyKind::Function(fn_ty) => TyKind::Function(FnPointer { - num_binders: fn_ty.num_binders, - sig: FnSig { safety, abi: FnAbi::Rust, variadic: fn_ty.sig.variadic }, - substitution: fn_ty.substitution.clone(), - }) - .intern(Interner), - _ => TyKind::Error.intern(Interner), +impl<'db, 'exprs> CoerceMany<'db, 'exprs> { + /// The usual case; collect the set of expressions dynamically. + /// If the full set of coercion sites is known before hand, + /// consider `with_coercion_sites()` instead to avoid allocation. + pub(crate) fn new(expected_ty: Ty<'db>) -> Self { + Self::make(expected_ty, Expressions::Dynamic(SmallVec::new())) } -} -fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer { - FnPointer { - num_binders: fn_ty.num_binders, - sig: FnSig { safety: chalk_ir::Safety::Unsafe, ..fn_ty.sig }, - substitution: fn_ty.substitution, + /// As an optimization, you can create a `CoerceMany` with a + /// preexisting slice of expressions. In this case, you are + /// expected to pass each element in the slice to `coerce(...)` in + /// order. This is used with arrays in particular to avoid + /// needlessly cloning the slice. + pub(crate) fn with_coercion_sites( + expected_ty: Ty<'db>, + coercion_sites: &'exprs [ExprId], + ) -> Self { + Self::make(expected_ty, Expressions::UpFront(coercion_sites)) + } + + fn make(expected_ty: Ty<'db>, expressions: Expressions<'exprs>) -> Self { + CoerceMany { expected_ty, final_ty: None, expressions, pushed: 0 } + } + + /// Returns the "expected type" with which this coercion was + /// constructed. This represents the "downward propagated" type + /// that was given to us at the start of typing whatever construct + /// we are typing (e.g., the match expression). + /// + /// Typically, this is used as the expected type when + /// type-checking each of the alternative expressions whose types + /// we are trying to merge. + pub(crate) fn expected_ty(&self) -> Ty<'db> { + self.expected_ty + } + + /// Returns the current "merged type", representing our best-guess + /// at the LUB of the expressions we've seen so far (if any). This + /// isn't *final* until you call `self.complete()`, which will return + /// the merged type. + pub(crate) fn merged_ty(&self) -> Ty<'db> { + self.final_ty.unwrap_or(self.expected_ty) } -} -fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { - match (from, to) { - (Mutability::Mut, Mutability::Mut | Mutability::Not) - | (Mutability::Not, Mutability::Not) => Ok(()), - (Mutability::Not, Mutability::Mut) => Err(TypeError), + /// Indicates that the value generated by `expression`, which is + /// of type `expression_ty`, is one of the possibilities that we + /// could coerce from. This will record `expression`, and later + /// calls to `coerce` may come back and add adjustments and things + /// if necessary. + pub(crate) fn coerce( + &mut self, + icx: &mut InferenceContext<'db>, + cause: &ObligationCause, + expression: ExprId, + expression_ty: Ty<'db>, + ) { + self.coerce_inner(icx, cause, expression, expression_ty, false, false) + } + + /// Indicates that one of the inputs is a "forced unit". This + /// occurs in a case like `if foo { ... };`, where the missing else + /// generates a "forced unit". Another example is a `loop { break; + /// }`, where the `break` has no argument expression. We treat + /// these cases slightly differently for error-reporting + /// purposes. Note that these tend to correspond to cases where + /// the `()` expression is implicit in the source, and hence we do + /// not take an expression argument. + /// + /// The `augment_error` gives you a chance to extend the error + /// message, in case any results (e.g., we use this to suggest + /// removing a `;`). + pub(crate) fn coerce_forced_unit( + &mut self, + icx: &mut InferenceContext<'db>, + expr: ExprId, + cause: &ObligationCause, + label_unit_as_expected: bool, + ) { + self.coerce_inner( + icx, + cause, + expr, + icx.result.standard_types.unit.to_nextsolver(icx.table.interner), + true, + label_unit_as_expected, + ) + } + + /// The inner coercion "engine". If `expression` is `None`, this + /// is a forced-unit case, and hence `expression_ty` must be + /// `Nil`. + pub(crate) fn coerce_inner( + &mut self, + icx: &mut InferenceContext<'db>, + cause: &ObligationCause, + expression: ExprId, + mut expression_ty: Ty<'db>, + force_unit: bool, + label_expression_as_expected: bool, + ) { + // Incorporate whatever type inference information we have + // until now; in principle we might also want to process + // pending obligations, but doing so should only improve + // compatibility (hopefully that is true) by helping us + // uncover never types better. + if expression_ty.is_ty_var() { + expression_ty = icx.shallow_resolve(expression_ty); + } + + let (expected, found) = if label_expression_as_expected { + // In the case where this is a "forced unit", like + // `break`, we want to call the `()` "expected" + // since it is implied by the syntax. + // (Note: not all force-units work this way.)" + (expression_ty, self.merged_ty()) + } else { + // Otherwise, the "expected" type for error + // reporting is the current unification type, + // which is basically the LUB of the expressions + // we've seen so far (combined with the expected + // type) + (self.merged_ty(), expression_ty) + }; + + // Handle the actual type unification etc. + let result = if !force_unit { + if self.pushed == 0 { + // Special-case the first expression we are coercing. + // To be honest, I'm not entirely sure why we do this. + // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why + icx.coerce( + expression.into(), + expression_ty, + self.expected_ty, + AllowTwoPhase::No, + CoerceNever::Yes, + ) + } else { + match self.expressions { + Expressions::Dynamic(ref exprs) => icx.try_find_coercion_lub( + exprs, + self.merged_ty(), + expression, + expression_ty, + ), + Expressions::UpFront(coercion_sites) => icx.try_find_coercion_lub( + &coercion_sites[0..self.pushed], + self.merged_ty(), + expression, + expression_ty, + ), + } + } + } else { + // this is a hack for cases where we default to `()` because + // the expression etc has been omitted from the source. An + // example is an `if let` without an else: + // + // if let Some(x) = ... { } + // + // we wind up with a second match arm that is like `_ => + // ()`. That is the case we are considering here. We take + // a different path to get the right "expected, found" + // message and so forth (and because we know that + // `expression_ty` will be unit). + // + // Another example is `break` with no argument expression. + assert!(expression_ty.is_unit(), "if let hack without unit type"); + icx.table + .infer_ctxt + .at(cause, icx.table.param_env) + .eq( + // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs + DefineOpaqueTypes::Yes, + expected, + found, + ) + .map(|infer_ok| { + icx.table.register_infer_ok(infer_ok); + expression_ty + }) + }; + + debug!(?result); + match result { + Ok(v) => { + self.final_ty = Some(v); + match self.expressions { + Expressions::Dynamic(ref mut buffer) => buffer.push(expression), + Expressions::UpFront(coercion_sites) => { + // if the user gave us an array to validate, check that we got + // the next expression in the list, as expected + assert_eq!(coercion_sites[self.pushed], expression); + } + } + } + Err(_coercion_error) => { + // Mark that we've failed to coerce the types here to suppress + // any superfluous errors we might encounter while trying to + // emit or provide suggestions on how to fix the initial error. + icx.set_tainted_by_errors(); + + self.final_ty = Some(Ty::new_error(icx.table.interner, ErrorGuaranteed)); + + icx.result.type_mismatches.insert( + expression.into(), + if label_expression_as_expected { + TypeMismatch { + expected: found.to_chalk(icx.table.interner), + actual: expected.to_chalk(icx.table.interner), + } + } else { + TypeMismatch { + expected: expected.to_chalk(icx.table.interner), + actual: found.to_chalk(icx.table.interner), + } + }, + ); + } + } + + self.pushed += 1; + } + + pub(crate) fn complete(self, icx: &mut InferenceContext<'db>) -> Ty<'db> { + if let Some(final_ty) = self.final_ty { + final_ty + } else { + // If we only had inputs that were of type `!` (or no + // inputs at all), then the final type is `!`. + assert_eq!(self.pushed, 0); + icx.result.standard_types.never.to_nextsolver(icx.table.interner) + } } } -pub(super) fn auto_deref_adjust_steps(autoderef: &Autoderef<'_, '_>) -> Vec { - let steps = autoderef.steps(); - let targets = - steps.iter().skip(1).map(|(_, ty)| ty.clone()).chain(iter::once(autoderef.final_ty())); - steps - .iter() - .map(|(kind, _source)| match kind { - // We do not know what kind of deref we require at this point yet - AutoderefKind::Overloaded => Some(OverloadedDeref(None)), - AutoderefKind::Builtin => None, - }) - .zip(targets) - .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target }) - .collect() +pub fn could_coerce( + db: &dyn HirDatabase, + env: Arc, + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, +) -> bool { + coerce(db, env, tys).is_ok() +} + +fn coerce<'db>( + db: &'db dyn HirDatabase, + env: Arc, + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, +) -> Result<(Vec, crate::Ty), TypeError>> { + let mut table = InferenceTable::new(db, env); + let vars = table.fresh_subst(tys.binders.as_slice(Interner)); + let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); + let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); + + let cause = ObligationCause::new(); + // FIXME: Target features. + let target_features = TargetFeatures::default(); + let mut coerce = Coerce { + table: &mut table, + has_errors: &mut false, + cause, + allow_two_phase: AllowTwoPhase::No, + coerce_never: true, + use_lub: false, + target_features: &mut || (&target_features, TargetFeatureIsSafeInTarget::No), + }; + let InferOk { value: (adjustments, ty), obligations } = coerce.coerce( + ty1_with_vars.to_nextsolver(coerce.table.interner), + ty2_with_vars.to_nextsolver(coerce.table.interner), + )?; + table.register_predicates(obligations); + + // default any type vars that weren't unified back to their original bound vars + // (kind of hacky) + let find_var = |iv| { + vars.iter(Interner).position(|v| match v.interned() { + chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner), + chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner), + chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), + } == Some(iv)) + }; + let fallback = |iv, kind, default, binder| match kind { + chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) + .map_or(default, |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), + chalk_ir::VariableKind::Lifetime => find_var(iv).map_or(default, |i| { + crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner) + }), + chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or(default, |i| { + crate::BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner) + }), + }; + // FIXME also map the types in the adjustments + Ok((adjustments, table.resolve_with_fallback(ty.to_chalk(table.interner), &fallback))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 0a58ea11bb871..c5a51dfc4cf92 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1,12 +1,10 @@ //! Type inference for expressions. -use std::{ - iter::{repeat, repeat_with}, - mem, -}; +use std::{iter::repeat_with, mem}; use chalk_ir::{DebruijnIndex, Mutability, TyVariableKind, cast::Cast}; use either::Either; +use hir_def::hir::ClosureKind; use hir_def::{ BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, expr_store::path::{GenericArg, GenericArgs, Path}, @@ -19,19 +17,23 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::sym; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; use stdx::always; use syntax::ast::RangeOp; +use tracing::debug; +use crate::autoderef::overloaded_deref_ty; +use crate::next_solver::ErrorGuaranteed; +use crate::next_solver::infer::DefineOpaqueTypes; +use crate::next_solver::obligation_ctxt::ObligationCtxt; use crate::{ Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, - Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, - autoderef::{Autoderef, builtin_deref, deref_by_trait}, - consteval, + Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval, generics::generics, infer::{ - BreakableKind, - coerce::{CoerceMany, CoerceNever, CoercionCause}, + AllowTwoPhase, BreakableKind, + coerce::{CoerceMany, CoerceNever}, find_continuable, pat::contains_explicit_ref_binding, }, @@ -42,7 +44,10 @@ use crate::{ }, mapping::{ToChalk, from_chalk}, method_resolution::{self, VisibleFromModule}, - next_solver::mapping::ChalkToNextSolver, + next_solver::{ + infer::traits::ObligationCause, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, @@ -50,7 +55,7 @@ use crate::{ use super::{ BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, - cast::CastCheck, coerce::auto_deref_adjust_steps, find_breakable, + cast::CastCheck, find_breakable, }; #[derive(Clone, Copy, PartialEq, Eq)] @@ -59,7 +64,7 @@ pub(crate) enum ExprIsRead { No, } -impl InferenceContext<'_> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_expr( &mut self, tgt_expr: ExprId, @@ -98,8 +103,14 @@ impl InferenceContext<'_> { } else { CoerceNever::No }; - match self.coerce(Some(expr), &ty, &target, coerce_never) { - Ok(res) => res, + match self.coerce( + expr.into(), + ty.to_nextsolver(self.table.interner), + target.to_nextsolver(self.table.interner), + AllowTwoPhase::No, + coerce_never, + ) { + Ok(res) => res.to_chalk(self.table.interner), Err(_) => { self.result.type_mismatches.insert( expr.into(), @@ -260,8 +271,15 @@ impl InferenceContext<'_> { } if let Some(target) = expected.only_has_type(&mut self.table) { - self.coerce(Some(expr), &ty, &target, CoerceNever::Yes) - .expect("never-to-any coercion should always succeed") + self.coerce( + expr.into(), + ty.to_nextsolver(self.table.interner), + target.to_nextsolver(self.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .expect("never-to-any coercion should always succeed") + .to_chalk(self.table.interner) } else { ty } @@ -304,27 +322,41 @@ impl InferenceContext<'_> { let then_ty = self.infer_expr_inner(then_branch, expected, ExprIsRead::Yes); let then_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); - let mut coerce = CoerceMany::new(expected.coercion_target_type(&mut self.table)); - coerce.coerce(self, Some(then_branch), &then_ty, CoercionCause::Expr(then_branch)); + let mut coercion_sites = [then_branch, tgt_expr]; + if let Some(else_branch) = else_branch { + coercion_sites[1] = else_branch; + } + let mut coerce = CoerceMany::with_coercion_sites( + expected + .coercion_target_type(&mut self.table) + .to_nextsolver(self.table.interner), + &coercion_sites, + ); + coerce.coerce( + self, + &ObligationCause::new(), + then_branch, + then_ty.to_nextsolver(self.table.interner), + ); match else_branch { Some(else_branch) => { let else_ty = self.infer_expr_inner(else_branch, expected, ExprIsRead::Yes); let else_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); coerce.coerce( self, - Some(else_branch), - &else_ty, - CoercionCause::Expr(else_branch), + &ObligationCause::new(), + else_branch, + else_ty.to_nextsolver(self.table.interner), ); self.diverges = condition_diverges | then_diverges & else_diverges; } None => { - coerce.coerce_forced_unit(self, CoercionCause::Expr(tgt_expr)); + coerce.coerce_forced_unit(self, tgt_expr, &ObligationCause::new(), true); self.diverges = condition_diverges; } } - coerce.complete(self) + coerce.complete(self).to_chalk(self.table.interner) } &Expr::Let { pat, expr } => { let child_is_read = if self.pat_guaranteed_to_constitute_read_for_never(pat) { @@ -377,7 +409,15 @@ impl InferenceContext<'_> { } } Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => self - .infer_closure(body, args, ret_type, arg_types, *closure_kind, tgt_expr, expected), + .infer_closure( + *body, + args, + *ret_type, + arg_types, + *closure_kind, + tgt_expr, + expected, + ), Expr::Call { callee, args, .. } => self.infer_call(tgt_expr, *callee, args, expected), Expr::MethodCall { receiver, args, method_name, generic_args } => self .infer_method_call( @@ -416,7 +456,7 @@ impl InferenceContext<'_> { } _ => self.table.new_type_var(), }; - let mut coerce = CoerceMany::new(result_ty); + let mut coerce = CoerceMany::new(result_ty.to_nextsolver(self.table.interner)); for arm in arms.iter() { if let Some(guard_expr) = arm.guard { @@ -431,12 +471,17 @@ impl InferenceContext<'_> { let arm_ty = self.infer_expr_inner(arm.expr, &expected, ExprIsRead::Yes); all_arms_diverge &= self.diverges; - coerce.coerce(self, Some(arm.expr), &arm_ty, CoercionCause::Expr(arm.expr)); + coerce.coerce( + self, + &ObligationCause::new(), + arm.expr, + arm_ty.to_nextsolver(self.table.interner), + ); } self.diverges = matchee_diverges | all_arms_diverge; - coerce.complete(self) + coerce.complete(self).to_chalk(self.table.interner) } } Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr), @@ -454,7 +499,7 @@ impl InferenceContext<'_> { let val_ty = if let Some(expr) = expr { let opt_coerce_to = match find_breakable(&mut self.breakables, label) { Some(ctxt) => match &ctxt.coerce { - Some(coerce) => coerce.expected_ty(), + Some(coerce) => coerce.expected_ty().to_chalk(self.table.interner), None => { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { expr: tgt_expr, @@ -478,11 +523,12 @@ impl InferenceContext<'_> { match find_breakable(&mut self.breakables, label) { Some(ctxt) => match ctxt.coerce.take() { Some(mut coerce) => { - let cause = match expr { - Some(expr) => CoercionCause::Expr(expr), - None => CoercionCause::Expr(tgt_expr), - }; - coerce.coerce(self, expr, &val_ty, cause); + coerce.coerce( + self, + &ObligationCause::new(), + expr.unwrap_or(tgt_expr), + val_ty.to_nextsolver(self.table.interner), + ); // Avoiding borrowck let ctxt = find_breakable(&mut self.breakables, label) @@ -514,7 +560,13 @@ impl InferenceContext<'_> { ); } else { let unit = self.result.standard_types.unit.clone(); - let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty, CoerceNever::Yes); + let _ = self.coerce( + tgt_expr.into(), + unit.to_nextsolver(self.table.interner), + yield_ty.to_nextsolver(self.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ); } resume_ty } else { @@ -670,11 +722,23 @@ impl InferenceContext<'_> { Substitution::empty(Interner), ); } - if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) { - self.table.structurally_resolve_type(derefed) + if let Some(derefed) = + inner_ty.to_nextsolver(self.table.interner).builtin_deref(self.db, true) + { + self.table + .structurally_resolve_type(&derefed.to_chalk(self.table.interner)) } else { - deref_by_trait(&mut self.table, inner_ty, false) - .unwrap_or_else(|| self.err_ty()) + let infer_ok = overloaded_deref_ty( + &self.table, + inner_ty.to_nextsolver(self.table.interner), + ); + match infer_ok { + Some(infer_ok) => self + .table + .register_infer_ok(infer_ok) + .to_chalk(self.table.interner), + None => self.err_ty(), + } } } UnaryOp::Neg => { @@ -1010,11 +1074,23 @@ impl InferenceContext<'_> { CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(), ) .intern(Interner); - _ = this.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes); + _ = this.coerce( + expr.into(), + ty.to_nextsolver(this.table.interner), + fnptr_ty.to_nextsolver(this.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ); } TyKind::Ref(mutbl, _, base_ty) => { let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner); - _ = this.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes); + _ = this.coerce( + expr.into(), + ty.to_nextsolver(this.table.interner), + ptr_ty.to_nextsolver(this.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ); } _ => {} } @@ -1092,15 +1168,23 @@ impl InferenceContext<'_> { let ret_ty = self.table.new_type_var(); let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(ret_ty.clone())); + let prev_ret_coercion = self + .return_coercion + .replace(CoerceMany::new(ret_ty.to_nextsolver(self.table.interner))); // FIXME: We should handle async blocks like we handle closures let expected = &Expectation::has_type(ret_ty); let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { let ty = this.infer_block(tgt_expr, *id, statements, *tail, None, expected); if let Some(target) = expected.only_has_type(&mut this.table) { - match this.coerce(Some(tgt_expr), &ty, &target, CoerceNever::Yes) { - Ok(res) => res, + match this.coerce( + tgt_expr.into(), + ty.to_nextsolver(this.table.interner), + target.to_nextsolver(this.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) { + Ok(res) => res.to_chalk(this.table.interner), Err(_) => { this.result.type_mismatches.insert( tgt_expr.into(), @@ -1209,13 +1293,21 @@ impl InferenceContext<'_> { (elem_ty, consteval::usize_const(self.db, Some(0), krate)) } Array::ElementList { elements, .. } => { - let mut coerce = CoerceMany::new(elem_ty); + let mut coerce = CoerceMany::with_coercion_sites( + elem_ty.to_nextsolver(self.table.interner), + elements, + ); for &expr in elements.iter() { let cur_elem_ty = self.infer_expr_inner(expr, &expected, ExprIsRead::Yes); - coerce.coerce(self, Some(expr), &cur_elem_ty, CoercionCause::Expr(expr)); + coerce.coerce( + self, + &ObligationCause::new(), + expr, + cur_elem_ty.to_nextsolver(self.table.interner), + ); } ( - coerce.complete(self), + coerce.complete(self).to_chalk(self.table.interner), consteval::usize_const(self.db, Some(elements.len() as u128), krate), ) } @@ -1254,11 +1346,17 @@ impl InferenceContext<'_> { .return_coercion .as_mut() .expect("infer_return called outside function body") - .expected_ty(); + .expected_ty() + .to_chalk(self.table.interner); let return_expr_ty = self.infer_expr_inner(expr, &Expectation::HasType(ret_ty), ExprIsRead::Yes); let mut coerce_many = self.return_coercion.take().unwrap(); - coerce_many.coerce(self, Some(expr), &return_expr_ty, CoercionCause::Expr(expr)); + coerce_many.coerce( + self, + &ObligationCause::new(), + expr, + return_expr_ty.to_nextsolver(self.table.interner), + ); self.return_coercion = Some(coerce_many); } @@ -1269,7 +1367,7 @@ impl InferenceContext<'_> { self.infer_return(expr); } else { let mut coerce = self.return_coercion.take().unwrap(); - coerce.coerce_forced_unit(self, CoercionCause::Expr(ret)); + coerce.coerce_forced_unit(self, ret, &ObligationCause::new(), true); self.return_coercion = Some(coerce); } } @@ -1286,7 +1384,7 @@ impl InferenceContext<'_> { fn infer_expr_become(&mut self, expr: ExprId) -> Ty { match &self.return_coercion { Some(return_coercion) => { - let ret_ty = return_coercion.expected_ty(); + let ret_ty = return_coercion.expected_ty().to_chalk(self.table.interner); let call_expr_ty = self.infer_expr_inner( expr, @@ -1540,9 +1638,10 @@ impl InferenceContext<'_> { }; if this .coerce( - Some(expr), - &this.result.standard_types.unit.clone(), - &t, + expr.into(), + this.result.standard_types.unit.to_nextsolver(this.table.interner), + t.to_nextsolver(this.table.interner), + AllowTwoPhase::No, coerce_never, ) .is_err() @@ -1563,6 +1662,7 @@ impl InferenceContext<'_> { }); self.resolver.reset_to_guard(g); if let Some(prev_env) = prev_env { + self.table.param_env = prev_env.env.to_nextsolver(self.table.interner); self.table.trait_env = prev_env; } @@ -1574,50 +1674,49 @@ impl InferenceContext<'_> { receiver_ty: &Ty, name: &Name, ) -> Option<(Ty, Either, Vec, bool)> { - let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false, false); + let interner = self.table.interner; + let mut autoderef = self.table.autoderef(receiver_ty.to_nextsolver(self.table.interner)); let mut private_field = None; let res = autoderef.by_ref().find_map(|(derefed_ty, _)| { - let (field_id, parameters) = match derefed_ty.kind(Interner) { - TyKind::Tuple(_, substs) => { + let (field_id, parameters) = match derefed_ty.kind() { + crate::next_solver::TyKind::Tuple(substs) => { return name.as_tuple_index().and_then(|idx| { - substs - .as_slice(Interner) - .get(idx) - .map(|a| a.assert_ty_ref(Interner)) - .cloned() - .map(|ty| { - ( - Either::Right(TupleFieldId { - tuple: TupleId( - self.tuple_field_accesses_rev - .insert_full(substs.clone()) - .0 - as u32, - ), - index: idx as u32, - }), - ty, - ) - }) + substs.as_slice().get(idx).copied().map(|ty| { + ( + Either::Right(TupleFieldId { + tuple: TupleId( + self.tuple_field_accesses_rev + .insert_full(substs.to_chalk(interner)) + .0 as u32, + ), + index: idx as u32, + }), + ty.to_chalk(interner), + ) + }) }); } - &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref parameters) => { - let local_id = s.fields(self.db).field(name)?; - let field = FieldId { parent: s.into(), local_id }; - (field, parameters.clone()) - } - &TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), ref parameters) => { - let local_id = u.fields(self.db).field(name)?; - let field = FieldId { parent: u.into(), local_id }; - (field, parameters.clone()) - } + crate::next_solver::TyKind::Adt(adt, parameters) => match adt.def_id().0 { + hir_def::AdtId::StructId(s) => { + let local_id = s.fields(self.db).field(name)?; + let field = FieldId { parent: s.into(), local_id }; + (field, parameters) + } + hir_def::AdtId::UnionId(u) => { + let local_id = u.fields(self.db).field(name)?; + let field = FieldId { parent: u.into(), local_id }; + (field, parameters) + } + hir_def::AdtId::EnumId(_) => return None, + }, _ => return None, }; + let parameters: crate::Substitution = parameters.to_chalk(interner); let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id] .is_visible_from(self.db, self.resolver.module()); if !is_visible { if private_field.is_none() { - private_field = Some((field_id, parameters)); + private_field = Some((field_id, parameters.clone())); } return None; } @@ -1629,14 +1728,14 @@ impl InferenceContext<'_> { Some(match res { Some((field_id, ty)) => { - let adjustments = auto_deref_adjust_steps(&autoderef); + let adjustments = autoderef.adjust_steps(); let ty = self.process_remote_user_written_ty(ty); (ty, field_id, adjustments, true) } None => { let (field_id, subst) = private_field?; - let adjustments = auto_deref_adjust_steps(&autoderef); + let adjustments = autoderef.adjust_steps(); let ty = self.db.field_types(field_id.parent)[field_id.local_id] .clone() .substitute(Interner, &subst); @@ -1725,11 +1824,13 @@ impl InferenceContext<'_> { expected: &Expectation, ) -> Ty { let callee_ty = self.infer_expr(callee, &Expectation::none(), ExprIsRead::Yes); - let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true); + let interner = self.table.interner; + let mut derefs = self.table.autoderef(callee_ty.to_nextsolver(interner)); let (res, derefed_callee) = loop { let Some((callee_deref_ty, _)) = derefs.next() else { break (None, callee_ty.clone()); }; + let callee_deref_ty = callee_deref_ty.to_chalk(interner); if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) { break (Some(res), callee_deref_ty); } @@ -1740,28 +1841,30 @@ impl InferenceContext<'_> { derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs) || res.is_none(); let (param_tys, ret_ty) = match res { Some((func, params, ret_ty)) => { - let mut adjustments = auto_deref_adjust_steps(&derefs); - if let TyKind::Closure(c, _) = - self.table.resolve_completely(callee_ty.clone()).kind(Interner) - { - self.add_current_closure_dependency(*c); - self.deferred_closures.entry(*c).or_default().push(( - derefed_callee.clone(), - callee_ty.clone(), - params.clone(), - tgt_expr, - )); - } + let params_chalk = + params.iter().map(|param| param.to_chalk(interner)).collect::>(); + let mut adjustments = derefs.adjust_steps(); if let Some(fn_x) = func { self.write_fn_trait_method_resolution( fn_x, &derefed_callee, &mut adjustments, &callee_ty, - ¶ms, + ¶ms_chalk, tgt_expr, ); } + if let &TyKind::Closure(c, _) = + self.table.resolve_completely(callee_ty.clone()).kind(Interner) + { + self.add_current_closure_dependency(c.into()); + self.deferred_closures.entry(c.into()).or_default().push(( + derefed_callee.clone(), + callee_ty.clone(), + params_chalk, + tgt_expr, + )); + } self.write_expr_adj(callee, adjustments.into_boxed_slice()); (params, ret_ty) } @@ -1770,7 +1873,7 @@ impl InferenceContext<'_> { call_expr: tgt_expr, found: callee_ty.clone(), }); - (Vec::new(), self.err_ty()) + (Vec::new(), crate::next_solver::Ty::new_error(interner, ErrorGuaranteed)) } }; let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args); @@ -1791,29 +1894,24 @@ impl InferenceContext<'_> { tgt_expr: ExprId, args: &[ExprId], callee_ty: Ty, - param_tys: &[Ty], - ret_ty: Ty, + param_tys: &[crate::next_solver::Ty<'db>], + ret_ty: crate::next_solver::Ty<'db>, indices_to_skip: &[u32], is_varargs: bool, expected: &Expectation, ) -> Ty { self.register_obligations_for_call(&callee_ty); - let expected_inputs = self.expected_inputs_for_expected_output( - expected, - ret_ty.clone(), - param_tys.to_owned(), - ); - self.check_call_arguments( tgt_expr, - args, - &expected_inputs, param_tys, + ret_ty, + expected, + args, indices_to_skip, is_varargs, ); - self.normalize_associated_types_in(ret_ty) + self.table.normalize_associated_types_in_ns(ret_ty).to_chalk(self.table.interner) } fn infer_method_call( @@ -1826,6 +1924,21 @@ impl InferenceContext<'_> { expected: &Expectation, ) -> Ty { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes); + let receiver_ty = self.table.structurally_resolve_type(&receiver_ty); + + if matches!( + receiver_ty.kind(Interner), + TyKind::Error | TyKind::InferenceVar(_, TyVariableKind::General) + ) { + // Don't probe on error type, or on a fully unresolved infer var. + // FIXME: Emit an error if we're probing on an infer var (type annotations needed). + for &arg in args { + // Make sure we infer and record the arguments. + self.infer_expr_no_expect(arg, ExprIsRead::Yes); + } + return receiver_ty; + } + let canonicalized_receiver = self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); @@ -1918,14 +2031,21 @@ impl InferenceContext<'_> { tgt_expr, args, callee_ty, - sig.params().get(strip_first as usize..).unwrap_or(&[]), - sig.ret().clone(), + &sig.params() + .get(strip_first as usize..) + .unwrap_or(&[]) + .iter() + .map(|param| param.to_nextsolver(self.table.interner)) + .collect::>(), + sig.ret().to_nextsolver(self.table.interner), &[], true, expected, ), None => { - self.check_call_arguments(tgt_expr, args, &[], &[], &[], true); + for &arg in args.iter() { + self.infer_expr_no_expect(arg, ExprIsRead::Yes); + } self.err_ty() } } @@ -1944,151 +2064,252 @@ impl InferenceContext<'_> { ) -> Ty { let method_ty = method_ty.substitute(Interner, &substs); self.register_obligations_for_call(&method_ty); + let interner = self.table.interner; let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) = match method_ty.callable_sig(self.db) { Some(sig) => ( if !sig.params().is_empty() { - (sig.params()[0].clone(), sig.params()[1..].to_vec()) + ( + sig.params()[0].to_nextsolver(interner), + sig.params()[1..] + .iter() + .map(|param| param.to_nextsolver(interner)) + .collect(), + ) } else { - (self.err_ty(), Vec::new()) + (crate::next_solver::Ty::new_error(interner, ErrorGuaranteed), Vec::new()) }, - sig.ret().clone(), + sig.ret().to_nextsolver(interner), sig.is_varargs, ), None => { - let formal_receiver_ty = self.table.new_type_var(); - let ret_ty = self.table.new_type_var(); + let formal_receiver_ty = self.table.next_ty_var(); + let ret_ty = self.table.next_ty_var(); ((formal_receiver_ty, Vec::new()), ret_ty, true) } }; - self.unify(&formal_receiver_ty, &receiver_ty); - - let expected_inputs = - self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone()); + self.table.unify_ns(formal_receiver_ty, receiver_ty.to_nextsolver(interner)); - self.check_call_arguments(tgt_expr, args, &expected_inputs, ¶m_tys, &[], is_varargs); - self.normalize_associated_types_in(ret_ty) + self.check_call_arguments(tgt_expr, ¶m_tys, ret_ty, expected, args, &[], is_varargs); + self.table.normalize_associated_types_in_ns(ret_ty).to_chalk(interner) } - fn expected_inputs_for_expected_output( + /// Generic function that factors out common logic from function calls, + /// method calls and overloaded operators. + pub(in super::super) fn check_call_arguments( &mut self, - expected_output: &Expectation, - output: Ty, - inputs: Vec, - ) -> Vec { - if let Some(expected_ty) = expected_output.only_has_type(&mut self.table) { - self.table.fudge_inference(|table| { - if table.try_unify(&expected_ty, &output).is_ok() { - table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind { - chalk_ir::VariableKind::Ty(tk) => var.to_ty(Interner, tk).cast(Interner), - chalk_ir::VariableKind::Lifetime => { - var.to_lifetime(Interner).cast(Interner) - } - chalk_ir::VariableKind::Const(ty) => { - var.to_const(Interner, ty).cast(Interner) + call_expr: ExprId, + // Types (as defined in the *signature* of the target function) + formal_input_tys: &[crate::next_solver::Ty<'db>], + formal_output: crate::next_solver::Ty<'db>, + // Expected output from the parent expression or statement + expectation: &Expectation, + // The expressions for each provided argument + provided_args: &[ExprId], + skip_indices: &[u32], + // Whether the function is variadic, for example when imported from C + c_variadic: bool, + ) { + let interner = self.table.interner; + + // First, let's unify the formal method signature with the expectation eagerly. + // We use this to guide coercion inference; it's output is "fudged" which means + // any remaining type variables are assigned to new, unrelated variables. This + // is because the inference guidance here is only speculative. + let formal_output = self.table.resolve_vars_with_obligations(formal_output); + let expected_input_tys: Option> = expectation + .only_has_type(&mut self.table) + .and_then(|expected_output| { + self.table + .infer_ctxt + .fudge_inference_if_ok(|| { + let mut ocx = ObligationCtxt::new(&self.table.infer_ctxt); + + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = ObligationCause::new(); + ocx.sup( + &origin, + self.table.param_env, + expected_output.to_nextsolver(interner), + formal_output, + )?; + if !ocx.select_where_possible().is_empty() { + return Err(crate::next_solver::TypeError::Mismatch); } + + // Record all the argument types, with the args + // produced from the above subtyping unification. + Ok(Some( + formal_input_tys + .iter() + .map(|&ty| self.table.infer_ctxt.resolve_vars_if_possible(ty)) + .collect(), + )) }) - } else { - Vec::new() - } + .ok() }) + .unwrap_or_default(); + + // If there are no external expectations at the call site, just use the types from the function defn + let expected_input_tys = if let Some(expected_input_tys) = &expected_input_tys { + assert_eq!(expected_input_tys.len(), formal_input_tys.len()); + expected_input_tys } else { - Vec::new() - } - } + formal_input_tys + }; - fn check_call_arguments( - &mut self, - expr: ExprId, - args: &[ExprId], - expected_inputs: &[Ty], - param_tys: &[Ty], - skip_indices: &[u32], - ignore_arg_param_mismatch: bool, - ) { - let arg_count_mismatch = - !ignore_arg_param_mismatch && args.len() != param_tys.len() + skip_indices.len(); - if arg_count_mismatch { + let minimum_input_count = expected_input_tys.len(); + let provided_arg_count = provided_args.len() - skip_indices.len(); + + // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path + // if the wrong number of arguments were supplied, we CAN'T be satisfied, + // and if we're c_variadic, the supplied arguments must be >= the minimum count from the function + // otherwise, they need to be identical, because rust doesn't currently support variadic functions + let args_count_matches = if c_variadic { + provided_arg_count >= minimum_input_count + } else { + provided_arg_count == minimum_input_count + }; + + if !args_count_matches { self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount { - call_expr: expr, - expected: param_tys.len() + skip_indices.len(), - found: args.len(), + call_expr, + expected: expected_input_tys.len() + skip_indices.len(), + found: provided_args.len(), }); + } + + // We introduce a helper function to demand that a given argument satisfy a given input + // This is more complicated than just checking type equality, as arguments could be coerced + // This version writes those types back so further type checking uses the narrowed types + let demand_compatible = |this: &mut InferenceContext<'db>, idx| { + let formal_input_ty: crate::next_solver::Ty<'db> = formal_input_tys[idx]; + let expected_input_ty: crate::next_solver::Ty<'db> = expected_input_tys[idx]; + let provided_arg = provided_args[idx]; + + debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty); + + // We're on the happy path here, so we'll do a more involved check and write back types + // To check compatibility, we'll do 3 things: + // 1. Unify the provided argument with the expected type + let expectation = Expectation::rvalue_hint(this, expected_input_ty.to_chalk(interner)); + + let checked_ty = this + .infer_expr_inner(provided_arg, &expectation, ExprIsRead::Yes) + .to_nextsolver(interner); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerced_ty = expectation + .only_has_type(&mut this.table) + .map(|it| it.to_nextsolver(interner)) + .unwrap_or(formal_input_ty); + + // Cause selection errors caused by resolving a single argument to point at the + // argument and not the call. This lets us customize the span pointed to in the + // fulfillment error to be more accurate. + let coerced_ty = this.table.resolve_vars_with_obligations(coerced_ty); + + let coerce_never = if this + .expr_guaranteed_to_constitute_read_for_never(provided_arg, ExprIsRead::Yes) + { + CoerceNever::Yes + } else { + CoerceNever::No + }; + let coerce_error = this + .coerce( + provided_arg.into(), + checked_ty, + coerced_ty, + AllowTwoPhase::Yes, + coerce_never, + ) + .err(); + if coerce_error.is_some() { + return Err((coerce_error, coerced_ty, checked_ty)); + } + + // 3. Check if the formal type is actually equal to the checked one + // and register any such obligations for future type checks. + let formal_ty_error = this + .table + .infer_ctxt + .at(&ObligationCause::new(), this.table.param_env) + .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty); + + // If neither check failed, the types are compatible + match formal_ty_error { + Ok(crate::next_solver::infer::InferOk { obligations, value: () }) => { + this.table.register_predicates(obligations); + Ok(()) + } + Err(err) => Err((Some(err), coerced_ty, checked_ty)), + } }; - // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- + // Check the arguments. // We do this in a pretty awful way: first we type-check any arguments // that are not closures, then we type-check the closures. This is so // that we have more information about the types of arguments when we // type-check the functions. This isn't really the right way to do this. for check_closures in [false, true] { - let mut skip_indices = skip_indices.iter().copied().fuse().peekable(); - let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty())); - let expected_iter = expected_inputs - .iter() - .cloned() - .chain(param_iter.clone().skip(expected_inputs.len())); - for (idx, ((&arg, param_ty), expected_ty)) in - args.iter().zip(param_iter).zip(expected_iter).enumerate() - { - let is_closure = matches!(&self.body[arg], Expr::Closure { .. }); - if is_closure != check_closures { + // More awful hacks: before we check argument types, try to do + // an "opportunistic" trait resolution of any trait bounds on + // the call. This helps coercions. + if check_closures { + self.table.select_obligations_where_possible(); + } + + let mut skip_indices = skip_indices.iter().copied(); + // Check each argument, to satisfy the input it was provided for + // Visually, we're traveling down the diagonal of the compatibility matrix + for (idx, arg) in provided_args.iter().enumerate() { + if skip_indices.clone().next() == Some(idx as u32) { + skip_indices.next(); continue; } - while skip_indices.peek().is_some_and(|&i| i < idx as u32) { - skip_indices.next(); + // For this check, we do *not* want to treat async coroutine closures (async blocks) + // as proper closures. Doing so would regress type inference when feeding + // the return value of an argument-position async block to an argument-position + // closure wrapped in a block. + // See . + let is_closure = if let Expr::Closure { closure_kind, .. } = self.body[*arg] { + !matches!(closure_kind, ClosureKind::Coroutine(_)) + } else { + false + }; + if is_closure != check_closures { + continue; } - if skip_indices.peek().copied() == Some(idx as u32) { + + if idx >= minimum_input_count { + // Make sure we've checked this expr at least once. + self.infer_expr_no_expect(*arg, ExprIsRead::Yes); continue; } - // the difference between param_ty and expected here is that - // expected is the parameter when the expected *return* type is - // taken into account. So in `let _: &[i32] = identity(&[1, 2])` - // the expected type is already `&[i32]`, whereas param_ty is - // still an unbound type variable. We don't always want to force - // the parameter to coerce to the expected type (for example in - // `coerce_unsize_expected_type_4`). - let param_ty = self.normalize_associated_types_in(param_ty); - let expected_ty = self.normalize_associated_types_in(expected_ty); - let expected = Expectation::rvalue_hint(self, expected_ty); - // infer with the expected type we have... - let ty = self.infer_expr_inner(arg, &expected, ExprIsRead::Yes); - - // then coerce to either the expected type or just the formal parameter type - let coercion_target = if let Some(ty) = expected.only_has_type(&mut self.table) { - // if we are coercing to the expectation, unify with the - // formal parameter type to connect everything - self.unify(&ty, ¶m_ty); - ty - } else { - param_ty - }; - // The function signature may contain some unknown types, so we need to insert - // type vars here to avoid type mismatch false positive. - let coercion_target = self.insert_type_vars(coercion_target); - - // Any expression that produces a value of type `!` must have diverged, - // unless it's a place expression that isn't being read from, in which case - // diverging would be unsound since we may never actually read the `!`. - // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. - let coerce_never = - if self.expr_guaranteed_to_constitute_read_for_never(arg, ExprIsRead::Yes) { - CoerceNever::Yes - } else { - CoerceNever::No - }; - if self.coerce(Some(arg), &ty, &coercion_target, coerce_never).is_err() - && !arg_count_mismatch + if let Err((_error, expected, found)) = demand_compatible(self, idx) + && args_count_matches { + // Don't report type mismatches if there is a mismatch in args count. self.result.type_mismatches.insert( - arg.into(), - TypeMismatch { expected: coercion_target, actual: ty.clone() }, + (*arg).into(), + TypeMismatch { + expected: expected.to_chalk(interner), + actual: found.to_chalk(interner), + }, ); } } } + + if !args_count_matches {} } fn substs_for_method_call( @@ -2448,10 +2669,22 @@ impl InferenceContext<'_> { cb: impl FnOnce(&mut Self) -> T, ) -> (Option, T) { self.breakables.push({ - BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label } + BreakableContext { + kind, + may_break: false, + coerce: ty.map(|ty| CoerceMany::new(ty.to_nextsolver(self.table.interner))), + label, + } }); let res = cb(self); let ctx = self.breakables.pop().expect("breakable stack broken"); - (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete(self)) } else { None }, res) + ( + if ctx.may_break { + ctx.coerce.map(|ctx| ctx.complete(self).to_chalk(self.table.interner)) + } else { + None + }, + res, + ) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 6781bc84d1c11..6e11fa942bdfb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -10,6 +10,8 @@ use hir_def::{ use hir_expand::name::Name; use stdx::TupleExt; +use crate::infer::AllowTwoPhase; +use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty, TyBuilder, TyExt, TyKind, @@ -303,16 +305,15 @@ impl InferenceContext<'_> { Pat::Path(path) => { let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty()); let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone()); - match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) { - Ok((adjustments, coerced_ty)) => { - if !adjustments.is_empty() { - self.result - .pat_adjustments - .entry(pat) - .or_default() - .extend(adjustments.into_iter().map(|adjust| adjust.target)); - } - self.write_pat_ty(pat, coerced_ty); + match self.coerce( + pat.into(), + expected.to_nextsolver(self.table.interner), + ty_inserted_vars.to_nextsolver(self.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) { + Ok(coerced_ty) => { + self.write_pat_ty(pat, coerced_ty.to_chalk(self.table.interner)); return self.pat_ty_after_adjustment(pat); } Err(_) => { @@ -387,8 +388,14 @@ impl InferenceContext<'_> { ); // We are returning early to avoid the unifiability check below. let lhs_ty = self.insert_type_vars_shallow(result); - let ty = match self.coerce(None, &expected, &lhs_ty, CoerceNever::Yes) { - Ok(ty) => ty, + let ty = match self.coerce( + pat.into(), + expected.to_nextsolver(self.table.interner), + lhs_ty.to_nextsolver(self.table.interner), + AllowTwoPhase::No, + CoerceNever::Yes, + ) { + Ok(ty) => ty.to_chalk(self.table.interner), Err(_) => { self.result.type_mismatches.insert( pat.into(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 19b83d3c212df..77eaf83eec73d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -1,6 +1,6 @@ //! Unification and canonicalization logic. -use std::{fmt, mem}; +use std::fmt; use chalk_ir::{ CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable, @@ -11,31 +11,37 @@ use hir_def::{AdtId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_next_trait_solver::solve::HasChanged; -use rustc_type_ir::inherent::IntoKind; +use rustc_type_ir::inherent::Ty as _; use rustc_type_ir::{ - AliasRelationDirection, FloatVid, IntVid, TyVid, - inherent::{Span, Term as _}, + FloatVid, IntVid, TyVid, TypeVisitableExt, + inherent::{IntoKind, Span, Term as _}, relate::{Relate, solver_relating::RelateExt}, - solve::{Certainty, NoSolution}, + solve::{Certainty, GoalSource, NoSolution}, }; -use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt}; use smallvec::SmallVec; use triomphe::Arc; -use super::{InferOk, InferResult, InferenceContext, TypeError}; +use super::{InferResult, InferenceContext, TypeError}; +use crate::next_solver::ErrorGuaranteed; use crate::{ - AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal, - GenericArg, GenericArgData, Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, - OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Substitution, TraitEnvironment, - TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, + AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData, + Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, + ProjectionTy, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, + VariableKind, WhereClause, consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, + next_solver::infer::InferOk, next_solver::{ - self, Binder, DbInterner, Predicate, PredicateKind, SolverDefIds, Term, - infer::{DbInternerInferExt, InferCtxt, snapshot::CombinedSnapshot}, - mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk}, + self, ClauseKind, DbInterner, ParamEnv, Predicate, PredicateKind, SolverDefIds, Term, + fulfill::FulfillmentCtxt, + infer::{ + DbInternerInferExt, InferCtxt, + snapshot::CombinedSnapshot, + traits::{Obligation, ObligationCause}, + }, + inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, + mapping::{ChalkToNextSolver, NextSolverToChalk}, }, to_chalk_trait_id, traits::{ @@ -50,43 +56,64 @@ impl<'db> InferenceContext<'db> { { self.table.canonicalize(t) } +} - pub(super) fn clauses_for_self_ty( - &mut self, - self_ty: InferenceVar, - ) -> SmallVec<[WhereClause; 4]> { - self.table.resolve_obligations_as_possible(); - - let root = InferenceVar::from_vid(self.table.infer_ctxt.root_var(self_ty.to_vid())); - let pending_obligations = mem::take(&mut self.table.pending_obligations); - let obligations = pending_obligations - .iter() - .filter_map(|obligation| match obligation.to_chalk(self.table.interner).goal.data(Interner) { - GoalData::DomainGoal(DomainGoal::Holds(clause)) => { - let ty = match clause { - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection), - .. - }) => projection.self_type_parameter(self.db), - WhereClause::Implemented(trait_ref) => { - trait_ref.self_type_parameter(Interner) - } - WhereClause::TypeOutlives(to) => to.ty.clone(), - _ => return None, - }; - let ty = self.resolve_ty_shallow(&ty); - if matches!(ty.kind(Interner), TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root) { - Some(clause.clone()) - } else { - None - } - } - _ => None, - }) - .collect(); - self.table.pending_obligations = pending_obligations; +struct NestedObligationsForSelfTy<'a, 'db> { + ctx: &'a InferenceTable<'db>, + self_ty: TyVid, + root_cause: &'a ObligationCause, + obligations_for_self_ty: &'a mut SmallVec<[Obligation<'db, Predicate<'db>>; 4]>, +} - obligations +impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { + type Result = (); + + fn config(&self) -> InspectConfig { + // Using an intentionally low depth to minimize the chance of future + // breaking changes in case we adapt the approach later on. This also + // avoids any hangs for exponentially growing proof trees. + InspectConfig { max_depth: 5 } + } + + fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'db>) { + // No need to walk into goal subtrees that certainly hold, since they + // wouldn't then be stalled on an infer var. + if inspect_goal.result() == Ok(Certainty::Yes) { + return; + } + + let db = self.ctx.interner; + let goal = inspect_goal.goal(); + if self.ctx.predicate_has_self_ty(goal.predicate, self.self_ty) + // We do not push the instantiated forms of goals as it would cause any + // aliases referencing bound vars to go from having escaping bound vars to + // being able to be normalized to an inference variable. + // + // This is mostly just a hack as arbitrary nested goals could still contain + // such aliases while having a different `GoalSource`. Closure signature inference + // however can't really handle *every* higher ranked `Fn` goal also being present + // in the form of `?c: Fn<(>::Assoc)`. + // + // This also just better matches the behaviour of the old solver where we do not + // encounter instantiated forms of goals, only nested goals that referred to bound + // vars from instantiated goals. + && !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked) + { + self.obligations_for_self_ty.push(Obligation::new( + db, + self.root_cause.clone(), + goal.param_env, + goal.predicate, + )); + } + + // If there's a unique way to prove a given goal, recurse into + // that candidate. This means that for `impl Trait for () {}` + // and a `(): Trait` goal we recurse into the impl and look at + // the nested `?0: FnOnce(u32)` goal. + if let Some(candidate) = inspect_goal.unique_applicable_candidate() { + candidate.visit_nested_no_probe(self) + } } } @@ -119,7 +146,7 @@ pub fn could_unify_deeply( let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); let ty1_with_vars = table.normalize_associated_types_in(ty1_with_vars); let ty2_with_vars = table.normalize_associated_types_in(ty2_with_vars); - table.resolve_obligations_as_possible(); + table.select_obligations_where_possible(); table.propagate_diverging_flag(); let ty1_with_vars = table.resolve_completely(ty1_with_vars); let ty2_with_vars = table.resolve_completely(ty2_with_vars); @@ -186,35 +213,117 @@ bitflags::bitflags! { } #[derive(Clone)] -pub(crate) struct InferenceTable<'a> { - pub(crate) db: &'a dyn HirDatabase, - pub(crate) interner: DbInterner<'a>, +pub(crate) struct InferenceTable<'db> { + pub(crate) db: &'db dyn HirDatabase, + pub(crate) interner: DbInterner<'db>, pub(crate) trait_env: Arc, + pub(crate) param_env: ParamEnv<'db>, pub(crate) tait_coercion_table: Option>, - pub(crate) infer_ctxt: InferCtxt<'a>, + pub(crate) infer_ctxt: InferCtxt<'db>, diverging_tys: FxHashSet, - pending_obligations: Vec>>, + pub(super) fulfillment_cx: FulfillmentCtxt<'db>, } -pub(crate) struct InferenceTableSnapshot<'a> { +pub(crate) struct InferenceTableSnapshot<'db> { ctxt_snapshot: CombinedSnapshot, + obligations: FulfillmentCtxt<'db>, diverging_tys: FxHashSet, - pending_obligations: Vec>>, } -impl<'a> InferenceTable<'a> { - pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { +impl<'db> InferenceTable<'db> { + pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc) -> Self { let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); + let infer_ctxt = interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { + defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), + }); InferenceTable { db, interner, + param_env: trait_env.env.to_nextsolver(interner), trait_env, tait_coercion_table: None, - infer_ctxt: interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { - defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), - }), + fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), + infer_ctxt, diverging_tys: FxHashSet::default(), - pending_obligations: Vec::new(), + } + } + + pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool { + let Some(sized_did) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else { + return true; + }; + self.obligations_for_self_ty(self_ty).into_iter().any(|obligation| { + match obligation.predicate.kind().skip_binder() { + crate::next_solver::PredicateKind::Clause( + crate::next_solver::ClauseKind::Trait(data), + ) => data.def_id().0 == sized_did, + _ => false, + } + }) + } + + pub(super) fn obligations_for_self_ty( + &self, + self_ty: TyVid, + ) -> SmallVec<[Obligation<'db, Predicate<'db>>; 4]> { + let obligations = self.fulfillment_cx.pending_obligations(); + let mut obligations_for_self_ty = SmallVec::new(); + for obligation in obligations { + let mut visitor = NestedObligationsForSelfTy { + ctx: self, + self_ty, + obligations_for_self_ty: &mut obligations_for_self_ty, + root_cause: &obligation.cause, + }; + + let goal = obligation.as_goal(); + self.infer_ctxt.visit_proof_tree(goal, &mut visitor); + } + + obligations_for_self_ty.retain_mut(|obligation| { + obligation.predicate = self.infer_ctxt.resolve_vars_if_possible(obligation.predicate); + !obligation.predicate.has_placeholders() + }); + obligations_for_self_ty + } + + fn predicate_has_self_ty(&self, predicate: Predicate<'db>, expected_vid: TyVid) -> bool { + match predicate.kind().skip_binder() { + PredicateKind::Clause(ClauseKind::Trait(data)) => { + self.type_matches_expected_vid(expected_vid, data.self_ty()) + } + PredicateKind::Clause(ClauseKind::Projection(data)) => { + self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty()) + } + PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Subtype(..) + | PredicateKind::Coerce(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) + | PredicateKind::DynCompatible(..) + | PredicateKind::NormalizesTo(..) + | PredicateKind::AliasRelate(..) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) + | PredicateKind::ConstEquate(..) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) + | PredicateKind::Ambiguous => false, + } + } + + fn type_matches_expected_vid( + &self, + expected_vid: TyVid, + ty: crate::next_solver::Ty<'db>, + ) -> bool { + let ty = self.shallow_resolve(ty); + + match ty.kind() { + crate::next_solver::TyKind::Infer(rustc_type_ir::TyVar(found_vid)) => { + self.infer_ctxt.root_var(expected_vid) == self.infer_ctxt.root_var(found_vid) + } + _ => false, } } @@ -288,13 +397,13 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> + pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where - T: rustc_type_ir::TypeFoldable>, + T: rustc_type_ir::TypeFoldable>, { // try to resolve obligations before canonicalizing, since this might // result in new knowledge about variables - self.resolve_obligations_as_possible(); + self.select_obligations_where_possible(); self.infer_ctxt.canonicalize_response(t) } @@ -306,19 +415,24 @@ impl<'a> InferenceTable<'a> { /// to do it as well. pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: ChalkToNextSolver<'a, U>, - U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + T: ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner)) .to_chalk(self.interner) } + // FIXME: We should get rid of this method. We cannot deeply normalize during inference, only when finishing. + // Inference should use shallow normalization (`try_structurally_resolve_type()`) only, when needed. pub(crate) fn normalize_associated_types_in_ns(&mut self, ty: T) -> T where - T: rustc_type_ir::TypeFoldable>, + T: rustc_type_ir::TypeFoldable> + Clone, { let ty = self.resolve_vars_with_obligations(ty); - ty.fold_with(&mut Normalizer { table: self }) + self.infer_ctxt + .at(&ObligationCause::new(), self.param_env) + .deeply_normalize(ty.clone()) + .unwrap_or(ty) } /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow @@ -388,8 +502,8 @@ impl<'a> InferenceTable<'a> { pub(crate) fn normalize_alias_ty( &mut self, - alias: crate::next_solver::Ty<'a>, - ) -> crate::next_solver::Ty<'a> { + alias: crate::next_solver::Ty<'db>, + ) -> crate::next_solver::Ty<'db> { let infer_term = self.infer_ctxt.next_ty_var(); let obligation = crate::next_solver::Predicate::new( self.interner, @@ -430,6 +544,10 @@ impl<'a> InferenceTable<'a> { self.new_var(TyVariableKind::General, false) } + pub(crate) fn next_ty_var(&mut self) -> crate::next_solver::Ty<'db> { + self.infer_ctxt.next_ty_var() + } + pub(crate) fn new_integer_var(&mut self) -> Ty { self.new_var(TyVariableKind::Integer, false) } @@ -454,6 +572,10 @@ impl<'a> InferenceTable<'a> { var.to_lifetime(Interner) } + pub(crate) fn next_region_var(&mut self) -> crate::next_solver::Region<'db> { + self.infer_ctxt.next_region_var() + } + pub(crate) fn resolve_with_fallback( &mut self, t: T, @@ -488,10 +610,10 @@ impl<'a> InferenceTable<'a> { pub(crate) fn instantiate_canonical_ns( &mut self, - canonical: rustc_type_ir::Canonical, T>, + canonical: rustc_type_ir::Canonical, T>, ) -> T where - T: rustc_type_ir::TypeFoldable>, + T: rustc_type_ir::TypeFoldable>, { self.infer_ctxt.instantiate_canonical(&canonical).0 } @@ -513,8 +635,8 @@ impl<'a> InferenceTable<'a> { pub(crate) fn resolve_completely(&mut self, t: T) -> T where - T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, - U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { let t = self.resolve_with_fallback(t, &|_, _, d, _| d); let t = self.normalize_associated_types_in(t); @@ -566,7 +688,7 @@ impl<'a> InferenceTable<'a> { } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. - pub(crate) fn unify, U: Relate>>( + pub(crate) fn unify, U: Relate>>( &mut self, ty1: &T, ty2: &T, @@ -575,12 +697,20 @@ impl<'a> InferenceTable<'a> { Ok(r) => r, Err(_) => return false, }; - self.register_infer_ok(result); + self.register_obligations(result.goals); + true + } + + pub(crate) fn unify_ns>>(&mut self, lhs: T, rhs: T) -> bool { + let Ok(infer_ok) = self.try_unify_ns(lhs, rhs) else { + return false; + }; + self.register_obligations(infer_ok.goals); true } /// Unify two relatable values (e.g. `Ty`) and check whether trait goals which arise from that could be fulfilled - pub(crate) fn unify_deeply, U: Relate>>( + pub(crate) fn unify_deeply, U: Relate>>( &mut self, ty1: &T, ty2: &T, @@ -596,18 +726,27 @@ impl<'a> InferenceTable<'a> { /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the /// caller needs to deal with them. - pub(crate) fn try_unify, U: Relate>>( + pub(crate) fn try_unify, U: Relate>>( &mut self, t1: &T, t2: &T, - ) -> InferResult<'a, ()> { - let param_env = self.trait_env.env.to_nextsolver(self.interner); + ) -> InferResult<'db, ()> { let lhs = t1.to_nextsolver(self.interner); let rhs = t2.to_nextsolver(self.interner); + self.try_unify_ns(lhs, rhs) + } + + /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the + /// caller needs to deal with them. + pub(crate) fn try_unify_ns>>( + &mut self, + lhs: T, + rhs: T, + ) -> InferResult<'db, ()> { let variance = rustc_type_ir::Variance::Invariant; let span = crate::next_solver::Span::dummy(); - match self.infer_ctxt.relate(param_env, lhs, variance, rhs, span) { - Ok(goals) => Ok(InferOk { goals, value: () }), + match self.infer_ctxt.relate(self.param_env, lhs, variance, rhs, span) { + Ok(goals) => Ok(crate::infer::InferOk { goals, value: () }), Err(_) => Err(TypeError), } } @@ -616,17 +755,19 @@ impl<'a> InferenceTable<'a> { /// otherwise, return ty. #[tracing::instrument(skip(self))] pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { - if !ty.data(Interner).flags.intersects(chalk_ir::TypeFlags::HAS_FREE_LOCAL_NAMES) { - return ty.clone(); - } - self.infer_ctxt - .resolve_vars_if_possible(ty.to_nextsolver(self.interner)) - .to_chalk(self.interner) + self.shallow_resolve(ty.to_nextsolver(self.interner)).to_chalk(self.interner) + } + + pub(crate) fn shallow_resolve( + &self, + ty: crate::next_solver::Ty<'db>, + ) -> crate::next_solver::Ty<'db> { + self.infer_ctxt.shallow_resolve(ty) } pub(crate) fn resolve_vars_with_obligations(&mut self, t: T) -> T where - T: rustc_type_ir::TypeFoldable>, + T: rustc_type_ir::TypeFoldable>, { use rustc_type_ir::TypeVisitableExt; @@ -640,7 +781,7 @@ impl<'a> InferenceTable<'a> { return t; } - self.resolve_obligations_as_possible(); + self.select_obligations_where_possible(); self.infer_ctxt.resolve_vars_if_possible(t) } @@ -659,42 +800,58 @@ impl<'a> InferenceTable<'a> { .to_chalk(self.interner) } - fn structurally_normalize_term(&mut self, term: Term<'a>) -> Term<'a> { - if term.to_alias_term().is_none() { - return term; - } - - let new_infer = self.infer_ctxt.next_term_var_of_kind(term); + fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> { + self.infer_ctxt + .at(&ObligationCause::new(), self.param_env) + .structurally_normalize_term(term, &mut self.fulfillment_cx) + .unwrap_or(term) + } - self.register_obligation(Predicate::new( - self.interner, - Binder::dummy(PredicateKind::AliasRelate( - term, - new_infer, - AliasRelationDirection::Equate, - )), - )); - self.resolve_obligations_as_possible(); - let res = self.infer_ctxt.resolve_vars_if_possible(new_infer); - if res == new_infer { term } else { res } + /// Try to resolve `ty` to a structural type, normalizing aliases. + /// + /// In case there is still ambiguity, the returned type may be an inference + /// variable. This is different from `structurally_resolve_type` which errors + /// in this case. + pub(crate) fn try_structurally_resolve_type( + &mut self, + ty: crate::next_solver::Ty<'db>, + ) -> crate::next_solver::Ty<'db> { + if let crate::next_solver::TyKind::Alias(..) = ty.kind() { + // We need to use a separate variable here as otherwise the temporary for + // `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting + // in a reentrant borrow, causing an ICE. + let result = self + .infer_ctxt + .at(&ObligationCause::misc(), self.param_env) + .structurally_normalize_ty(ty, &mut self.fulfillment_cx); + match result { + Ok(normalized_ty) => normalized_ty, + Err(_errors) => crate::next_solver::Ty::new_error(self.interner, ErrorGuaranteed), + } + } else { + self.resolve_vars_with_obligations(ty) + } } - pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'a> { + pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> { let ctxt_snapshot = self.infer_ctxt.start_snapshot(); let diverging_tys = self.diverging_tys.clone(); - let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot { ctxt_snapshot, pending_obligations, diverging_tys } + let obligations = self.fulfillment_cx.clone(); + InferenceTableSnapshot { ctxt_snapshot, diverging_tys, obligations } } #[tracing::instrument(skip_all)] - pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'a>) { + pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) { self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); self.diverging_tys = snapshot.diverging_tys; - self.pending_obligations = snapshot.pending_obligations; + self.fulfillment_cx = snapshot.obligations; } #[tracing::instrument(skip_all)] - pub(crate) fn run_in_snapshot(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T { + pub(crate) fn run_in_snapshot( + &mut self, + f: impl FnOnce(&mut InferenceTable<'db>) -> T, + ) -> T { let snapshot = self.snapshot(); let result = f(self); self.rollback_to(snapshot); @@ -703,7 +860,7 @@ impl<'a> InferenceTable<'a> { pub(crate) fn commit_if_ok( &mut self, - f: impl FnOnce(&mut InferenceTable<'_>) -> Result, + f: impl FnOnce(&mut InferenceTable<'db>) -> Result, ) -> Result { let snapshot = self.snapshot(); let result = f(self); @@ -735,7 +892,7 @@ impl<'a> InferenceTable<'a> { result.map(|m| m.1) } - pub(crate) fn register_obligation(&mut self, predicate: Predicate<'a>) { + pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { let goal = next_solver::Goal { param_env: self.trait_env.env.to_nextsolver(self.interner), predicate, @@ -746,7 +903,7 @@ impl<'a> InferenceTable<'a> { #[tracing::instrument(level = "debug", skip(self))] fn register_obligation_in_env( &mut self, - goal: next_solver::Goal<'a, next_solver::Predicate<'a>>, + goal: next_solver::Goal<'db, next_solver::Predicate<'db>>, ) { let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); tracing::debug!(?result); @@ -754,119 +911,68 @@ impl<'a> InferenceTable<'a> { Ok((_, Certainty::Yes)) => {} Err(rustc_type_ir::solve::NoSolution) => {} Ok((_, Certainty::Maybe(_))) => { - self.pending_obligations.push(goal); + self.fulfillment_cx.register_predicate_obligation( + &self.infer_ctxt, + Obligation::new( + self.interner, + ObligationCause::new(), + goal.param_env, + goal.predicate, + ), + ); } } } - pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk<'a, T>) { - infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); + pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk<'db, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.register_predicates(obligations); + value } - pub(crate) fn resolve_obligations_as_possible(&mut self) { - let _span = tracing::info_span!("resolve_obligations_as_possible").entered(); - let mut changed = true; - while mem::take(&mut changed) { - let mut obligations = mem::take(&mut self.pending_obligations); - - for goal in obligations.drain(..) { - tracing::debug!(obligation = ?goal); - - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); - let (has_changed, certainty) = match result { - Ok(result) => result, - Err(_) => { - continue; - } - }; - - if matches!(has_changed, HasChanged::Yes) { - changed = true; - } + pub(crate) fn register_obligations( + &mut self, + obligations: Vec>>, + ) { + obligations.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => self.pending_obligations.push(goal), - } - } - } + pub(crate) fn select_obligations_where_possible(&mut self) { + self.fulfillment_cx.select_where_possible(&self.infer_ctxt); } - pub(crate) fn fudge_inference>( + pub(super) fn register_predicate( &mut self, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - use chalk_ir::fold::TypeFolder; - - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct VarFudger<'a, 'b> { - table: &'a mut InferenceTable<'b>, - highest_known_var: InferenceVar, + obligation: crate::next_solver::infer::traits::PredicateObligation<'db>, + ) { + if obligation.has_escaping_bound_vars() { + panic!("escaping bound vars in predicate {:?}", obligation); } - impl TypeFolder for VarFudger<'_, '_> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_inference_ty( - &mut self, - var: chalk_ir::InferenceVar, - kind: TyVariableKind, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Ty { - if var < self.highest_known_var { - var.to_ty(Interner, kind) - } else { - self.table.new_type_var() - } - } - - fn fold_inference_lifetime( - &mut self, - var: chalk_ir::InferenceVar, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Lifetime { - if var < self.highest_known_var { - var.to_lifetime(Interner) - } else { - self.table.new_lifetime_var() - } - } - fn fold_inference_const( - &mut self, - ty: chalk_ir::Ty, - var: chalk_ir::InferenceVar, - _outer_binder: chalk_ir::DebruijnIndex, - ) -> chalk_ir::Const { - if var < self.highest_known_var { - var.to_const(Interner, ty) - } else { - self.table.new_const_var(ty) - } - } - } + self.fulfillment_cx.register_predicate_obligation(&self.infer_ctxt, obligation); + } - let snapshot = self.snapshot(); - let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var"); - let result = f(self); - self.rollback_to(snapshot); - result - .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST) + pub(super) fn register_predicates(&mut self, obligations: I) + where + I: IntoIterator>, + { + obligations.into_iter().for_each(|obligation| { + self.register_predicate(obligation); + }); } pub(crate) fn callable_sig( &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option, Vec, Ty)> { + ) -> Option<(Option, Vec>, crate::next_solver::Ty<'db>)> + { match ty.callable_sig(self.db) { - Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())), + Some(sig) => Some(( + None, + sig.params().iter().map(|param| param.to_nextsolver(self.interner)).collect(), + sig.ret().to_nextsolver(self.interner), + )), None => { let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?; Some((Some(f), args_ty, return_ty)) @@ -878,7 +984,7 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(FnTrait, Vec, Ty)> { + ) -> Option<(FnTrait, Vec>, crate::next_solver::Ty<'db>)> { for (fn_trait_name, output_assoc_name, subtraits) in [ (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]), (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]), @@ -898,7 +1004,7 @@ impl<'a> InferenceTable<'a> { ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), ParamKind::Const(_) => unreachable!("Tuple with const parameter"), }; - arg_tys.push(arg.clone()); + arg_tys.push(arg.to_nextsolver(self.interner)); arg.cast(Interner) }) .build(); @@ -920,7 +1026,8 @@ impl<'a> InferenceTable<'a> { let goal: Goal = trait_ref.clone().cast(Interner); if !self.try_obligation(goal.clone()).no_solution() { self.register_obligation(goal.to_nextsolver(self.interner)); - let return_ty = self.normalize_projection_ty(projection); + let return_ty = + self.normalize_projection_ty(projection).to_nextsolver(self.interner); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); @@ -969,8 +1076,8 @@ impl<'a> InferenceTable<'a> { /// Whenever you lower a user-written type, you should call this. pub(crate) fn process_user_written_ty(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, - U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { self.process_remote_user_written_ty(ty) // FIXME: Register a well-formed obligation. @@ -980,13 +1087,14 @@ impl<'a> InferenceTable<'a> { /// while `process_user_written_ty()` should (but doesn't currently). pub(crate) fn process_remote_user_written_ty(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, - U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { let ty = self.insert_type_vars(ty); // See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495: // Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs // to normalize before inspecting the `TyKind`. + // FIXME(next-solver): We should not deeply normalize here, only shallowly. self.normalize_associated_types_in(ty) } @@ -1074,7 +1182,10 @@ impl<'a> InferenceTable<'a> { impl fmt::Debug for InferenceTable<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("InferenceTable").finish() + f.debug_struct("InferenceTable") + .field("name", &self.infer_ctxt.inner.borrow().type_variable_storage) + .field("fulfillment_cx", &self.fulfillment_cx) + .finish() } } @@ -1091,7 +1202,7 @@ mod resolve { }; use rustc_type_ir::{FloatVid, IntVid, TyVid}; - #[derive(Copy, Clone, PartialEq, Eq)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(super) enum VarKind { Ty(TyVariableKind), Const, @@ -1264,62 +1375,3 @@ mod resolve { } } } - -/// This expects its input to be resolved. -struct Normalizer<'a, 'b> { - table: &'a mut InferenceTable<'b>, -} - -impl<'db> Normalizer<'_, 'db> { - fn normalize_alias_term( - &mut self, - alias_term: crate::next_solver::Term<'db>, - ) -> crate::next_solver::Term<'db> { - let infer_term = self.table.infer_ctxt.next_term_var_of_kind(alias_term); - let obligation = crate::next_solver::Predicate::new( - self.table.interner, - crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate( - alias_term, - infer_term, - rustc_type_ir::AliasRelationDirection::Equate, - )), - ); - self.table.register_obligation(obligation); - let term = self.table.resolve_vars_with_obligations(infer_term); - // Now normalize the result, because maybe it contains more aliases. - match term { - Term::Ty(term) => term.super_fold_with(self).into(), - Term::Const(term) => term.super_fold_with(self).into(), - } - } -} - -impl<'db> rustc_type_ir::TypeFolder> for Normalizer<'_, 'db> { - fn cx(&self) -> DbInterner<'db> { - self.table.interner - } - - fn fold_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> { - if !ty.has_aliases() { - return ty; - } - - let crate::next_solver::TyKind::Alias(..) = ty.kind() else { - return ty.super_fold_with(self); - }; - // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only). - self.normalize_alias_term(ty.into()).expect_type() - } - - fn fold_const(&mut self, ct: crate::next_solver::Const<'db>) -> crate::next_solver::Const<'db> { - if !ct.has_aliases() { - return ct; - } - - let crate::next_solver::ConstKind::Unevaluated(..) = ct.kind() else { - return ct.super_fold_with(self); - }; - // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only). - self.normalize_alias_term(ct.into()).expect_const() - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 2020a8b34b4f9..f21673c732e40 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -28,7 +28,6 @@ use crate::{ DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, mapping::{ChalkToNextSolver, convert_args_for_result}, - project::solve_normalize::deeply_normalize, }, }; @@ -172,7 +171,7 @@ pub fn layout_of_ty_query<'db>( let cx = LayoutCx::new(dl); let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); - let ty = deeply_normalize(infer_ctxt.at(&cause, ParamEnv::empty()), ty).unwrap_or(ty); + let ty = infer_ctxt.at(&cause, ParamEnv::empty()).deeply_normalize(ty).unwrap_or(ty); let result = match ty.kind() { TyKind::Adt(def, args) => { match def.inner().id { @@ -335,8 +334,8 @@ pub fn layout_of_ty_query<'db>( .clone() .substitute( Interner, - ClosureSubst(&convert_args_for_result(interner, args.inner())) - .parent_subst(), + &ClosureSubst(&convert_args_for_result(interner, args.inner())) + .parent_subst(db), ) .to_nextsolver(interner); db.layout_of_ty(ty, trait_env.clone()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 02fdbf0ebf0df..3d3cbeaf4b2d5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -115,7 +115,7 @@ pub use infer::{ Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, PointerCast, cast::CastError, - closure::{CaptureKind, CapturedItem}, + closure::analysis::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, }; pub use interner::Interner; @@ -133,8 +133,8 @@ pub use method_resolution::check_orphan_rules; pub use target_feature::TargetFeatures; pub use traits::TraitEnvironment; pub use utils::{ - Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call, - target_feature_is_safe_in_target, + TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits, + is_fn_unsafe_to_call, target_feature_is_safe_in_target, }; pub use variance::Variance; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 5c29befe123cf..2292e5c99413e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -17,6 +17,7 @@ use std::{ use base_db::Crate; use either::Either; +use hir_def::item_tree::FieldsShape; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId, @@ -34,6 +35,7 @@ use hir_def::{ TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; +use hir_def::{ConstId, StaticId}; use hir_expand::name::Name; use intern::sym; use la_arena::{Arena, ArenaMap, Idx}; @@ -53,6 +55,7 @@ use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; +use crate::ValueTyDefId; use crate::{ FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, @@ -206,6 +209,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } + pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) { + self.lifetime_elision = lifetime_elision; + } + pub(crate) fn with_debruijn( &mut self, debruijn: DebruijnIndex, @@ -958,6 +965,105 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind } } +/// Build the declared type of a function. This should not need to look at the +/// function body. +fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::FunctionId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + )) +} + +/// Build the declared type of a const. +fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { + let resolver = def.resolver(db); + let data = db.const_signature(def); + let parent = def.loc(db).container; + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ); + ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); + EarlyBinder::bind(ctx.lower_ty(data.type_ref)) +} + +/// Build the declared type of a static. +fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { + let resolver = def.resolver(db); + let module = resolver.module(); + let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block()); + let data = db.static_signature(def); + let parent = def.loc(db).container; + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ); + ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); + EarlyBinder::bind(ctx.lower_ty(data.type_ref)) +} + +/// Build the type of a tuple struct constructor. +fn type_for_struct_constructor<'db>( + db: &'db dyn HirDatabase, + def: StructId, +) -> Option>> { + let struct_data = def.fields(db); + match struct_data.shape { + FieldsShape::Record => None, + FieldsShape::Unit => Some(type_for_adt(db, def.into())), + FieldsShape::Tuple => { + let interner = DbInterner::new_with(db, None, None); + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::StructId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + ))) + } + } +} + +/// Build the type of a tuple enum variant constructor. +fn type_for_enum_variant_constructor<'db>( + db: &'db dyn HirDatabase, + def: EnumVariantId, +) -> Option>> { + let struct_data = def.fields(db); + match struct_data.shape { + FieldsShape::Record => None, + FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), + FieldsShape::Tuple => { + let interner = DbInterner::new_with(db, None, None); + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::EnumVariantId(def).into(), + GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + ))) + } + } +} + +pub(crate) fn value_ty_query<'db>( + db: &'db dyn HirDatabase, + def: ValueTyDefId, +) -> Option>> { + match def { + ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), + ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), + ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), + ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), + ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), + ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), + } +} + pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, t: TypeAliasId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index ac85bf7950723..a4427517a10b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -24,7 +24,7 @@ use triomphe::Arc; use crate::{ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef, - TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause, + TraitRefExt, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause, autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, @@ -622,18 +622,23 @@ pub struct ReceiverAdjustments { } impl ReceiverAdjustments { - pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec) { - let mut ty = table.structurally_resolve_type(&ty); + pub(crate) fn apply( + &self, + table: &mut InferenceTable<'_>, + mut ty: Ty, + ) -> (Ty, Vec) { let mut adjust = Vec::new(); + let mut autoderef = table.autoderef(ty.to_nextsolver(table.interner)); + autoderef.next(); for _ in 0..self.autoderefs { - match autoderef::autoderef_step(table, ty.clone(), true, false) { + match autoderef.next() { None => { never!("autoderef not possible for {:?}", ty); ty = TyKind::Error.intern(Interner); break; } - Some((kind, new_ty)) => { - ty = new_ty.clone(); + Some((new_ty, _)) => { + ty = new_ty.to_chalk(autoderef.table.interner); let mutbl = match self.autoref { Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m), Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not), @@ -641,11 +646,11 @@ impl ReceiverAdjustments { None => None, }; adjust.push(Adjustment { - kind: Adjust::Deref(match kind { + kind: Adjust::Deref(match autoderef.steps().last().unwrap().1 { AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)), AutoderefKind::Builtin => None, }), - target: new_ty, + target: ty.clone(), }); } } @@ -1282,17 +1287,20 @@ fn iterate_method_candidates_by_receiver<'db>( name: Option<&Name>, callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { + let interner = table.interner; let receiver_ty = table.instantiate_canonical_ns(receiver_ty); - let receiver_ty: crate::Ty = receiver_ty.to_chalk(table.interner); + let receiver_ty: crate::Ty = receiver_ty.to_chalk(interner); // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that, including raw derefs. table.run_in_snapshot(|table| { let mut autoderef = - autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true); + autoderef::Autoderef::new_no_tracking(table, receiver_ty.to_nextsolver(interner)) + .include_raw_pointers() + .use_receiver_trait(); while let Some((self_ty, _)) = autoderef.next() { iterate_inherent_methods( - &self_ty, + &self_ty.to_chalk(interner), autoderef.table, name, Some(&receiver_ty), @@ -1308,15 +1316,18 @@ fn iterate_method_candidates_by_receiver<'db>( })?; table.run_in_snapshot(|table| { let mut autoderef = - autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true); + autoderef::Autoderef::new_no_tracking(table, receiver_ty.to_nextsolver(interner)) + .include_raw_pointers() + .use_receiver_trait(); while let Some((self_ty, _)) = autoderef.next() { - if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) { + if matches!(self_ty.kind(), crate::next_solver::TyKind::Infer(rustc_type_ir::TyVar(_))) + { // don't try to resolve methods on unknown types return ControlFlow::Continue(()); } iterate_trait_method_candidates( - &self_ty, + &self_ty.to_chalk(interner), autoderef.table, traits_in_scope, name, @@ -1760,7 +1771,8 @@ fn is_valid_trait_method_candidate( for pred in infer_ok.into_obligations() { ctxt.register_predicate_obligation(&table.infer_ctxt, pred); } - check_that!(ctxt.select_all_or_error(&table.infer_ctxt).is_empty()); + // FIXME: Are we doing this correctly? Probably better to follow rustc more closely. + check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty()); } check_that!(table.unify(receiver_ty, &expected_receiver)); @@ -1937,11 +1949,10 @@ fn autoderef_method_receiver<'db>( ) -> Vec<(next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> { let interner = table.interner; let mut deref_chain = Vec::new(); - let mut autoderef = - autoderef::Autoderef::new_no_tracking(table, ty.to_chalk(interner), false, true); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty).use_receiver_trait(); while let Some((ty, derefs)) = autoderef.next() { deref_chain.push(( - autoderef.table.canonicalize(ty.to_nextsolver(interner)), + autoderef.table.canonicalize(ty), ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false }, )); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index 52df851c30d13..2c09fb9a89e78 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -113,8 +113,13 @@ fn make_fetch_closure_field( let InternedClosure(def, _) = db.lookup_intern_closure(c.into()); let infer = db.infer(def); let (captures, _) = infer.closure_info(&c); - let parent_subst = ClosureSubst(subst).parent_subst(); - captures.get(f).expect("broken closure field").ty.clone().substitute(Interner, parent_subst) + let parent_subst = ClosureSubst(subst).parent_subst(db); + captures + .get(f) + .expect("broken closure field") + .ty + .clone() + .substitute(Interner, &parent_subst) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index cddd1fb7be526..6f950b8022c98 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -712,13 +712,13 @@ impl<'db> Evaluator<'db> { let InternedClosure(def, _) = self.db.lookup_intern_closure(c.into()); let infer = self.db.infer(def); let (captures, _) = infer.closure_info(&c); - let parent_subst = ClosureSubst(subst).parent_subst(); + let parent_subst = ClosureSubst(subst).parent_subst(self.db); captures .get(f) .expect("broken closure field") .ty .clone() - .substitute(Interner, parent_subst) + .substitute(Interner, &parent_subst) }, self.crate_id, ); @@ -2772,7 +2772,7 @@ impl<'db> Evaluator<'db> { TyKind::Closure(closure, subst) => self.exec_closure( *closure, func_data, - &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()), + &ClosureSubst(subst).parent_subst(self.db), destination, &args[1..], locals, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index e27d334d2a991..f67778b0f12f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -4,6 +4,7 @@ use std::cmp::{self, Ordering}; use chalk_ir::TyKind; +use hir_def::signatures::FunctionSignature; use hir_def::{ CrateRootModuleId, builtin_type::{BuiltinInt, BuiltinUint}, @@ -63,17 +64,7 @@ impl Evaluator<'_> { let function_data = self.db.function_signature(def); let attrs = self.db.attrs(def.into()); - let is_intrinsic = attrs.by_key(sym::rustc_intrinsic).exists() - // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used - || (match &function_data.abi { - Some(abi) => *abi == sym::rust_dash_intrinsic, - None => match def.lookup(self.db).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - block.abi(self.db) == Some(sym::rust_dash_intrinsic) - } - _ => false, - }, - }); + let is_intrinsic = FunctionSignature::is_intrinsic(self.db, def); if is_intrinsic { return self.exec_intrinsic( @@ -194,7 +185,7 @@ impl Evaluator<'_> { let infer = self.db.infer(closure_owner); let (captures, _) = infer.closure_info(id); let layout = self.layout(self_ty.to_nextsolver(interner))?; - let ty_iter = captures.iter().map(|c| c.ty(subst)); + let ty_iter = captures.iter().map(|c| c.ty(self.db, subst)); self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?; } TyKind::Tuple(_, subst) => { 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 5a56d99fbaa29..2a6e3a147a7d7 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 @@ -12,34 +12,37 @@ use crate::{ use super::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError> { - let module_id = db.module_for_file(file_id.file_id(db)); - let def_map = module_id.def_map(db); - let scope = &def_map[module_id.local_id].scope; - let func_id = scope - .declarations() - .find_map(|x| match x { - hir_def::ModuleDefId::FunctionId(x) => { - if db.function_signature(x).name.display(db, Edition::CURRENT).to_string() == "main" - { - Some(x) - } else { - None + salsa::attach(db, || { + let module_id = db.module_for_file(file_id.file_id(db)); + let def_map = module_id.def_map(db); + let scope = &def_map[module_id.local_id].scope; + let func_id = scope + .declarations() + .find_map(|x| match x { + hir_def::ModuleDefId::FunctionId(x) => { + if db.function_signature(x).name.display(db, Edition::CURRENT).to_string() + == "main" + { + Some(x) + } else { + None + } } - } - _ => None, - }) - .expect("no main function found"); - let body = db - .monomorphized_mir_body( - func_id.into(), - Substitution::empty(Interner), - db.trait_environment(func_id.into()), - ) - .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; - - let (result, output) = salsa::attach(db, || interpret_mir(db, body, false, None))?; - result?; - Ok((output.stdout().into_owned(), output.stderr().into_owned())) + _ => None, + }) + .expect("no main function found"); + let body = db + .monomorphized_mir_body( + func_id.into(), + Substitution::empty(Interner), + db.trait_environment(func_id.into()), + ) + .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; + + let (result, output) = interpret_mir(db, body, false, None)?; + result?; + Ok((output.stdout().into_owned(), output.stderr().into_owned())) + }) } fn check_pass(#[rust_analyzer::rust_fixture] ra_fixture: &str) { @@ -53,43 +56,60 @@ fn check_pass_and_stdio( ) { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); - let file_id = *file_ids.last().unwrap(); - let x = eval_main(&db, file_id); - match x { - Err(e) => { - let mut err = String::new(); - let line_index = |size: TextSize| { - let mut size = u32::from(size) as usize; - let lines = ra_fixture.lines().enumerate(); - for (i, l) in lines { - if let Some(x) = size.checked_sub(l.len()) { - size = x; - } else { - return (i, size); + salsa::attach(&db, || { + let file_id = *file_ids.last().unwrap(); + let x = eval_main(&db, file_id); + match x { + Err(e) => { + let mut err = String::new(); + let line_index = |size: TextSize| { + let mut size = u32::from(size) as usize; + let lines = ra_fixture.lines().enumerate(); + for (i, l) in lines { + if let Some(x) = size.checked_sub(l.len()) { + size = x; + } else { + return (i, size); + } } - } - (usize::MAX, size) - }; - let span_formatter = |file, range: TextRange| { - format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end())) - }; - let krate = db.module_for_file(file_id.file_id(&db)).krate(); - e.pretty_print(&mut err, &db, span_formatter, DisplayTarget::from_crate(&db, krate)) + (usize::MAX, size) + }; + let span_formatter = |file, range: TextRange| { + format!( + "{:?} {:?}..{:?}", + file, + line_index(range.start()), + line_index(range.end()) + ) + }; + let krate = db.module_for_file(file_id.file_id(&db)).krate(); + e.pretty_print( + &mut err, + &db, + span_formatter, + DisplayTarget::from_crate(&db, krate), + ) .unwrap(); - panic!("Error in interpreting: {err}"); - } - Ok((stdout, stderr)) => { - assert_eq!(stdout, expected_stdout); - assert_eq!(stderr, expected_stderr); + panic!("Error in interpreting: {err}"); + } + Ok((stdout, stderr)) => { + assert_eq!(stdout, expected_stdout); + assert_eq!(stderr, expected_stderr); + } } - } + }) } fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: &str) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - let file_id = *file_ids.last().unwrap(); - let e = eval_main(&db, file_id).unwrap_err(); - assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic); + salsa::attach(&db, || { + let file_id = *file_ids.last().unwrap(); + let e = eval_main(&db, file_id).unwrap_err(); + assert_eq!( + e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), + expected_panic + ); + }) } fn check_error_with( @@ -97,9 +117,11 @@ fn check_error_with( expect_err: impl FnOnce(MirEvalError) -> bool, ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - let file_id = *file_ids.last().unwrap(); - let e = eval_main(&db, file_id).unwrap_err(); - assert!(expect_err(e)); + salsa::attach(&db, || { + let file_id = *file_ids.last().unwrap(); + let e = eval_main(&db, file_id).unwrap_err(); + assert!(expect_err(e)); + }) } #[test] @@ -492,7 +514,7 @@ fn main() { fn from_fn() { check_pass( r#" -//- minicore: fn, iterator +//- minicore: fn, iterator, sized struct FromFn(F); impl Option> Iterator for FromFn { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 45a1131e33399..50e416a66a64b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -2065,7 +2065,7 @@ pub fn mir_body_for_closure_query( }, }); ctx.result.param_locals.push(closure_local); - let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else { + let Some(sig) = ClosureSubst(substs).sig_ty(db).callable_sig(db) else { implementation_error!("closure has not callable sig"); }; let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 0225deebe4f31..34d8b649c981b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -9,14 +9,17 @@ pub mod fulfill; mod generic_arg; pub mod generics; pub mod infer; +pub(crate) mod inspect; pub mod interner; mod ir_print; pub mod mapping; +mod normalize; +pub mod obligation_ctxt; mod opaques; pub mod predicate; -pub(crate) mod project; mod region; mod solver; +mod structural_normalize; mod ty; pub mod util; @@ -37,8 +40,11 @@ pub type CanonicalVarValues<'db> = rustc_type_ir::CanonicalVarValues = rustc_type_ir::CanonicalVarKind>; pub type CanonicalQueryInput<'db, V> = rustc_type_ir::CanonicalQueryInput, V>; pub type AliasTy<'db> = rustc_type_ir::AliasTy>; +pub type FnSig<'db> = rustc_type_ir::FnSig>; pub type PolyFnSig<'db> = Binder<'db, rustc_type_ir::FnSig>>; pub type TypingMode<'db> = rustc_type_ir::TypingMode>; +pub type TypeError<'db> = rustc_type_ir::error::TypeError>; +pub type QueryResult<'db> = rustc_type_ir::solve::QueryResult>; pub type FxIndexMap = indexmap::IndexMap>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 23789b06e828b..0b3582051bc07 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -4,16 +4,19 @@ use std::hash::Hash; use hir_def::{ConstParamId, TypeOrConstParamId}; use intern::{Interned, Symbol}; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; +use rustc_ast_ir::{try_visit, visit::VisitorResult}; use rustc_type_ir::{ BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, WithCachedTypeInfo, - inherent::{IntoKind, PlaceholderLike}, + TypeVisitable, TypeVisitableExt, WithCachedTypeInfo, + inherent::{IntoKind, ParamEnv as _, PlaceholderLike, SliceLike}, relate::Relate, }; -use crate::{ConstScalar, MemoryMap, interner::InternedWrapperNoDebug}; +use crate::{ + ConstScalar, MemoryMap, + interner::InternedWrapperNoDebug, + next_solver::{ClauseKind, ParamEnv}, +}; use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty}; @@ -96,6 +99,40 @@ impl std::fmt::Debug for ParamConst { } } +impl ParamConst { + pub fn find_const_ty_from_env<'db>(self, env: ParamEnv<'db>) -> Ty<'db> { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ClauseKind::ConstArgHasType(param_ct, ty) => { + assert!(!(param_ct, ty).has_escaping_bound_vars()); + + match param_ct.kind() { + ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty), + _ => None, + } + } + _ => None, + } + }); + + // N.B. it may be tempting to fix ICEs by making this function return + // `Option>` instead of `Ty<'db>`; however, this is generally + // considered to be a bandaid solution, since it hides more important + // underlying issues with how we construct generics and predicates of + // items. It's advised to fix the underlying issue rather than trying + // to modify this function. + let ty = candidates.next().unwrap_or_else(|| { + panic!("cannot find `{self:?}` in param-env: {env:#?}"); + }); + assert!( + candidates.next().is_none(), + "did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}" + ); + ty + } +} + /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index a9c572d3f34ee..1ae59beca2728 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -17,7 +17,7 @@ pub enum Ctor { Enum(EnumVariantId), } -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum SolverDefId { AdtId(AdtId), ConstId(ConstId), @@ -32,6 +32,64 @@ pub enum SolverDefId { Ctor(Ctor), } +impl std::fmt::Debug for SolverDefId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let interner = DbInterner::conjure(); + let db = interner.db; + match *self { + SolverDefId::AdtId(AdtId::StructId(id)) => { + f.debug_tuple("AdtId").field(&db.struct_signature(id).name.as_str()).finish() + } + SolverDefId::AdtId(AdtId::EnumId(id)) => { + f.debug_tuple("AdtId").field(&db.enum_signature(id).name.as_str()).finish() + } + SolverDefId::AdtId(AdtId::UnionId(id)) => { + f.debug_tuple("AdtId").field(&db.union_signature(id).name.as_str()).finish() + } + SolverDefId::ConstId(id) => f + .debug_tuple("ConstId") + .field(&db.const_signature(id).name.as_ref().map_or("_", |name| name.as_str())) + .finish(), + SolverDefId::FunctionId(id) => { + f.debug_tuple("FunctionId").field(&db.function_signature(id).name.as_str()).finish() + } + SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(), + SolverDefId::StaticId(id) => { + f.debug_tuple("StaticId").field(&db.static_signature(id).name.as_str()).finish() + } + SolverDefId::TraitId(id) => { + f.debug_tuple("TraitId").field(&db.trait_signature(id).name.as_str()).finish() + } + SolverDefId::TypeAliasId(id) => f + .debug_tuple("TypeAliasId") + .field(&db.type_alias_signature(id).name.as_str()) + .finish(), + SolverDefId::InternedClosureId(id) => { + f.debug_tuple("InternedClosureId").field(&id).finish() + } + SolverDefId::InternedCoroutineId(id) => { + f.debug_tuple("InternedCoroutineId").field(&id).finish() + } + SolverDefId::InternedOpaqueTyId(id) => { + f.debug_tuple("InternedOpaqueTyId").field(&id).finish() + } + SolverDefId::Ctor(Ctor::Struct(id)) => { + f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish() + } + SolverDefId::Ctor(Ctor::Enum(id)) => { + let parent_enum = id.loc(db).parent; + f.debug_tuple("Ctor") + .field(&format_args!( + "\"{}::{}\"", + db.enum_signature(parent_enum).name.as_str(), + parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() + )) + .finish() + } + } + } +} + impl_from!( AdtId(StructId, EnumId, UnionId), ConstId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs index 4258f4c7ac68b..a8183ab422792 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -1,21 +1,28 @@ //! Fulfill loop for next-solver. -use std::marker::PhantomData; -use std::mem; -use std::ops::ControlFlow; -use std::vec::ExtractIf; - -use rustc_next_trait_solver::delegate::SolverDelegate; -use rustc_next_trait_solver::solve::{ - GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt, +mod errors; + +use std::{marker::PhantomData, mem, ops::ControlFlow, vec::ExtractIf}; + +use rustc_hash::FxHashSet; +use rustc_next_trait_solver::{ + delegate::SolverDelegate, + solve::{GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt}, +}; +use rustc_type_ir::{ + Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + inherent::{IntoKind, Span as _}, + solve::{Certainty, NoSolution}, }; -use rustc_type_ir::Interner; -use rustc_type_ir::inherent::Span as _; -use rustc_type_ir::solve::{Certainty, NoSolution}; -use crate::next_solver::infer::InferCtxt; -use crate::next_solver::infer::traits::{PredicateObligation, PredicateObligations}; -use crate::next_solver::{DbInterner, SolverContext, Span, TypingMode}; +use crate::next_solver::{ + DbInterner, SolverContext, SolverDefId, Span, Ty, TyKind, TypingMode, + infer::{ + InferCtxt, + traits::{PredicateObligation, PredicateObligations}, + }, + inspect::ProofTreeVisitor, +}; type PendingObligations<'db> = Vec<(PredicateObligation<'db>, Option>>)>; @@ -31,6 +38,7 @@ type PendingObligations<'db> = /// /// It is also likely that we want to use slightly different datastructures /// here as this will have to deal with far more root goals than `evaluate_all`. +#[derive(Debug, Clone)] pub struct FulfillmentCtxt<'db> { obligations: ObligationStorage<'db>, @@ -41,7 +49,7 @@ pub struct FulfillmentCtxt<'db> { usable_in_snapshot: usize, } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] struct ObligationStorage<'db> { /// Obligations which resulted in an overflow in fulfillment itself. /// @@ -123,10 +131,21 @@ impl<'db> FulfillmentCtxt<'db> { infcx: &InferCtxt<'db>, obligation: PredicateObligation<'db>, ) { - assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + // FIXME: See the comment in `select_where_possible()`. + // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); self.obligations.register(obligation, None); } + pub(crate) fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'db>, + obligations: impl IntoIterator>, + ) { + // FIXME: See the comment in `select_where_possible()`. + // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + obligations.into_iter().for_each(|obligation| self.obligations.register(obligation, None)); + } + pub(crate) fn collect_remaining_errors( &mut self, infcx: &InferCtxt<'db>, @@ -143,7 +162,11 @@ impl<'db> FulfillmentCtxt<'db> { &mut self, infcx: &InferCtxt<'db>, ) -> Vec> { - assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); + // FIXME(next-solver): We should bring this assertion back. Currently it panics because + // there are places which use `InferenceTable` and open a snapshot and register obligations + // and select. They should use a different `ObligationCtxt` instead. Then we'll be also able + // to not put the obligations queue in `InferenceTable`'s snapshots. + // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); loop { let mut any_changed = false; @@ -216,9 +239,94 @@ impl<'db> FulfillmentCtxt<'db> { self.obligations.has_pending_obligations() } - fn pending_obligations(&self) -> PredicateObligations<'db> { + pub(crate) fn pending_obligations(&self) -> PredicateObligations<'db> { self.obligations.clone_pending() } + + pub(crate) fn drain_stalled_obligations_for_coroutines( + &mut self, + infcx: &InferCtxt<'db>, + ) -> PredicateObligations<'db> { + let stalled_coroutines = match infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators + } + TypingMode::Coherence + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } + | TypingMode::PostAnalysis => return Default::default(), + }; + let stalled_coroutines = stalled_coroutines.inner(); + + if stalled_coroutines.is_empty() { + return Default::default(); + } + + self.obligations + .drain_pending(|obl| { + infcx.probe(|_| { + infcx + .visit_proof_tree( + obl.as_goal(), + &mut StalledOnCoroutines { + stalled_coroutines, + cache: Default::default(), + }, + ) + .is_break() + }) + }) + .into_iter() + .map(|(o, _)| o) + .collect() + } +} + +/// Detect if a goal is stalled on a coroutine that is owned by the current typeck root. +/// +/// This function can (erroneously) fail to detect a predicate, i.e. it doesn't need to +/// be complete. However, this will lead to ambiguity errors, so we want to make it +/// accurate. +/// +/// This function can be also return false positives, which will lead to poor diagnostics +/// so we want to keep this visitor *precise* too. +pub struct StalledOnCoroutines<'a, 'db> { + pub stalled_coroutines: &'a [SolverDefId], + pub cache: FxHashSet>, +} + +impl<'db> ProofTreeVisitor<'db> for StalledOnCoroutines<'_, 'db> { + type Result = ControlFlow<()>; + + fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'db>) -> Self::Result { + inspect_goal.goal().predicate.visit_with(self)?; + + if let Some(candidate) = inspect_goal.unique_applicable_candidate() { + candidate.visit_nested_no_probe(self) + } else { + ControlFlow::Continue(()) + } + } +} + +impl<'db> TypeVisitor> for StalledOnCoroutines<'_, 'db> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if !self.cache.insert(ty) { + return ControlFlow::Continue(()); + } + + if let TyKind::Coroutine(def_id, _) = ty.kind() + && self.stalled_coroutines.contains(&def_id.into()) + { + ControlFlow::Break(()) + } else if ty.has_coroutines() { + ty.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } + } } #[derive(Debug)] @@ -227,3 +335,10 @@ pub enum NextSolverError<'db> { Ambiguity(PredicateObligation<'db>), Overflow(PredicateObligation<'db>), } + +impl NextSolverError<'_> { + #[inline] + pub fn is_true_error(&self) -> bool { + matches!(self, NextSolverError::TrueError(_)) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs new file mode 100644 index 0000000000000..6cd9e55acf0e7 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -0,0 +1,1332 @@ +//! Trait solving error diagnosis and reporting. +//! +//! This code isn't used by rust-analyzer (it should, but then it'll probably be better to re-port it from rustc). +//! It's only there because without it, debugging trait solver errors is a nightmare. + +use std::{fmt::Debug, ops::ControlFlow}; + +use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt}; +use rustc_type_ir::{ + AliasRelationDirection, AliasTermKind, HostEffectPredicate, Interner, PredicatePolarity, + error::ExpectedFound, + inherent::{IntoKind, PlaceholderConst, SliceLike, Span as _}, + lang_items::SolverTraitLangItem, + solve::{CandidateSource, Certainty, GoalSource, MaybeCause, NoSolution}, +}; +use tracing::{instrument, trace}; + +use crate::next_solver::{ + AliasTerm, Binder, ClauseKind, Const, ConstKind, DbInterner, PolyTraitPredicate, PredicateKind, + SolverContext, SolverDefId, Span, Term, TraitPredicate, Ty, TyKind, TypeError, + fulfill::NextSolverError, + infer::{ + InferCtxt, + select::SelectionError, + traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations}, + }, + inspect::{self, ProofTreeVisitor}, + normalize::deeply_normalize_for_diagnostics, +}; + +#[derive(Debug)] +pub struct FulfillmentError<'db> { + pub obligation: PredicateObligation<'db>, + pub code: FulfillmentErrorCode<'db>, + /// Diagnostics only: the 'root' obligation which resulted in + /// the failure to process `obligation`. This is the obligation + /// that was initially passed to `register_predicate_obligation` + pub root_obligation: PredicateObligation<'db>, +} + +impl<'db> FulfillmentError<'db> { + pub fn new( + obligation: PredicateObligation<'db>, + code: FulfillmentErrorCode<'db>, + root_obligation: PredicateObligation<'db>, + ) -> FulfillmentError<'db> { + FulfillmentError { obligation, code, root_obligation } + } + + pub fn is_true_error(&self) -> bool { + match self.code { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => true, + FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { + false + } + } + } +} + +#[derive(Debug, Clone)] +pub enum FulfillmentErrorCode<'db> { + /// Inherently impossible to fulfill; this trait is implemented if and only + /// if it is already implemented. + Cycle(PredicateObligations<'db>), + Select(SelectionError<'db>), + Project(MismatchedProjectionTypes<'db>), + Subtype(ExpectedFound>, TypeError<'db>), // always comes from a SubtypePredicate + ConstEquate(ExpectedFound>, TypeError<'db>), + Ambiguity { + /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation + /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by + /// emitting a fatal error instead. + overflow: Option, + }, +} + +#[derive(Debug, Clone)] +pub struct MismatchedProjectionTypes<'db> { + pub err: TypeError<'db>, +} + +pub(super) fn fulfillment_error_for_no_solution<'db>( + infcx: &InferCtxt<'db>, + root_obligation: PredicateObligation<'db>, +) -> FulfillmentError<'db> { + let obligation = find_best_leaf_obligation(infcx, &root_obligation, false); + + let code = match obligation.predicate.kind().skip_binder() { + PredicateKind::Clause(ClauseKind::Projection(_)) => { + FulfillmentErrorCode::Project( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, expected_ty)) => { + let ct_ty = match ct.kind() { + ConstKind::Unevaluated(uv) => { + infcx.interner.type_of(uv.def).instantiate(infcx.interner, uv.args) + } + ConstKind::Param(param_ct) => param_ct.find_const_ty_from_env(obligation.param_env), + ConstKind::Value(cv) => cv.ty, + kind => panic!( + "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}" + ), + }; + FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType { + ct, + ct_ty, + expected_ty, + }) + } + PredicateKind::NormalizesTo(..) => { + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) + } + PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) + } + PredicateKind::Subtype(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(a, b); + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) + } + PredicateKind::Coerce(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(b, a); + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) + } + PredicateKind::Clause(_) | PredicateKind::DynCompatible(_) | PredicateKind::Ambiguous => { + FulfillmentErrorCode::Select(SelectionError::Unimplemented) + } + PredicateKind::ConstEquate(..) => { + panic!("unexpected goal: {obligation:?}") + } + }; + + FulfillmentError { obligation, code, root_obligation } +} + +pub(super) fn fulfillment_error_for_stalled<'db>( + infcx: &InferCtxt<'db>, + root_obligation: PredicateObligation<'db>, +) -> FulfillmentError<'db> { + let (code, refine_obligation) = infcx.probe(|_| { + match <&SolverContext<'db>>::from(infcx).evaluate_root_goal( + root_obligation.as_goal(), + Span::dummy(), + None, + ) { + Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { + (FulfillmentErrorCode::Ambiguity { overflow: None }, true) + } + Ok(GoalEvaluation { + certainty: + Certainty::Maybe(MaybeCause::Overflow { + suggest_increasing_limit, + keep_constraints: _, + }), + .. + }) => ( + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, + // Don't look into overflows because we treat overflows weirdly anyways. + // We discard the inference constraints from overflowing goals, so + // recomputing the goal again during `find_best_leaf_obligation` may apply + // inference guidance that makes other goals go from ambig -> pass, for example. + // + // FIXME: We should probably just look into overflows here. + false, + ), + Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => { + panic!( + "did not expect successful goal when collecting ambiguity errors for `{:?}`", + infcx.resolve_vars_if_possible(root_obligation.predicate), + ) + } + Err(_) => { + panic!( + "did not expect selection error when collecting ambiguity errors for `{:?}`", + infcx.resolve_vars_if_possible(root_obligation.predicate), + ) + } + } + }); + + FulfillmentError { + obligation: if refine_obligation { + find_best_leaf_obligation(infcx, &root_obligation, true) + } else { + root_obligation.clone() + }, + code, + root_obligation, + } +} + +pub(super) fn fulfillment_error_for_overflow<'db>( + infcx: &InferCtxt<'db>, + root_obligation: PredicateObligation<'db>, +) -> FulfillmentError<'db> { + FulfillmentError { + obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, + root_obligation, + } +} + +#[instrument(level = "debug", skip(infcx), ret)] +fn find_best_leaf_obligation<'db>( + infcx: &InferCtxt<'db>, + obligation: &PredicateObligation<'db>, + consider_ambiguities: bool, +) -> PredicateObligation<'db> { + let obligation = infcx.resolve_vars_if_possible(obligation.clone()); + // FIXME: we use a probe here as the `BestObligation` visitor does not + // check whether it uses candidates which get shadowed by where-bounds. + // + // We should probably fix the visitor to not do so instead, as this also + // means the leaf obligation may be incorrect. + let obligation = infcx + .fudge_inference_if_ok(|| { + infcx + .visit_proof_tree( + obligation.as_goal(), + &mut BestObligation { obligation: obligation.clone(), consider_ambiguities }, + ) + .break_value() + .ok_or(()) + }) + .unwrap_or(obligation); + deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) +} + +struct BestObligation<'db> { + obligation: PredicateObligation<'db>, + consider_ambiguities: bool, +} + +impl<'db> BestObligation<'db> { + fn with_derived_obligation( + &mut self, + derived_obligation: PredicateObligation<'db>, + and_then: impl FnOnce(&mut Self) -> >::Result, + ) -> >::Result { + let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); + let res = and_then(self); + self.obligation = old_obligation; + res + } + + /// Filter out the candidates that aren't interesting to visit for the + /// purposes of reporting errors. For ambiguities, we only consider + /// candidates that may hold. For errors, we only consider candidates that + /// *don't* hold and which have impl-where clauses that also don't hold. + fn non_trivial_candidates<'a>( + &self, + goal: &'a inspect::InspectGoal<'a, 'db>, + ) -> Vec> { + let mut candidates = goal.candidates(); + match self.consider_ambiguities { + true => { + // If we have an ambiguous obligation, we must consider *all* candidates + // that hold, or else we may guide inference causing other goals to go + // from ambig -> pass/fail. + candidates.retain(|candidate| candidate.result().is_ok()); + } + false => { + // We always handle rigid alias candidates separately as we may not add them for + // aliases whose trait bound doesn't hold. + candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. })); + // If we have >1 candidate, one may still be due to "boring" reasons, like + // an alias-relate that failed to hold when deeply evaluated. We really + // don't care about reasons like this. + if candidates.len() > 1 { + candidates.retain(|candidate| { + goal.infcx().probe(|_| { + candidate.instantiate_nested_goals().iter().any(|nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition + | GoalSource::InstantiateHigherRanked + | GoalSource::AliasWellFormed + ) && nested_goal.result().is_err() + }) + }) + }); + } + } + } + + candidates + } + + /// HACK: We walk the nested obligations for a well-formed arg manually, + /// since there's nontrivial logic in `wf.rs` to set up an obligation cause. + /// Ideally we'd be able to track this better. + fn visit_well_formed_goal( + &mut self, + candidate: &inspect::InspectCandidate<'_, 'db>, + term: Term<'db>, + ) -> ControlFlow> { + let infcx = candidate.goal().infcx(); + let param_env = candidate.goal().goal().param_env; + + for obligation in wf::unnormalized_obligations(infcx, param_env, term).into_iter().flatten() + { + let nested_goal = candidate + .instantiate_proof_tree_for_nested_goal(GoalSource::Misc, obligation.as_goal()); + // Skip nested goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, nested_goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => continue, + } + + self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; + } + + ControlFlow::Break(self.obligation.clone()) + } + + /// If a normalization of an associated item or a trait goal fails without trying any + /// candidates it's likely that normalizing its self type failed. We manually detect + /// such cases here. + fn detect_error_in_self_ty_normalization( + &mut self, + goal: &inspect::InspectGoal<'_, 'db>, + self_ty: Ty<'db>, + ) -> ControlFlow> { + assert!(!self.consider_ambiguities); + let interner = goal.infcx().interner; + if let TyKind::Alias(..) = self_ty.kind() { + let infer_term = goal.infcx().next_ty_var(); + let pred = PredicateKind::AliasRelate( + self_ty.into(), + infer_term.into(), + AliasRelationDirection::Equate, + ); + let obligation = Obligation::new( + interner, + self.obligation.cause.clone(), + goal.goal().param_env, + pred, + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(interner, pred), + goal.depth() + 1, + this, + ) + }) + } else { + ControlFlow::Continue(()) + } + } + + /// When a higher-ranked projection goal fails, check that the corresponding + /// higher-ranked trait goal holds or not. This is because the process of + /// instantiating and then re-canonicalizing the binder of the projection goal + /// forces us to be unable to see that the leak check failed in the nested + /// `NormalizesTo` goal, so we don't fall back to the rigid projection check + /// that should catch when a projection goal fails due to an unsatisfied trait + /// goal. + fn detect_trait_error_in_higher_ranked_projection( + &mut self, + goal: &inspect::InspectGoal<'_, 'db>, + ) -> ControlFlow> { + let interner = goal.infcx().interner; + if let Some(projection_clause) = goal.goal().predicate.as_projection_clause() + && !projection_clause.bound_vars().is_empty() + { + let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(interner)); + let obligation = Obligation::new( + interner, + self.obligation.cause.clone(), + goal.goal().param_env, + deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred), + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(interner, pred), + goal.depth() + 1, + this, + ) + }) + } else { + ControlFlow::Continue(()) + } + } + + /// It is likely that `NormalizesTo` failed without any applicable candidates + /// because the alias is not well-formed. + /// + /// As we only enter `RigidAlias` candidates if the trait bound of the associated type + /// holds, we discard these candidates in `non_trivial_candidates` and always manually + /// check this here. + fn detect_non_well_formed_assoc_item( + &mut self, + goal: &inspect::InspectGoal<'_, 'db>, + alias: AliasTerm<'db>, + ) -> ControlFlow> { + let interner = goal.infcx().interner; + let obligation = Obligation::new( + interner, + self.obligation.cause.clone(), + goal.goal().param_env, + alias.trait_ref(interner), + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(interner, alias.trait_ref(interner)), + goal.depth() + 1, + this, + ) + }) + } + + /// If we have no candidates, then it's likely that there is a + /// non-well-formed alias in the goal. + fn detect_error_from_empty_candidates( + &mut self, + goal: &inspect::InspectGoal<'_, 'db>, + ) -> ControlFlow> { + let interner = goal.infcx().interner; + let pred_kind = goal.goal().predicate.kind(); + + match pred_kind.no_bound_vars() { + Some(PredicateKind::Clause(ClauseKind::Trait(pred))) => { + self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?; + } + Some(PredicateKind::NormalizesTo(pred)) => { + if let AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst = + pred.alias.kind(interner) + { + self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?; + self.detect_non_well_formed_assoc_item(goal, pred.alias)?; + } + } + Some(_) | None => {} + } + + ControlFlow::Break(self.obligation.clone()) + } +} + +impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { + type Result = ControlFlow>; + + #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))] + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'db>) -> Self::Result { + let interner = goal.infcx().interner; + // Skip goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => return ControlFlow::Continue(()), + } + + let pred = goal.goal().predicate; + + let candidates = self.non_trivial_candidates(goal); + let candidate = match candidates.as_slice() { + [candidate] => candidate, + [] => return self.detect_error_from_empty_candidates(goal), + _ => return ControlFlow::Break(self.obligation.clone()), + }; + + // // Don't walk into impls that have `do_not_recommend`. + // if let inspect::ProbeKind::TraitCandidate { + // source: CandidateSource::Impl(impl_def_id), + // result: _, + // } = candidate.kind() + // && interner.do_not_recommend_impl(impl_def_id) + // { + // trace!("#[do_not_recommend] -> exit"); + // return ControlFlow::Break(self.obligation.clone()); + // } + + // FIXME: Also, what about considering >1 layer up the stack? May be necessary + // for normalizes-to. + let child_mode = match pred.kind().skip_binder() { + PredicateKind::Clause(ClauseKind::Trait(trait_pred)) => { + ChildMode::Trait(pred.kind().rebind(trait_pred)) + } + PredicateKind::Clause(ClauseKind::HostEffect(host_pred)) => { + ChildMode::Host(pred.kind().rebind(host_pred)) + } + PredicateKind::NormalizesTo(normalizes_to) + if matches!( + normalizes_to.alias.kind(interner), + AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst + ) => + { + ChildMode::Trait(pred.kind().rebind(TraitPredicate { + trait_ref: normalizes_to.alias.trait_ref(interner), + polarity: PredicatePolarity::Positive, + })) + } + PredicateKind::Clause(ClauseKind::WellFormed(term)) => { + return self.visit_well_formed_goal(candidate, term); + } + _ => ChildMode::PassThrough, + }; + + let nested_goals = candidate.instantiate_nested_goals(); + + // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as + // an actual candidate, instead we should treat them as if the impl was never considered to + // have potentially applied. As if `impl Trait for for<..> fn(..A) -> R` was written + // instead of `impl Trait for T`. + // + // We do this as a separate loop so that we do not choose to tell the user about some nested + // goal before we encounter a `T: FnPtr` nested goal. + for nested_goal in &nested_goals { + if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() + && interner + .is_trait_lang_item(poly_trait_pred.def_id(), SolverTraitLangItem::FnPtrTrait) + && let Err(NoSolution) = nested_goal.result() + { + return ControlFlow::Break(self.obligation.clone()); + } + } + + let mut impl_where_bound_count = 0; + for nested_goal in nested_goals { + trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); + + let nested_pred = nested_goal.goal().predicate; + + let make_obligation = || Obligation { + cause: ObligationCause::dummy(), + param_env: nested_goal.goal().param_env, + predicate: nested_pred, + recursion_depth: self.obligation.recursion_depth + 1, + }; + + let obligation; + match (child_mode, nested_goal.source()) { + ( + ChildMode::Trait(_) | ChildMode::Host(_), + GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), + ) => { + continue; + } + (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { + obligation = make_obligation(); + impl_where_bound_count += 1; + } + ( + ChildMode::Host(parent_host_pred), + GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition, + ) => { + obligation = make_obligation(); + impl_where_bound_count += 1; + } + // Skip over a higher-ranked predicate. + (_, GoalSource::InstantiateHigherRanked) => { + obligation = self.obligation.clone(); + } + (ChildMode::PassThrough, _) + | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => { + obligation = make_obligation(); + } + } + + self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; + } + + // alias-relate may fail because the lhs or rhs can't be normalized, + // and therefore is treated as rigid. + if let Some(PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(interner, ClauseKind::WellFormed(lhs)), + goal.depth() + 1, + self, + )?; + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(interner, ClauseKind::WellFormed(rhs)), + goal.depth() + 1, + self, + )?; + } + + self.detect_trait_error_in_higher_ranked_projection(goal)?; + + ControlFlow::Break(self.obligation.clone()) + } +} + +#[derive(Debug, Copy, Clone)] +enum ChildMode<'db> { + // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, + // and skip all `GoalSource::Misc`, which represent useless obligations + // such as alias-eq which may not hold. + Trait(PolyTraitPredicate<'db>), + // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, + // and skip all `GoalSource::Misc`, which represent useless obligations + // such as alias-eq which may not hold. + Host(Binder<'db, HostEffectPredicate>>), + // Skip trying to derive an `ObligationCause` from this obligation, and + // report *all* sub-obligations as if they came directly from the parent + // obligation. + PassThrough, +} + +impl<'db> NextSolverError<'db> { + pub fn to_debuggable_error(&self, infcx: &InferCtxt<'db>) -> FulfillmentError<'db> { + match self { + NextSolverError::TrueError(obligation) => { + fulfillment_error_for_no_solution(infcx, obligation.clone()) + } + NextSolverError::Ambiguity(obligation) => { + fulfillment_error_for_stalled(infcx, obligation.clone()) + } + NextSolverError::Overflow(obligation) => { + fulfillment_error_for_overflow(infcx, obligation.clone()) + } + } + } +} + +mod wf { + use std::iter; + + use hir_def::ItemContainerId; + use rustc_type_ir::inherent::{ + AdtDef, BoundExistentialPredicates, GenericArg, GenericArgs as _, IntoKind, SliceLike, + Term as _, Ty as _, + }; + use rustc_type_ir::lang_items::SolverTraitLangItem; + use rustc_type_ir::{ + Interner, PredicatePolarity, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, + }; + use tracing::{debug, instrument, trace}; + + use crate::next_solver::infer::InferCtxt; + use crate::next_solver::infer::traits::{ + Obligation, ObligationCause, PredicateObligation, PredicateObligations, + }; + use crate::next_solver::{ + AliasTerm, Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, + GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitPredicate, + TraitRef, Ty, TyKind, + }; + + /// Compute the predicates that are required for a type to be well-formed. + /// + /// This is only intended to be used in the new solver, since it does not + /// take into account recursion depth or proper error-reporting spans. + pub fn unnormalized_obligations<'db>( + infcx: &InferCtxt<'db>, + param_env: ParamEnv<'db>, + term: Term<'db>, + ) -> Option> { + debug_assert_eq!(term, infcx.resolve_vars_if_possible(term)); + + // However, if `arg` IS an unresolved inference variable, returns `None`, + // because we are not able to make any progress at all. This is to prevent + // cycles where we say "?0 is WF if ?0 is WF". + if term.is_infer() { + return None; + } + + let mut wf = + WfPredicates { infcx, param_env, out: PredicateObligations::new(), recursion_depth: 0 }; + wf.add_wf_preds_for_term(term); + Some(wf.out) + } + + struct WfPredicates<'a, 'db> { + infcx: &'a InferCtxt<'db>, + param_env: ParamEnv<'db>, + out: PredicateObligations<'db>, + recursion_depth: usize, + } + + /// Controls whether we "elaborate" supertraits and so forth on the WF + /// predicates. This is a kind of hack to address #43784. The + /// underlying problem in that issue was a trait structure like: + /// + /// ```ignore (illustrative) + /// trait Foo: Copy { } + /// trait Bar: Foo { } + /// impl Foo for T { } + /// impl Bar for T { } + /// ``` + /// + /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but + /// we decide that this is true because `T: Bar` is in the + /// where-clauses (and we can elaborate that to include `T: + /// Copy`). This wouldn't be a problem, except that when we check the + /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` + /// impl. And so nowhere did we check that `T: Copy` holds! + /// + /// To resolve this, we elaborate the WF requirements that must be + /// proven when checking impls. This means that (e.g.) the `impl Bar + /// for T` will be forced to prove not only that `T: Foo` but also `T: + /// Copy` (which it won't be able to do, because there is no `Copy` + /// impl for `T`). + #[derive(Debug, PartialEq, Eq, Copy, Clone)] + enum Elaborate { + All, + None, + } + + impl<'a, 'db> WfPredicates<'a, 'db> { + fn interner(&self) -> DbInterner<'db> { + self.infcx.interner + } + + /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. + fn add_wf_preds_for_trait_pred( + &mut self, + trait_pred: TraitPredicate<'db>, + elaborate: Elaborate, + ) { + let tcx = self.interner(); + let trait_ref = trait_pred.trait_ref; + + // Negative trait predicates don't require supertraits to hold, just + // that their args are WF. + if trait_pred.polarity == PredicatePolarity::Negative { + self.add_wf_preds_for_negative_trait_pred(trait_ref); + return; + } + + // if the trait predicate is not const, the wf obligations should not be const as well. + let obligations = self.nominal_obligations(trait_ref.def_id.0.into(), trait_ref.args); + + debug!("compute_trait_pred obligations {:?}", obligations); + let param_env = self.param_env; + let depth = self.recursion_depth; + + let extend = |PredicateObligation { predicate, mut cause, .. }| { + Obligation::with_depth(tcx, cause, depth, param_env, predicate) + }; + + if let Elaborate::All = elaborate { + let implied_obligations = rustc_type_ir::elaborate::elaborate(tcx, obligations); + let implied_obligations = implied_obligations.map(extend); + self.out.extend(implied_obligations); + } else { + self.out.extend(obligations); + } + + self.out.extend( + trait_ref + .args + .iter() + .enumerate() + .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t))) + .filter(|(_, term)| !term.has_escaping_bound_vars()) + .map(|(i, term)| { + let mut cause = ObligationCause::misc(); + // The first arg is the self ty - use the correct span for it. + Obligation::with_depth( + tcx, + cause, + depth, + param_env, + ClauseKind::WellFormed(term), + ) + }), + ); + } + + // Compute the obligations that are required for `trait_ref` to be WF, + // given that it is a *negative* trait predicate. + fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: TraitRef<'db>) { + for arg in trait_ref.args { + if let Some(term) = arg.as_term() { + self.add_wf_preds_for_term(term); + } + } + } + + /// Pushes the obligations required for an alias (except inherent) to be WF + /// into `self.out`. + fn add_wf_preds_for_alias_term(&mut self, data: AliasTerm<'db>) { + // A projection is well-formed if + // + // (a) its predicates hold (*) + // (b) its args are wf + // + // (*) The predicates of an associated type include the predicates of + // the trait that it's contained in. For example, given + // + // trait A: Clone { + // type X where T: Copy; + // } + // + // The predicates of `<() as A>::X` are: + // [ + // `(): Sized` + // `(): Clone` + // `(): A` + // `i32: Sized` + // `i32: Clone` + // `i32: Copy` + // ] + let obligations = self.nominal_obligations(data.def_id, data.args); + self.out.extend(obligations); + + self.add_wf_preds_for_projection_args(data.args); + } + + fn add_wf_preds_for_projection_args(&mut self, args: GenericArgs<'db>) { + let tcx = self.interner(); + let cause = ObligationCause::new(); + let param_env = self.param_env; + let depth = self.recursion_depth; + + self.out.extend( + args.iter() + .filter_map(|arg| arg.as_term()) + .filter(|term| !term.has_escaping_bound_vars()) + .map(|term| { + Obligation::with_depth( + tcx, + cause.clone(), + depth, + param_env, + ClauseKind::WellFormed(term), + ) + }), + ); + } + + fn require_sized(&mut self, subty: Ty<'db>) { + if !subty.has_escaping_bound_vars() { + let cause = ObligationCause::new(); + let trait_ref = TraitRef::new( + self.interner(), + self.interner().require_trait_lang_item(SolverTraitLangItem::Sized), + [subty], + ); + self.out.push(Obligation::with_depth( + self.interner(), + cause, + self.recursion_depth, + self.param_env, + Binder::dummy(trait_ref), + )); + } + } + + /// Pushes all the predicates needed to validate that `term` is WF into `out`. + #[instrument(level = "debug", skip(self))] + fn add_wf_preds_for_term(&mut self, term: Term<'db>) { + term.visit_with(self); + debug!(?self.out); + } + + #[instrument(level = "debug", skip(self))] + fn nominal_obligations( + &mut self, + def_id: SolverDefId, + args: GenericArgs<'db>, + ) -> PredicateObligations<'db> { + // PERF: `Sized`'s predicates include `MetaSized`, but both are compiler implemented marker + // traits, so `MetaSized` will always be WF if `Sized` is WF and vice-versa. Determining + // the nominal obligations of `Sized` would in-effect just elaborate `MetaSized` and make + // the compiler do a bunch of work needlessly. + if let SolverDefId::TraitId(def_id) = def_id + && self.interner().is_trait_lang_item(def_id.into(), SolverTraitLangItem::Sized) + { + return Default::default(); + } + + self.interner() + .predicates_of(def_id) + .iter_instantiated(self.interner(), args) + .map(|pred| { + let cause = ObligationCause::new(); + Obligation::with_depth( + self.interner(), + cause, + self.recursion_depth, + self.param_env, + pred, + ) + }) + .filter(|pred| !pred.has_escaping_bound_vars()) + .collect() + } + + fn add_wf_preds_for_dyn_ty( + &mut self, + ty: Ty<'db>, + data: &[Binder<'db, ExistentialPredicate<'db>>], + region: Region<'db>, + ) { + // Imagine a type like this: + // + // trait Foo { } + // trait Bar<'c> : 'c { } + // + // &'b (Foo+'c+Bar<'d>) + // ^ + // + // In this case, the following relationships must hold: + // + // 'b <= 'c + // 'd <= 'c + // + // The first conditions is due to the normal region pointer + // rules, which say that a reference cannot outlive its + // referent. + // + // The final condition may be a bit surprising. In particular, + // you may expect that it would have been `'c <= 'd`, since + // usually lifetimes of outer things are conservative + // approximations for inner things. However, it works somewhat + // differently with trait objects: here the idea is that if the + // user specifies a region bound (`'c`, in this case) it is the + // "master bound" that *implies* that bounds from other traits are + // all met. (Remember that *all bounds* in a type like + // `Foo+Bar+Zed` must be met, not just one, hence if we write + // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and + // 'y.) + // + // Note: in fact we only permit builtin traits, not `Bar<'d>`, I + // am looking forward to the future here. + if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { + let implicit_bounds = object_region_bounds(self.interner(), data); + + let explicit_bound = region; + + self.out.reserve(implicit_bounds.len()); + for implicit_bound in implicit_bounds { + let cause = ObligationCause::new(); + let outlives = Binder::dummy(rustc_type_ir::OutlivesPredicate( + explicit_bound, + implicit_bound, + )); + self.out.push(Obligation::with_depth( + self.interner(), + cause, + self.recursion_depth, + self.param_env, + outlives, + )); + } + + // We don't add any wf predicates corresponding to the trait ref's generic arguments + // which allows code like this to compile: + // ```rust + // trait Trait {} + // fn foo(_: &dyn Trait<[u32]>) {} + // ``` + } + } + } + + impl<'a, 'db> TypeVisitor> for WfPredicates<'a, 'db> { + type Result = (); + + fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result { + debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); + + let tcx = self.interner(); + + match t.kind() { + TyKind::Bool + | TyKind::Char + | TyKind::Int(..) + | TyKind::Uint(..) + | TyKind::Float(..) + | TyKind::Error(_) + | TyKind::Str + | TyKind::CoroutineWitness(..) + | TyKind::Never + | TyKind::Param(_) + | TyKind::Bound(..) + | TyKind::Placeholder(..) + | TyKind::Foreign(..) => { + // WfScalar, WfParameter, etc + } + + // Can only infer to `TyKind::Int(_) | TyKind::Uint(_)`. + TyKind::Infer(rustc_type_ir::IntVar(_)) => {} + + // Can only infer to `TyKind::Float(_)`. + TyKind::Infer(rustc_type_ir::FloatVar(_)) => {} + + TyKind::Slice(subty) => { + self.require_sized(subty); + } + + TyKind::Array(subty, len) => { + self.require_sized(subty); + // Note that the len being WF is implicitly checked while visiting. + // Here we just check that it's of type usize. + let cause = ObligationCause::new(); + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + Binder::dummy(PredicateKind::Clause(ClauseKind::ConstArgHasType( + len, + Ty::new_unit(self.interner()), + ))), + )); + } + + TyKind::Pat(base_ty, pat) => { + self.require_sized(base_ty); + } + + TyKind::Tuple(tys) => { + if let Some((_last, rest)) = tys.split_last() { + for &elem in rest { + self.require_sized(elem); + } + } + } + + TyKind::RawPtr(_, _) => { + // Simple cases that are WF if their type args are WF. + } + + TyKind::Alias( + rustc_type_ir::Projection | rustc_type_ir::Opaque | rustc_type_ir::Free, + data, + ) => { + let obligations = self.nominal_obligations(data.def_id, data.args); + self.out.extend(obligations); + } + TyKind::Alias(rustc_type_ir::Inherent, data) => { + return; + } + + TyKind::Adt(def, args) => { + // WfNominalType + let obligations = self.nominal_obligations(def.def_id().0.into(), args); + self.out.extend(obligations); + } + + TyKind::FnDef(did, args) => { + // HACK: Check the return type of function definitions for + // well-formedness to mostly fix #84533. This is still not + // perfect and there may be ways to abuse the fact that we + // ignore requirements with escaping bound vars. That's a + // more general issue however. + let fn_sig = tcx.fn_sig(did).instantiate(tcx, args); + fn_sig.output().skip_binder().visit_with(self); + + let did = match did.0 { + hir_def::CallableDefId::FunctionId(id) => id.into(), + hir_def::CallableDefId::StructId(id) => SolverDefId::Ctor(Ctor::Struct(id)), + hir_def::CallableDefId::EnumVariantId(id) => { + SolverDefId::Ctor(Ctor::Enum(id)) + } + }; + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + } + + TyKind::Ref(r, rty, _) => { + // WfReference + if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { + let cause = ObligationCause::new(); + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives( + rustc_type_ir::OutlivesPredicate(rty, r), + ))), + )); + } + } + + TyKind::Coroutine(did, args, ..) => { + // Walk ALL the types in the coroutine: this will + // include the upvar types as well as the yield + // type. Note that this is mildly distinct from + // the closure case, where we have to be careful + // about the signature of the closure. We don't + // have the problem of implied bounds here since + // coroutines don't take arguments. + let obligations = self.nominal_obligations(did.0.into(), args); + self.out.extend(obligations); + } + + TyKind::Closure(did, args) => { + // Note that we cannot skip the generic types + // types. Normally, within the fn + // body where they are created, the generics will + // always be WF, and outside of that fn body we + // are not directly inspecting closure types + // anyway, except via auto trait matching (which + // only inspects the upvar types). + // But when a closure is part of a type-alias-impl-trait + // then the function that created the defining site may + // have had more bounds available than the type alias + // specifies. This may cause us to have a closure in the + // hidden type that is not actually well formed and + // can cause compiler crashes when the user abuses unsafe + // code to procure such a closure. + // See tests/ui/type-alias-impl-trait/wf_check_closures.rs + let obligations = self.nominal_obligations(did.0.into(), args); + self.out.extend(obligations); + // Only check the upvar types for WF, not the rest + // of the types within. This is needed because we + // capture the signature and it may not be WF + // without the implied bounds. Consider a closure + // like `|x: &'a T|` -- it may be that `T: 'a` is + // not known to hold in the creator's context (and + // indeed the closure may not be invoked by its + // creator, but rather turned to someone who *can* + // verify that). + // + // The special treatment of closures here really + // ought not to be necessary either; the problem + // is related to #25860 -- there is no way for us + // to express a fn type complete with the implied + // bounds that it is assuming. I think in reality + // the WF rules around fn are a bit messed up, and + // that is the rot problem: `fn(&'a T)` should + // probably always be WF, because it should be + // shorthand for something like `where(T: 'a) { + // fn(&'a T) }`, as discussed in #25860. + let upvars = args.as_closure().tupled_upvars_ty(); + return upvars.visit_with(self); + } + + TyKind::CoroutineClosure(did, args) => { + // See the above comments. The same apply to coroutine-closures. + let obligations = self.nominal_obligations(did.0.into(), args); + self.out.extend(obligations); + let upvars = args.as_coroutine_closure().tupled_upvars_ty(); + return upvars.visit_with(self); + } + + TyKind::FnPtr(..) => { + // Let the visitor iterate into the argument/return + // types appearing in the fn signature. + } + TyKind::UnsafeBinder(ty) => {} + + TyKind::Dynamic(data, r, _) => { + // WfObject + // + // Here, we defer WF checking due to higher-ranked + // regions. This is perhaps not ideal. + self.add_wf_preds_for_dyn_ty(t, data.as_slice(), r); + + // FIXME(#27579) RFC also considers adding trait + // obligations that don't refer to Self and + // checking those + if let Some(principal) = data.principal_def_id() { + self.out.push(Obligation::with_depth( + tcx, + ObligationCause::new(), + self.recursion_depth, + self.param_env, + Binder::dummy(PredicateKind::DynCompatible(principal)), + )); + } + } + + // Inference variables are the complicated case, since we don't + // know what type they are. We do two things: + // + // 1. Check if they have been resolved, and if so proceed with + // THAT type. + // 2. If not, we've at least simplified things (e.g., we went + // from `Vec?0>: WF` to `?0: WF`), so we can + // register a pending obligation and keep + // moving. (Goal is that an "inductive hypothesis" + // is satisfied to ensure termination.) + // See also the comment on `fn obligations`, describing cycle + // prevention, which happens before this can be reached. + TyKind::Infer(_) => { + let cause = ObligationCause::new(); + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(t.into()))), + )); + } + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: Const<'db>) -> Self::Result { + let tcx = self.interner(); + + match c.kind() { + ConstKind::Unevaluated(uv) => { + if !c.has_escaping_bound_vars() { + let predicate = + Binder::dummy(PredicateKind::Clause(ClauseKind::ConstEvaluatable(c))); + let cause = ObligationCause::new(); + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + + if let SolverDefId::ConstId(uv_def) = uv.def + && let ItemContainerId::ImplId(impl_) = + uv_def.loc(self.interner().db).container + && self.interner().db.impl_signature(impl_).target_trait.is_none() + { + return; // Subtree is handled by above function + } else { + let obligations = self.nominal_obligations(uv.def, uv.args); + self.out.extend(obligations); + } + } + } + ConstKind::Infer(_) => { + let cause = ObligationCause::new(); + + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(c.into()))), + )); + } + ConstKind::Expr(_) => { + // FIXME(generic_const_exprs): this doesn't verify that given `Expr(N + 1)` the + // trait bound `typeof(N): Add` holds. This is currently unnecessary + // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` + // which means that the `DefId` would have been typeck'd elsewhere. However in + // the future we may allow directly lowering to `ConstKind::Expr` in which case + // we would not be proving bounds we should. + + let predicate = + Binder::dummy(PredicateKind::Clause(ClauseKind::ConstEvaluatable(c))); + let cause = ObligationCause::new(); + self.out.push(Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } + + ConstKind::Error(_) + | ConstKind::Param(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(..) => { + // These variants are trivially WF, so nothing to do here. + } + ConstKind::Value(..) => { + // FIXME: Enforce that values are structurally-matchable. + } + } + + c.super_visit_with(self) + } + + fn visit_predicate(&mut self, _p: Predicate<'db>) -> Self::Result { + panic!("predicate should not be checked for well-formedness"); + } + } + + /// Given an object type like `SomeTrait + Send`, computes the lifetime + /// bounds that must hold on the elided self type. These are derived + /// from the declarations of `SomeTrait`, `Send`, and friends -- if + /// they declare `trait SomeTrait : 'static`, for example, then + /// `'static` would appear in the list. + /// + /// N.B., in some cases, particularly around higher-ranked bounds, + /// this function returns a kind of conservative approximation. + /// That is, all regions returned by this function are definitely + /// required, but there may be other region bounds that are not + /// returned, as well as requirements like `for<'a> T: 'a`. + /// + /// Requires that trait definitions have been processed so that we can + /// elaborate predicates and walk supertraits. + pub fn object_region_bounds<'db>( + interner: DbInterner<'db>, + existential_predicates: &[Binder<'db, ExistentialPredicate<'db>>], + ) -> Vec> { + let erased_self_ty = Ty::new_unit(interner); + + let predicates = existential_predicates + .iter() + .map(|predicate| predicate.with_self_ty(interner, erased_self_ty)); + + rustc_type_ir::elaborate::elaborate(interner, predicates) + .filter_map(|pred| { + debug!(?pred); + match pred.kind().skip_binder() { + ClauseKind::TypeOutlives(rustc_type_ir::OutlivesPredicate(ref t, ref r)) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == &erased_self_ty && !r.has_escaping_bound_vars() { + Some(*r) + } else { + None + } + } + ClauseKind::Trait(_) + | ClauseKind::HostEffect(..) + | ClauseKind::RegionOutlives(_) + | ClauseKind::Projection(_) + | ClauseKind::ConstArgHasType(_, _) + | ClauseKind::WellFormed(_) + | ClauseKind::UnstableFeature(_) + | ClauseKind::ConstEvaluatable(_) => None, + } + }) + .collect() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 4e124d07d2b38..097bb85cbd491 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -6,12 +6,15 @@ use rustc_type_ir::{ ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable, Variance, - inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _}, + inherent::{ + GenericArg as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _, + }, relate::{Relate, VarianceDiagInfo}, }; use smallvec::SmallVec; use crate::db::HirDatabase; +use crate::next_solver::{Binder, PolyFnSig}; use super::{ Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys, @@ -240,6 +243,34 @@ impl<'db> GenericArgs<'db> { args.push(kind); } } + + pub fn closure_sig_untupled(self) -> PolyFnSig<'db> { + let TyKind::FnPtr(inputs_and_output, hdr) = + self.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.kind() + else { + unreachable!("not a function pointer") + }; + inputs_and_output.with(hdr) + } + + /// A "sensible" `.split_closure_args()`, where the arguments are not in a tuple. + pub fn split_closure_args_untupled(self) -> rustc_type_ir::ClosureArgsParts> { + // FIXME: should use `ClosureSubst` when possible + match self.inner().as_slice() { + [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => { + let interner = DbInterner::conjure(); + rustc_type_ir::ClosureArgsParts { + parent_args: GenericArgs::new_from_iter(interner, parent_args.iter().cloned()), + closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(), + closure_kind_ty: closure_kind_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } + _ => { + unreachable!("unexpected closure sig"); + } + } + } } impl<'db> rustc_type_ir::relate::Relate> for GenericArgs<'db> { @@ -329,7 +360,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< fn split_closure_args(self) -> rustc_type_ir::ClosureArgsParts> { // FIXME: should use `ClosureSubst` when possible match self.inner().as_slice() { - [parent_args @ .., sig_ty] => { + [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => { let interner = DbInterner::conjure(); // This is stupid, but the next solver expects the first input to actually be a tuple let sig_ty = match sig_ty.expect_ty().kind() { @@ -354,8 +385,8 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< rustc_type_ir::ClosureArgsParts { parent_args: GenericArgs::new_from_iter(interner, parent_args.iter().cloned()), closure_sig_as_fn_ptr_ty: sig_ty, - closure_kind_ty: Ty::new(interner, TyKind::Int(IntTy::I8)), - tupled_upvars_ty: Ty::new_unit(interner), + closure_kind_ty: closure_kind_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), } } _ => { @@ -392,14 +423,14 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< fn split_coroutine_args(self) -> rustc_type_ir::CoroutineArgsParts> { let interner = DbInterner::conjure(); match self.inner().as_slice() { - [parent_args @ .., resume_ty, yield_ty, return_ty] => { + [parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => { rustc_type_ir::CoroutineArgsParts { parent_args: GenericArgs::new_from_iter(interner, parent_args.iter().cloned()), - kind_ty: Ty::new_unit(interner), + kind_ty: kind_ty.expect_ty(), resume_ty: resume_ty.expect_ty(), yield_ty: yield_ty.expect_ty(), return_ty: return_ty.expect_ty(), - tupled_upvars_ty: Ty::new_unit(interner), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), } } _ => panic!("GenericArgs were likely not for a Coroutine."), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs index d64c7ed626eb2..8dfffe0d365e7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs @@ -26,7 +26,7 @@ //! things. (That system should probably be refactored.) use rustc_type_ir::{ - FnSig, GenericArgKind, TypingMode, Variance, + FnSig, GenericArgKind, TypeFoldable, TypingMode, Variance, error::ExpectedFound, inherent::{IntoKind, Span as _}, relate::{Relate, TypeRelation, solver_relating::RelateExt}, @@ -36,6 +36,8 @@ use crate::next_solver::{ AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term, TraitRef, Ty, + fulfill::{FulfillmentCtxt, NextSolverError}, + infer::relate::lattice::{LatticeOp, LatticeOpKind}, }; use super::{ @@ -210,6 +212,34 @@ impl<'a, 'db> At<'a, 'db> { } } + /// Deeply normalizes `value`, replacing all aliases which can by normalized in + /// the current environment. This errors in case normalization fails or is ambiguous. + pub fn deeply_normalize(self, value: T) -> Result>> + where + T: TypeFoldable>, + { + crate::next_solver::normalize::deeply_normalize(self, value) + } + + /// Computes the least-upper-bound, or mutual supertype, of two + /// values. The order of the arguments doesn't matter, but since + /// this can result in an error (e.g., if asked to compute LUB of + /// u32 and i32), it is meaningful to call one of them the + /// "expected type". + pub fn lub(self, expected: T, actual: T) -> InferResult<'db, T> + where + T: ToTrace<'db>, + { + let mut op = LatticeOp::new( + self.infcx, + ToTrace::to_trace(self.cause, expected, actual), + self.param_env, + LatticeOpKind::Lub, + ); + let value = op.relate(expected, actual)?; + Ok(InferOk { value, obligations: op.into_obligations() }) + } + fn goals_to_obligations(&self, goals: Vec>>) -> InferOk<'db, ()> { InferOk { value: (), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index ce6c941287325..8e922abacb206 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -2,6 +2,7 @@ use std::cell::{Cell, RefCell}; use std::fmt; +use std::ops::Range; use std::sync::Arc; pub use BoundRegionConversionTime::*; @@ -55,6 +56,7 @@ mod opaque_types; pub mod region_constraints; pub mod relate; pub mod resolve; +pub(crate) mod select; pub(crate) mod snapshot; pub(crate) mod traits; mod type_variable; @@ -81,6 +83,10 @@ pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable< ut::InPlace, &'a mut InferCtxtUndoLogs<'db>>, >; +fn iter_idx_range + Into>(range: Range) -> impl Iterator { + (range.start.into()..range.end.into()).map(Into::into) +} + /// This type contains all the things within `InferCtxt` that sit within a /// `RefCell` and are involved with taking/rolling back snapshots. Snapshot /// operations are hot enough that we want only one call to `borrow_mut` per diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs index 50549694c3f23..7f15a467b3e87 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs @@ -22,7 +22,7 @@ use crate::next_solver::{ AliasTy, Binder, DbInterner, OpaqueTypeKey, ParamTy, PlaceholderTy, Region, Ty, }; -#[derive(Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct RegionConstraintStorage<'db> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. pub(super) var_infos: IndexVec, @@ -239,7 +239,7 @@ pub struct VerifyIfEq<'db> { pub bound: Region<'db>, } -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct TwoRegions<'db> { a: Region<'db>, b: Region<'db>, @@ -458,6 +458,44 @@ impl<'db> RegionConstraintCollector<'db, '_> { } } + pub(super) fn lub_regions( + &mut self, + db: DbInterner<'db>, + a: Region<'db>, + b: Region<'db>, + ) -> Region<'db> { + // cannot add constraints once regions are resolved + debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b); + #[expect(clippy::if_same_then_else)] + if a.is_static() || b.is_static() { + a // nothing lives longer than static + } else if a == b { + a // LUB(a,a) = a + } else { + self.combine_vars(db, Lub, a, b) + } + } + + pub(super) fn glb_regions( + &mut self, + db: DbInterner<'db>, + a: Region<'db>, + b: Region<'db>, + ) -> Region<'db> { + // cannot add constraints once regions are resolved + debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b); + #[expect(clippy::if_same_then_else)] + if a.is_static() { + b // static lives longer than everything else + } else if b.is_static() { + a // static lives longer than everything else + } else if a == b { + a // GLB(a,a) = a + } else { + self.combine_vars(db, Glb, a, b) + } + } + /// Resolves a region var to its value in the unification table, if it exists. /// Otherwise, it is resolved to the root `ReVar` in the table. pub fn opportunistic_resolve_var( @@ -531,6 +569,17 @@ impl<'db> RegionConstraintCollector<'db, '_> { } } + pub fn vars_since_snapshot(&self, value_count: usize) -> Range { + RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()) + } + + /// See `InferCtxt::region_constraints_added_in_snapshot`. + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot) -> bool { + self.undo_log + .region_constraints_in_snapshot(mark) + .any(|elt| matches!(elt, AddConstraint(_))) + } + #[inline] fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'db, RegionVidKey<'db>> { ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs index de336c69b3180..7e2735db3b77a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs @@ -350,7 +350,7 @@ impl<'db> Generalizer<'_, 'db> { // with inference variables can cause incorrect ambiguity. // // cc trait-system-refactor-initiative#110 - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + if !alias.has_escaping_bound_vars() && !self.in_alias { return Ok(self.next_ty_var_for_alias()); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs new file mode 100644 index 0000000000000..c7f771ffe37f7 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs @@ -0,0 +1,269 @@ +//! # Lattice variables +//! +//! Generic code for operating on [lattices] of inference variables +//! that are characterized by an upper- and lower-bound. +//! +//! The code is defined quite generically so that it can be +//! applied both to type variables, which represent types being inferred, +//! and fn variables, which represent function types being inferred. +//! (It may eventually be applied to their types as well.) +//! In some cases, the functions are also generic with respect to the +//! operation on the lattice (GLB vs LUB). +//! +//! ## Note +//! +//! Although all the functions are generic, for simplicity, comments in the source code +//! generally refer to type variables and the LUB operation. +//! +//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) + +use rustc_type_ir::{ + AliasRelationDirection, TypeVisitableExt, Upcast, Variance, + inherent::{IntoKind, Span as _}, + relate::{ + Relate, StructurallyRelateAliases, TypeRelation, VarianceDiagInfo, + combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys}, + }, +}; + +use crate::next_solver::{ + AliasTy, Binder, Const, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Region, Span, Ty, + TyKind, + infer::{ + DefineOpaqueTypes, InferCtxt, TypeTrace, + relate::RelateResult, + traits::{Obligation, PredicateObligations}, + }, +}; + +#[derive(Clone, Copy)] +pub(crate) enum LatticeOpKind { + Glb, + Lub, +} + +impl LatticeOpKind { + fn invert(self) -> Self { + match self { + LatticeOpKind::Glb => LatticeOpKind::Lub, + LatticeOpKind::Lub => LatticeOpKind::Glb, + } + } +} + +/// A greatest lower bound" (common subtype) or least upper bound (common supertype). +pub(crate) struct LatticeOp<'infcx, 'db> { + infcx: &'infcx InferCtxt<'db>, + // Immutable fields + trace: TypeTrace<'db>, + param_env: ParamEnv<'db>, + // Mutable fields + kind: LatticeOpKind, + obligations: PredicateObligations<'db>, +} + +impl<'infcx, 'db> LatticeOp<'infcx, 'db> { + pub(crate) fn new( + infcx: &'infcx InferCtxt<'db>, + trace: TypeTrace<'db>, + param_env: ParamEnv<'db>, + kind: LatticeOpKind, + ) -> LatticeOp<'infcx, 'db> { + LatticeOp { infcx, trace, param_env, kind, obligations: PredicateObligations::new() } + } + + pub(crate) fn into_obligations(self) -> PredicateObligations<'db> { + self.obligations + } +} + +impl<'db> TypeRelation> for LatticeOp<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn relate_with_variance>>( + &mut self, + variance: Variance, + _info: VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'db, T> { + match variance { + Variance::Invariant => { + self.obligations.extend( + self.infcx + .at(&self.trace.cause, self.param_env) + .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)? + .into_obligations(), + ); + Ok(a) + } + Variance::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test + Variance::Bivariant => Ok(a), + Variance::Contravariant => { + self.kind = self.kind.invert(); + let res = self.relate(a, b); + self.kind = self.kind.invert(); + res + } + } + } + + /// Relates two types using a given lattice. + fn tys(&mut self, a: Ty<'db>, b: Ty<'db>) -> RelateResult<'db, Ty<'db>> { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + + match (a.kind(), b.kind()) { + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in particular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (TyKind::Infer(rustc_type_ir::TyVar(..)), _) => { + let v = infcx.next_ty_var(); + self.relate_bound(v, b, a)?; + Ok(v) + } + (_, TyKind::Infer(rustc_type_ir::TyVar(..))) => { + let v = infcx.next_ty_var(); + self.relate_bound(v, a, b)?; + Ok(v) + } + + ( + TyKind::Alias(rustc_type_ir::Opaque, AliasTy { def_id: a_def_id, .. }), + TyKind::Alias(rustc_type_ir::Opaque, AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => super_combine_tys(infcx, self, a, b), + + _ => super_combine_tys(infcx, self, a, b), + } + } + + fn regions(&mut self, a: Region<'db>, b: Region<'db>) -> RelateResult<'db, Region<'db>> { + let mut inner = self.infcx.inner.borrow_mut(); + let mut constraints = inner.unwrap_region_constraints(); + Ok(match self.kind { + // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 + LatticeOpKind::Glb => constraints.lub_regions(self.cx(), a, b), + + // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 + LatticeOpKind::Lub => constraints.glb_regions(self.cx(), a, b), + }) + } + + fn consts(&mut self, a: Const<'db>, b: Const<'db>) -> RelateResult<'db, Const<'db>> { + super_combine_consts(self.infcx, self, a, b) + } + + fn binders( + &mut self, + a: Binder<'db, T>, + b: Binder<'db, T>, + ) -> RelateResult<'db, Binder<'db, T>> + where + T: Relate>, + { + // GLB/LUB of a binder and itself is just itself + if a == b { + return Ok(a); + } + + if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { + // When higher-ranked types are involved, computing the GLB/LUB is + // very challenging, switch to invariance. This is obviously + // overly conservative but works ok in practice. + self.relate_with_variance(Variance::Invariant, VarianceDiagInfo::default(), a, b)?; + Ok(a) + } else { + Ok(Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) + } + } +} + +impl<'infcx, 'db> LatticeOp<'infcx, 'db> { + // Relates the type `v` to `a` and `b` such that `v` represents + // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unnecessary + // type variable obligations. See caller for details. + fn relate_bound(&mut self, v: Ty<'db>, a: Ty<'db>, b: Ty<'db>) -> RelateResult<'db, ()> { + let at = self.infcx.at(&self.trace.cause, self.param_env); + match self.kind { + LatticeOpKind::Glb => { + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations()); + } + LatticeOpKind::Lub => { + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations()); + } + } + Ok(()) + } +} + +impl<'db> PredicateEmittingRelation> for LatticeOp<'_, 'db> { + fn span(&self) -> Span { + Span::dummy() + } + + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + + fn param_env(&self) -> ParamEnv<'db> { + self.param_env + } + + fn register_predicates( + &mut self, + preds: impl IntoIterator, Predicate<'db>>>, + ) { + self.obligations.extend(preds.into_iter().map(|pred| { + Obligation::new(self.infcx.interner, self.trace.cause.clone(), self.param_env, pred) + })) + } + + fn register_goals(&mut self, goals: impl IntoIterator>>) { + self.obligations.extend(goals.into_iter().map(|goal| { + Obligation::new( + self.infcx.interner, + self.trace.cause.clone(), + goal.param_env, + goal.predicate, + ) + })) + } + + fn register_alias_relate_predicate(&mut self, a: Ty<'db>, b: Ty<'db>) { + self.register_predicates([Binder::dummy(PredicateKind::AliasRelate( + a.into(), + b.into(), + // FIXME(deferred_projection_equality): This isn't right, I think? + AliasRelationDirection::Equate, + ))]); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs index 836ae39dc5253..0cc1cf756a9c2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/mod.rs @@ -9,5 +9,6 @@ use crate::next_solver::DbInterner; mod generalize; mod higher_ranked; +pub(crate) mod lattice; pub type RelateResult<'db, T> = rustc_type_ir::relate::RelateResult, T>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs new file mode 100644 index 0000000000000..d656d94f4f91e --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs @@ -0,0 +1,334 @@ +use std::ops::ControlFlow; + +use hir_def::{ImplId, TraitId}; +use rustc_type_ir::{ + Interner, + solve::{BuiltinImplSource, CandidateSource, Certainty, inspect::ProbeKind}, +}; + +use crate::{ + db::InternedOpaqueTyId, + next_solver::{ + Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError, + infer::{ + InferCtxt, + traits::{Obligation, ObligationCause, PredicateObligation, TraitObligation}, + }, + inspect::{InspectCandidate, InspectGoal, ProofTreeVisitor}, + }, +}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum SelectionError<'db> { + /// The trait is not implemented. + Unimplemented, + /// After a closure impl has selected, its "outputs" were evaluated + /// (which for closures includes the "input" type params) and they + /// didn't resolve. See `confirm_poly_trait_refs` for more. + SignatureMismatch(Box>), + /// The trait pointed by `DefId` is dyn-incompatible. + TraitDynIncompatible(TraitId), + /// A given constant couldn't be evaluated. + NotConstEvaluatable(NotConstEvaluatable), + /// Exceeded the recursion depth during type projection. + Overflow(OverflowError), + /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). + /// We can thus not know whether the hidden type implements an auto trait, so + /// we should not presume anything about it. + OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId), + /// Error for a `ConstArgHasType` goal + ConstArgHasWrongType { ct: Const<'db>, ct_ty: Ty<'db>, expected_ty: Ty<'db> }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum NotConstEvaluatable { + Error(ErrorGuaranteed), + MentionsInfer, + MentionsParam, +} + +/// Indicates that trait evaluation caused overflow and in which pass. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum OverflowError { + Error(ErrorGuaranteed), + Canonical, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SignatureMismatchData<'db> { + pub found_trait_ref: TraitRef<'db>, + pub expected_trait_ref: TraitRef<'db>, + pub terr: TypeError<'db>, +} + +/// When performing resolution, it is typically the case that there +/// can be one of three outcomes: +/// +/// - `Ok(Some(r))`: success occurred with result `r` +/// - `Ok(None)`: could not definitely determine anything, usually due +/// to inconclusive type inference. +/// - `Err(e)`: error `e` occurred +pub type SelectionResult<'db, T> = Result, SelectionError<'db>>; + +/// Given the successful resolution of an obligation, the `ImplSource` +/// indicates where the impl comes from. +/// +/// For example, the obligation may be satisfied by a specific impl (case A), +/// or it may be relative to some bound that is in scope (case B). +/// +/// ```ignore (illustrative) +/// impl Clone for Option { ... } // Impl_1 +/// impl Clone for Box { ... } // Impl_2 +/// impl Clone for i32 { ... } // Impl_3 +/// +/// fn foo(concrete: Option>, param: T, mixed: Option) { +/// // Case A: ImplSource points at a specific impl. Only possible when +/// // type is concretely known. If the impl itself has bounded +/// // type parameters, ImplSource will carry resolutions for those as well: +/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])]) +/// +/// // Case B: ImplSource must be provided by caller. This applies when +/// // type is a type parameter. +/// param.clone(); // ImplSource::Param +/// +/// // Case C: A mix of cases A and B. +/// mixed.clone(); // ImplSource(Impl_1, [ImplSource::Param]) +/// } +/// ``` +/// +/// ### The type parameter `N` +/// +/// See explanation on `ImplSourceUserDefinedData`. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ImplSource<'db, N> { + /// ImplSource identifying a particular impl. + UserDefined(ImplSourceUserDefinedData<'db, N>), + + /// Successful resolution to an obligation provided by the caller + /// for some type parameter. The `Vec` represents the + /// obligations incurred from normalizing the where-clause (if + /// any). + Param(Vec), + + /// Successful resolution for a builtin impl. + Builtin(BuiltinImplSource, Vec), +} + +impl<'db, N> ImplSource<'db, N> { + pub fn nested_obligations(self) -> Vec { + match self { + ImplSource::UserDefined(i) => i.nested, + ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, + } + } + + pub fn borrow_nested_obligations(&self) -> &[N] { + match self { + ImplSource::UserDefined(i) => &i.nested, + ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, + } + } + + pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { + match self { + ImplSource::UserDefined(i) => &mut i.nested, + ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, + } + } + + pub fn map(self, f: F) -> ImplSource<'db, M> + where + F: FnMut(N) -> M, + { + match self { + ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id: i.impl_def_id, + args: i.args, + nested: i.nested.into_iter().map(f).collect(), + }), + ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()), + ImplSource::Builtin(source, n) => { + ImplSource::Builtin(source, n.into_iter().map(f).collect()) + } + } + } +} + +/// Identifies a particular impl in the source, along with a set of +/// generic parameters from the impl's type/lifetime parameters. The +/// `nested` vector corresponds to the nested obligations attached to +/// the impl's type parameters. +/// +/// The type parameter `N` indicates the type used for "nested +/// obligations" that are required by the impl. During type-check, this +/// is `Obligation`, as one might expect. During codegen, however, this +/// is `()`, because codegen only requires a shallow resolution of an +/// impl, and nested obligations are satisfied later. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ImplSourceUserDefinedData<'db, N> { + pub impl_def_id: ImplId, + pub args: GenericArgs<'db>, + pub nested: Vec, +} + +pub type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>; + +impl<'db> InferCtxt<'db> { + pub(crate) fn select( + &self, + obligation: &TraitObligation<'db>, + ) -> SelectionResult<'db, Selection<'db>> { + self.visit_proof_tree( + Goal::new(self.interner, obligation.param_env, obligation.predicate), + &mut Select {}, + ) + .break_value() + .unwrap() + } +} + +struct Select {} + +impl<'db> ProofTreeVisitor<'db> for Select { + type Result = ControlFlow>>; + + fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result { + let mut candidates = goal.candidates(); + candidates.retain(|cand| cand.result().is_ok()); + + // No candidates -- not implemented. + if candidates.is_empty() { + return ControlFlow::Break(Err(SelectionError::Unimplemented)); + } + + // One candidate, no need to winnow. + if candidates.len() == 1 { + return ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap()))); + } + + // Don't winnow until `Certainty::Yes` -- we don't need to winnow until + // codegen, and only on the good path. + if matches!(goal.result().unwrap(), Certainty::Maybe(..)) { + return ControlFlow::Break(Ok(None)); + } + + // We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`. + let mut i = 0; + while i < candidates.len() { + let should_drop_i = (0..candidates.len()) + .filter(|&j| i != j) + .any(|j| candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])); + if should_drop_i { + candidates.swap_remove(i); + } else { + i += 1; + if i > 1 { + return ControlFlow::Break(Ok(None)); + } + } + } + + ControlFlow::Break(Ok(to_selection(candidates.into_iter().next().unwrap()))) + } +} + +/// This is a lot more limited than the old solver's equivalent method. This may lead to more `Ok(None)` +/// results when selecting traits in polymorphic contexts, but we should never rely on the lack of ambiguity, +/// and should always just gracefully fail here. We shouldn't rely on this incompleteness. +fn candidate_should_be_dropped_in_favor_of<'db>( + victim: &InspectCandidate<'_, 'db>, + other: &InspectCandidate<'_, 'db>, +) -> bool { + // Don't winnow until `Certainty::Yes` -- we don't need to winnow until + // codegen, and only on the good path. + if matches!(other.result().unwrap(), Certainty::Maybe(..)) { + return false; + } + + let ProbeKind::TraitCandidate { source: victim_source, result: _ } = victim.kind() else { + return false; + }; + let ProbeKind::TraitCandidate { source: other_source, result: _ } = other.kind() else { + return false; + }; + + match (victim_source, other_source) { + (_, CandidateSource::CoherenceUnknowable) | (CandidateSource::CoherenceUnknowable, _) => { + panic!("should not have assembled a CoherenceUnknowable candidate") + } + + // In the old trait solver, we arbitrarily choose lower vtable candidates + // over higher ones. + ( + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)), + ) => a >= b, + ( + CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(a)), + CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(b)), + ) => a >= b, + // Prefer dyn candidates over non-dyn candidates. This is necessary to + // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. + ( + CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound, + CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), + ) => true, + + // Prefer specializing candidates over specialized candidates. + (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => { + victim.goal().infcx().interner.impl_specializes(other_def_id, victim_def_id) + } + + _ => false, + } +} + +fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option> { + if let Certainty::Maybe(..) = cand.shallow_certainty() { + return None; + } + + let nested = match cand.result().expect("expected positive result") { + Certainty::Yes => Vec::new(), + Certainty::Maybe(_) => cand + .instantiate_nested_goals() + .into_iter() + .map(|nested| { + Obligation::new( + nested.infcx().interner, + ObligationCause::dummy(), + nested.goal().param_env, + nested.goal().predicate, + ) + }) + .collect(), + }; + + Some(match cand.kind() { + ProbeKind::TraitCandidate { source, result: _ } => match source { + CandidateSource::Impl(impl_def_id) => { + // FIXME: Remove this in favor of storing this in the tree + // For impl candidates, we do the rematch manually to compute the args. + ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id: impl_def_id.0, + args: cand.instantiate_impl_args(), + nested, + }) + } + CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested), + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested), + CandidateSource::CoherenceUnknowable => { + panic!("didn't expect to select an unknowable candidate") + } + }, + ProbeKind::NormalizedSelfTyAssembly + | ProbeKind::UnsizeAssembly + | ProbeKind::ProjectionCompatibility + | ProbeKind::OpaqueTypeStorageLookup { result: _ } + | ProbeKind::Root { result: _ } + | ProbeKind::ShadowedEnvProbing + | ProbeKind::RigidAlias { result: _ } => { + panic!("didn't expect to assemble trait candidate from {:#?}", cand.kind()) + } + }) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs new file mode 100644 index 0000000000000..74353574e3298 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs @@ -0,0 +1,263 @@ +use std::ops::Range; + +use ena::{ + snapshot_vec as sv, + unify::{self as ut, UnifyKey}, +}; +use rustc_type_ir::{ + ConstVid, FloatVid, IntVid, RegionKind, RegionVid, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind, +}; + +use crate::next_solver::{ + Const, ConstKind, DbInterner, Region, Ty, TyKind, + infer::{ + InferCtxt, UnificationTable, iter_idx_range, + snapshot::VariableLengths, + type_variable::TypeVariableOrigin, + unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}, + }, +}; + +fn vars_since_snapshot<'db, T>( + table: &UnificationTable<'_, 'db, T>, + snapshot_var_len: usize, +) -> Range +where + T: UnifyKey, + super::UndoLog<'db>: From>>, +{ + T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32) +} + +fn const_vars_since_snapshot<'db>( + table: &mut UnificationTable<'_, 'db, ConstVidKey<'db>>, + snapshot_var_len: usize, +) -> (Range, Vec) { + let range = vars_since_snapshot(table, snapshot_var_len); + let range = range.start.vid..range.end.vid; + + ( + range.clone(), + iter_idx_range(range) + .map(|index| match table.probe_value(index) { + ConstVariableValue::Known { value: _ } => { + ConstVariableOrigin { param_def_id: None } + } + ConstVariableValue::Unknown { origin, universe: _ } => origin, + }) + .collect(), + ) +} + +impl<'db> InferCtxt<'db> { + /// This rather funky routine is used while processing expected + /// types. What happens here is that we want to propagate a + /// coercion through the return type of a fn to its + /// argument. Consider the type of `Option::Some`, which is + /// basically `for fn(T) -> Option`. So if we have an + /// expression `Some(&[1, 2, 3])`, and that has the expected type + /// `Option<&[u32]>`, we would like to type check `&[1, 2, 3]` + /// with the expectation of `&[u32]`. This will cause us to coerce + /// from `&[u32; 3]` to `&[u32]` and make the users life more + /// pleasant. + /// + /// The way we do this is using `fudge_inference_if_ok`. What the + /// routine actually does is to start a snapshot and execute the + /// closure `f`. In our example above, what this closure will do + /// is to unify the expectation (`Option<&[u32]>`) with the actual + /// return type (`Option`, where `?T` represents the variable + /// instantiated for `T`). This will cause `?T` to be unified + /// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The + /// input type (`?T`) is then returned by `f()`. + /// + /// At this point, `fudge_inference_if_ok` will normalize all type + /// variables, converting `?T` to `&?a [u32]` and end the + /// snapshot. The problem is that we can't just return this type + /// out, because it references the region variable `?a`, and that + /// region variable was popped when we popped the snapshot. + /// + /// So what we do is to keep a list (`region_vars`, in the code below) + /// of region variables created during the snapshot (here, `?a`). We + /// fold the return value and replace any such regions with a *new* + /// region variable (e.g., `?b`) and return the result (`&?b [u32]`). + /// This can then be used as the expectation for the fn argument. + /// + /// The important point here is that, for soundness purposes, the + /// regions in question are not particularly important. We will + /// use the expected types to guide coercions, but we will still + /// type-check the resulting types from those coercions against + /// the actual types (`?T`, `Option`) -- and remember that + /// after the snapshot is popped, the variable `?T` is no longer + /// unified. + pub fn fudge_inference_if_ok(&self, f: F) -> Result + where + F: FnOnce() -> Result, + T: TypeFoldable>, + { + let variable_lengths = self.variable_lengths(); + let (snapshot_vars, value) = self.probe(|_| { + let value = f()?; + // At this point, `value` could in principle refer + // to inference variables that have been created during + // the snapshot. Once we exit `probe()`, those are + // going to be popped, so we will have to + // eliminate any references to them. + let snapshot_vars = SnapshotVarData::new(self, variable_lengths); + Ok((snapshot_vars, self.resolve_vars_if_possible(value))) + })?; + + // At this point, we need to replace any of the now-popped + // type/region variables that appear in `value` with a fresh + // variable of the appropriate kind. We can't do this during + // the probe because they would just get popped then too. =) + Ok(self.fudge_inference(snapshot_vars, value)) + } + + fn fudge_inference>>( + &self, + snapshot_vars: SnapshotVarData, + value: T, + ) -> T { + // Micro-optimization: if no variables have been created, then + // `value` can't refer to any of them. =) So we can just return it. + if snapshot_vars.is_empty() { + value + } else { + value.fold_with(&mut InferenceFudger { infcx: self, snapshot_vars }) + } + } +} + +struct SnapshotVarData { + region_vars: Range, + type_vars: (Range, Vec), + int_vars: Range, + float_vars: Range, + const_vars: (Range, Vec), +} + +impl SnapshotVarData { + fn new(infcx: &InferCtxt<'_>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData { + let mut inner = infcx.inner.borrow_mut(); + let region_vars = inner + .unwrap_region_constraints() + .vars_since_snapshot(vars_pre_snapshot.region_constraints_len); + let type_vars = inner.type_variables().vars_since_snapshot(vars_pre_snapshot.type_var_len); + let int_vars = + vars_since_snapshot(&inner.int_unification_table(), vars_pre_snapshot.int_var_len); + let float_vars = + vars_since_snapshot(&inner.float_unification_table(), vars_pre_snapshot.float_var_len); + + let const_vars = const_vars_since_snapshot( + &mut inner.const_unification_table(), + vars_pre_snapshot.const_var_len, + ); + SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } + } + + fn is_empty(&self) -> bool { + let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self; + region_vars.is_empty() + && type_vars.0.is_empty() + && int_vars.is_empty() + && float_vars.is_empty() + && const_vars.0.is_empty() + } +} + +struct InferenceFudger<'a, 'db> { + infcx: &'a InferCtxt<'db>, + snapshot_vars: SnapshotVarData, +} + +impl<'a, 'db> TypeFolder> for InferenceFudger<'a, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + if let TyKind::Infer(infer_ty) = ty.kind() { + match infer_ty { + rustc_type_ir::TyVar(vid) => { + if self.snapshot_vars.type_vars.0.contains(&vid) { + // This variable was created during the fudging. + // Recreate it with a fresh variable here. + let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize(); + let origin = self.snapshot_vars.type_vars.1[idx]; + self.infcx.next_ty_var_with_origin(origin) + } else { + // This variable was created before the + // "fudging". Since we refresh all type + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!( + self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown() + ); + ty + } + } + rustc_type_ir::IntVar(vid) => { + if self.snapshot_vars.int_vars.contains(&vid) { + self.infcx.next_int_var() + } else { + ty + } + } + rustc_type_ir::FloatVar(vid) => { + if self.snapshot_vars.float_vars.contains(&vid) { + self.infcx.next_float_var() + } else { + ty + } + } + rustc_type_ir::FreshTy(_) + | rustc_type_ir::FreshIntTy(_) + | rustc_type_ir::FreshFloatTy(_) => { + unreachable!("unexpected fresh infcx var") + } + } + } else if ty.has_infer() { + ty.super_fold_with(self) + } else { + ty + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if let RegionKind::ReVar(vid) = r.kind() { + if self.snapshot_vars.region_vars.contains(&vid) { + let idx = vid.index() - self.snapshot_vars.region_vars.start.index(); + self.infcx.next_region_var() + } else { + r + } + } else { + r + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + if let ConstKind::Infer(infer_ct) = ct.kind() { + match infer_ct { + rustc_type_ir::InferConst::Var(vid) => { + if self.snapshot_vars.const_vars.0.contains(&vid) { + let idx = vid.index() - self.snapshot_vars.const_vars.0.start.index(); + let origin = self.snapshot_vars.const_vars.1[idx]; + self.infcx.next_const_var_with_origin(origin) + } else { + ct + } + } + rustc_type_ir::InferConst::Fresh(_) => { + unreachable!("unexpected fresh infcx var") + } + } + } else if ct.has_infer() { + ct.super_fold_with(self) + } else { + ct + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs index 8c7dfb25e07f9..7b9ca96c51406 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs @@ -7,6 +7,7 @@ use tracing::{debug, instrument}; use super::InferCtxt; use super::region_constraints::RegionSnapshot; +mod fudge; pub(crate) mod undo_log; use undo_log::{Snapshot, UndoLog}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs index 28ae56f4ee70a..05a1013b3fbd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs @@ -178,6 +178,10 @@ impl<'db> InferCtxtUndoLogs<'db> { }) } + pub(crate) fn opaque_types_in_snapshot(&self, s: &Snapshot) -> bool { + self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..))) + } + fn assert_open_snapshot(&self, snapshot: &Snapshot) { // Failures here may indicate a failure to follow a stack discipline. assert!(self.logs.len() >= snapshot.undo_len); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs index f1df806ab3187..68aa12d7bb0cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs @@ -7,14 +7,16 @@ use std::{ hash::{Hash, Hasher}, }; +use rustc_type_ir::elaborate::Elaboratable; use rustc_type_ir::{ PredicatePolarity, Upcast, solve::{Certainty, NoSolution}, }; +use rustc_type_ir::{TypeFoldable, TypeVisitable}; use crate::next_solver::{ - Binder, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, TraitPredicate, - Ty, + Binder, Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, Span, + TraitPredicate, Ty, }; use super::InferCtxt; @@ -29,24 +31,29 @@ use super::InferCtxt; /// only live for a short period of time. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ObligationCause { - /// The ID of the fn body that triggered this obligation. This is - /// used for region obligations to determine the precise - /// environment in which the region obligation should be evaluated - /// (in particular, closures can add new assumptions). See the - /// field `region_obligations` of the `FulfillmentContext` for more - /// information. - pub body_id: Option, + // FIXME: This should contain an `ExprId`/`PatId` etc., and a cause code. But for now we + // don't report trait solving diagnostics, so this is irrelevant. + _private: (), } impl ObligationCause { + #[expect( + clippy::new_without_default, + reason = "`new` is temporary, eventually we will provide span etc. here" + )] #[inline] - pub fn new(body_id: SolverDefId) -> ObligationCause { - ObligationCause { body_id: Some(body_id) } + pub fn new() -> ObligationCause { + ObligationCause { _private: () } } - #[inline(always)] + #[inline] pub fn dummy() -> ObligationCause { - ObligationCause { body_id: None } + ObligationCause::new() + } + + #[inline] + pub fn misc() -> ObligationCause { + ObligationCause::new() } } @@ -75,6 +82,72 @@ pub struct Obligation<'db, T> { pub recursion_depth: usize, } +/// For [`Obligation`], a sub-obligation is combined with the current obligation's +/// param-env and cause code. +impl<'db> Elaboratable> for PredicateObligation<'db> { + fn predicate(&self) -> Predicate<'db> { + self.predicate + } + + fn child(&self, clause: Clause<'db>) -> Self { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + recursion_depth: 0, + predicate: clause.as_predicate(), + } + } + + fn child_with_derived_cause( + &self, + clause: Clause<'db>, + span: Span, + parent_trait_pred: PolyTraitPredicate<'db>, + index: usize, + ) -> Self { + let cause = ObligationCause::new(); + Obligation { + cause, + param_env: self.param_env, + recursion_depth: 0, + predicate: clause.as_predicate(), + } + } +} + +impl<'db, T: TypeVisitable>> TypeVisitable> for Obligation<'db, T> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + rustc_ast_ir::try_visit!(self.param_env.visit_with(visitor)); + self.predicate.visit_with(visitor) + } +} + +impl<'db, T: TypeFoldable>> TypeFoldable> for Obligation<'db, T> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(Obligation { + cause: self.cause.clone(), + param_env: self.param_env.try_fold_with(folder)?, + predicate: self.predicate.try_fold_with(folder)?, + recursion_depth: self.recursion_depth, + }) + } + + fn fold_with>>(self, folder: &mut F) -> Self { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env.fold_with(folder), + predicate: self.predicate.fold_with(folder), + recursion_depth: self.recursion_depth, + } + } +} + impl<'db, T: Copy> Obligation<'db, T> { pub fn as_goal(&self) -> Goal<'db, T> { Goal { param_env: self.param_env, predicate: self.predicate } @@ -156,15 +229,6 @@ impl<'db, O> Obligation<'db, O> { Obligation { cause, param_env, recursion_depth, predicate } } - pub fn misc( - tcx: DbInterner<'db>, - body_id: SolverDefId, - param_env: ParamEnv<'db>, - trait_ref: impl Upcast, O>, - ) -> Obligation<'db, O> { - Obligation::new(tcx, ObligationCause::new(body_id), param_env, trait_ref) - } - pub fn with

( + &self, + tcx: DbInterner<'db>, + value: impl Upcast, P>, + ) -> Obligation<'db, P> { + Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs new file mode 100644 index 0000000000000..5217308af473c --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/type_variable.rs @@ -0,0 +1,268 @@ +//! Storage for type variables for the infer context the next-trait-solver. + +use std::cmp; +use std::marker::PhantomData; +use std::ops::Range; + +use ena::snapshot_vec as sv; +use ena::undo_log::Rollback; +use ena::unify as ut; +use rustc_index::IndexVec; +use rustc_type_ir::TyVid; +use rustc_type_ir::UniverseIndex; +use rustc_type_ir::inherent::Ty as _; +use tracing::debug; + +use crate::next_solver::SolverDefId; +use crate::next_solver::Ty; +use crate::next_solver::infer::InferCtxtUndoLogs; + +impl<'db> Rollback>>> for TypeVariableStorage<'db> { + fn reverse(&mut self, undo: sv::UndoLog>>) { + self.eq_relations.reverse(undo) + } +} + +#[derive(Clone, Default)] +pub(crate) struct TypeVariableStorage<'db> { + /// The origins of each type variable. + values: IndexVec, + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X == ?Y`. This table also stores, for each key, + /// the known value. + eq_relations: ut::UnificationTableStorage>, +} + +pub(crate) struct TypeVariableTable<'a, 'db> { + storage: &'a mut TypeVariableStorage<'db>, + + undo_log: &'a mut InferCtxtUndoLogs<'db>, +} + +#[derive(Copy, Clone, Debug)] +pub struct TypeVariableOrigin { + /// `DefId` of the type parameter this was instantiated for, if any. + /// + /// This should only be used for diagnostics. + pub param_def_id: Option, +} + +#[derive(Clone)] +pub(crate) struct TypeVariableData { + origin: TypeVariableOrigin, +} + +#[derive(Clone, Debug)] +pub(crate) enum TypeVariableValue<'db> { + Known { value: Ty<'db> }, + Unknown { universe: UniverseIndex }, +} + +impl<'db> TypeVariableValue<'db> { + /// If this value is known, returns the type it is known to be. + /// Otherwise, `None`. + pub(crate) fn known(&self) -> Option> { + match self { + TypeVariableValue::Unknown { .. } => None, + TypeVariableValue::Known { value } => Some(*value), + } + } + + pub(crate) fn is_unknown(&self) -> bool { + match *self { + TypeVariableValue::Unknown { .. } => true, + TypeVariableValue::Known { .. } => false, + } + } +} + +impl<'db> TypeVariableStorage<'db> { + #[inline] + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'db>, + ) -> TypeVariableTable<'a, 'db> { + TypeVariableTable { storage: self, undo_log } + } + + #[inline] + pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage> { + &self.eq_relations + } + + pub(super) fn finalize_rollback(&mut self) { + debug_assert!(self.values.len() >= self.eq_relations.len()); + self.values.truncate(self.eq_relations.len()); + } +} + +impl<'db> TypeVariableTable<'_, 'db> { + /// Returns the origin that was given when `vid` was created. + /// + /// Note that this function does not return care whether + /// `vid` has been unified with something else or not. + pub(crate) fn var_origin(&self, vid: TyVid) -> TypeVariableOrigin { + self.storage.values[vid].origin + } + + /// Records that `a == b`, depending on `dir`. + /// + /// Precondition: neither `a` nor `b` are known. + pub(crate) fn equate(&mut self, a: TyVid, b: TyVid) { + debug_assert!(self.probe(a).is_unknown()); + debug_assert!(self.probe(b).is_unknown()); + self.eq_relations().union(a, b); + } + + /// Instantiates `vid` with the type `ty`. + /// + /// Precondition: `vid` must not have been previously instantiated. + pub(crate) fn instantiate(&mut self, vid: TyVid, ty: Ty<'db>) { + let vid = self.root_var(vid); + debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}"); + debug_assert!(self.probe(vid).is_unknown()); + debug_assert!( + self.eq_relations().probe_value(vid).is_unknown(), + "instantiating type variable `{vid:?}` twice: new-value = {ty:?}, old-value={:?}", + self.eq_relations().probe_value(vid) + ); + self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty }); + } + + /// Creates a new type variable. + /// + /// - `diverging`: indicates if this is a "diverging" type + /// variable, e.g., one created as the type of a `return` + /// expression. The code in this module doesn't care if a + /// variable is diverging, but the main Rust type-checker will + /// sometimes "unify" such variables with the `!` or `()` types. + /// - `origin`: indicates *why* the type variable was created. + /// The code in this module doesn't care, but it can be useful + /// for improving error messages. + pub(crate) fn new_var(&mut self, universe: UniverseIndex, origin: TypeVariableOrigin) -> TyVid { + let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); + let index = self.storage.values.push(TypeVariableData { origin }); + debug_assert_eq!(eq_key.vid, index); + + debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin); + + index + } + + /// Returns the number of type variables created thus far. + pub(crate) fn num_vars(&self) -> usize { + self.storage.values.len() + } + + /// Returns the "root" variable of `vid` in the `eq_relations` + /// equivalence table. All type variables that have been equated + /// will yield the same root variable (per the union-find + /// algorithm), so `root_var(a) == root_var(b)` implies that `a == + /// b` (transitively). + pub(crate) fn root_var(&mut self, vid: TyVid) -> TyVid { + self.eq_relations().find(vid).vid + } + + /// Retrieves the type to which `vid` has been instantiated, if + /// any. + pub(crate) fn probe(&mut self, vid: TyVid) -> TypeVariableValue<'db> { + self.inlined_probe(vid) + } + + /// An always-inlined variant of `probe`, for very hot call sites. + #[inline(always)] + pub(crate) fn inlined_probe(&mut self, vid: TyVid) -> TypeVariableValue<'db> { + self.eq_relations().inlined_probe_value(vid) + } + + #[inline] + fn eq_relations(&mut self) -> super::UnificationTable<'_, 'db, TyVidEqKey<'db>> { + self.storage.eq_relations.with_log(self.undo_log) + } + + /// Returns indices of all variables that are not yet + /// instantiated. + pub(crate) fn unresolved_variables(&mut self) -> Vec { + (0..self.num_vars()) + .filter_map(|i| { + let vid = TyVid::from_usize(i); + match self.probe(vid) { + TypeVariableValue::Unknown { .. } => Some(vid), + TypeVariableValue::Known { .. } => None, + } + }) + .collect() + } +} + +/////////////////////////////////////////////////////////////////////////// + +/// These structs (a newtyped TyVid) are used as the unification key +/// for the `eq_relations`; they carry a `TypeVariableValue` along +/// with them. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) struct TyVidEqKey<'db> { + vid: TyVid, + + // in the table, we map each ty-vid to one of these: + phantom: PhantomData>, +} + +impl<'db> From for TyVidEqKey<'db> { + #[inline] // make this function eligible for inlining - it is quite hot. + fn from(vid: TyVid) -> Self { + TyVidEqKey { vid, phantom: PhantomData } + } +} + +impl<'db> ut::UnifyKey for TyVidEqKey<'db> { + type Value = TypeVariableValue<'db>; + #[inline(always)] + fn index(&self) -> u32 { + self.vid.as_u32() + } + #[inline] + fn from_index(i: u32) -> Self { + TyVidEqKey::from(TyVid::from_u32(i)) + } + fn tag() -> &'static str { + "TyVidEqKey" + } +} + +impl<'db> ut::UnifyValue for TypeVariableValue<'db> { + type Error = ut::NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result { + match (value1, value2) { + // We never equate two type variables, both of which + // have known types. Instead, we recursively equate + // those types. + (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => { + panic!("equating two type variables, both of which have known types") + } + + // If one side is known, prefer that one. + (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => { + Ok(value1.clone()) + } + (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => { + Ok(value2.clone()) + } + + // If both sides are *unknown*, it hardly matters, does it? + ( + &TypeVariableValue::Unknown { universe: universe1 }, + &TypeVariableValue::Unknown { universe: universe2 }, + ) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(universe1, universe2); + Ok(TypeVariableValue::Unknown { universe }) + } + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs new file mode 100644 index 0000000000000..b9afb45ba89da --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs @@ -0,0 +1,176 @@ +//! Unification keyes for the infer context the next-trait-solver. + +use std::cmp; +use std::marker::PhantomData; + +use ena::unify::{NoError, UnifyKey, UnifyValue}; +use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind}; + +use crate::next_solver::{Const, Region, SolverDefId, Ty}; + +#[derive(Clone, Debug)] +pub enum RegionVariableValue<'db> { + Known { value: Region<'db> }, + Unknown { universe: UniverseIndex }, +} + +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct RegionVidKey<'db> { + pub vid: RegionVid, + pub phantom: PhantomData>, +} + +impl<'db> From for RegionVidKey<'db> { + fn from(vid: RegionVid) -> Self { + RegionVidKey { vid, phantom: PhantomData } + } +} + +impl<'db> UnifyKey for RegionVidKey<'db> { + type Value = RegionVariableValue<'db>; + #[inline] + fn index(&self) -> u32 { + self.vid.as_u32() + } + #[inline] + fn from_index(i: u32) -> Self { + RegionVidKey::from(RegionVid::from_u32(i)) + } + fn tag() -> &'static str { + "RegionVidKey" + } +} + +pub struct RegionUnificationError; +impl<'db> UnifyValue for RegionVariableValue<'db> { + type Error = RegionUnificationError; + + fn unify_values(value1: &Self, value2: &Self) -> Result { + match (value1, value2) { + (RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => { + Err(RegionUnificationError) + } + + (RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe }) + | (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => { + let universe_of_value = match (*value).kind() { + RegionKind::ReStatic + | RegionKind::ReErased + | RegionKind::ReLateParam(..) + | RegionKind::ReEarlyParam(..) + | RegionKind::ReError(_) => UniverseIndex::ROOT, + RegionKind::RePlaceholder(placeholder) => placeholder.universe, + RegionKind::ReVar(..) | RegionKind::ReBound(..) => { + panic!("not a universal region") + } + }; + + if universe.can_name(universe_of_value) { + Ok(RegionVariableValue::Known { value: *value }) + } else { + Err(RegionUnificationError) + } + } + + ( + RegionVariableValue::Unknown { universe: a }, + RegionVariableValue::Unknown { universe: b }, + ) => { + // If we unify two unconstrained regions then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + Ok(RegionVariableValue::Unknown { universe: (*a).min(*b) }) + } + } + } +} + +// Generic consts. + +#[derive(Copy, Clone, Debug)] +pub struct ConstVariableOrigin { + /// `DefId` of the const parameter this was instantiated for, if any. + /// + /// This should only be used for diagnostics. + pub param_def_id: Option, +} + +#[derive(Clone, Debug)] +pub enum ConstVariableValue<'db> { + Known { value: Const<'db> }, + Unknown { origin: ConstVariableOrigin, universe: UniverseIndex }, +} + +impl<'db> ConstVariableValue<'db> { + /// If this value is known, returns the const it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option> { + match self { + ConstVariableValue::Unknown { .. } => None, + ConstVariableValue::Known { value } => Some(*value), + } + } +} + +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct ConstVidKey<'db> { + pub vid: ConstVid, + pub phantom: PhantomData>, +} + +impl<'db> From for ConstVidKey<'db> { + fn from(vid: ConstVid) -> Self { + ConstVidKey { vid, phantom: PhantomData } + } +} + +impl<'db> UnifyKey for ConstVidKey<'db> { + type Value = ConstVariableValue<'db>; + #[inline] + fn index(&self) -> u32 { + self.vid.as_u32() + } + #[inline] + fn from_index(i: u32) -> Self { + ConstVidKey::from(ConstVid::from_u32(i)) + } + fn tag() -> &'static str { + "ConstVidKey" + } +} + +impl<'db> UnifyValue for ConstVariableValue<'db> { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result { + match (value1, value2) { + (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { + panic!("equating two const variables, both of which have known values") + } + + // If one side is known, prefer that one. + (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { + Ok(value1.clone()) + } + (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { + Ok(value2.clone()) + } + + // If both sides are *unknown*, it hardly matters, does it? + ( + ConstVariableValue::Unknown { origin, universe: universe1 }, + ConstVariableValue::Unknown { origin: _, universe: universe2 }, + ) => { + // If we unify two unbound variables, ?T and ?U, then whatever + // value they wind up taking (which must be the same value) must + // be nameable by both universes. Therefore, the resulting + // universe is the minimum of the two universes, because that is + // the one which contains the fewest names in scope. + let universe = cmp::min(*universe1, *universe2); + Ok(ConstVariableValue::Unknown { origin: *origin, universe }) + } + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs new file mode 100644 index 0000000000000..9c1bd52065fd2 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -0,0 +1,2173 @@ +//! Things related to the Interner in the next-trait-solver. +#![allow(unused)] + +use base_db::Crate; +use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; +use hir_def::lang_item::LangItem; +use hir_def::signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}; +use hir_def::{AdtId, BlockId, TypeAliasId, VariantId}; +use hir_def::{AttrDefId, Lookup}; +use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId}; +use intern::sym::non_exhaustive; +use intern::{Interned, impl_internable, sym}; +use la_arena::Idx; +use rustc_abi::{Align, ReprFlags, ReprOptions}; +use rustc_hash::FxHashSet; +use rustc_index::bit_set::DenseBitSet; +use rustc_type_ir::elaborate::elaborate; +use rustc_type_ir::error::TypeError; +use rustc_type_ir::inherent::{ + AdtDef as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike as _, Span as _, +}; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::SizedTraitKind; +use rustc_type_ir::{ + AliasTerm, AliasTermKind, AliasTy, EarlyBinder, FlagComputation, Flags, ImplPolarity, InferTy, + ProjectionPredicate, TraitPredicate, TraitRef, Upcast, +}; +use salsa::plumbing::AsId; +use smallvec::{SmallVec, smallvec}; +use std::fmt; +use std::ops::ControlFlow; +use syntax::ast::SelfParamKind; +use triomphe::Arc; + +use rustc_ast_ir::visit::VisitorResult; +use rustc_index::IndexVec; +use rustc_type_ir::TypeVisitableExt; +use rustc_type_ir::{ + BoundVar, CollectAndApply, DebruijnIndex, GenericArgKind, RegionKind, TermKind, UniverseIndex, + Variance, WithCachedTypeInfo, elaborate, + inherent::{self, Const as _, Region as _, Ty as _}, + ir_print, relate, +}; + +use crate::lower_nextsolver::{self, TyLoweringContext}; +use crate::method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}; +use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; +use crate::next_solver::{ + CanonicalVarKind, FxIndexMap, InternedWrapperNoDebug, RegionAssumptions, SolverDefIds, +}; +use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase}; + +use super::generics::generics; +use super::util::sizedness_constraint_for_ty; +use super::{ + Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, + Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints, + ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv, + ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate, + PredicateKind, Term, Ty, TyKind, Tys, ValueConst, + abi::Safety, + fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate}, + generics::Generics, + mapping::ChalkToNextSolver, + region::{ + BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region, + }, +}; +use super::{ClauseKind, SolverDefId, Valtree}; + +#[macro_export] +#[doc(hidden)] +macro_rules! _interned_vec_nolifetime_salsa { + ($name:ident, $ty:ty) => { + interned_vec_nolifetime_salsa!($name, $ty, nofold); + + impl<'db> rustc_type_ir::TypeFoldable> for $name { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = + self.iter().map(|v| v.try_fold_with(folder)).collect::>()?; + Ok($name::new_(folder.cx().db(), inner)) + } + fn fold_with>>( + self, + folder: &mut F, + ) -> Self { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = + self.iter().map(|v| v.fold_with(folder)).collect(); + $name::new_(folder.cx().db(), inner) + } + } + + impl<'db> rustc_type_ir::TypeVisitable> for $name { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + use rustc_ast_ir::visit::VisitorResult; + use rustc_type_ir::inherent::SliceLike as _; + rustc_ast_ir::walk_visitable_list!(visitor, self.as_slice().iter()); + V::Result::output() + } + } + }; + ($name:ident, $ty:ty, nofold) => { + #[salsa::interned(no_lifetime, constructor = new_, debug)] + pub struct $name { + #[returns(ref)] + inner_: smallvec::SmallVec<[$ty; 2]>, + } + + impl $name { + pub fn new_from_iter<'db>( + interner: DbInterner<'db>, + data: impl IntoIterator, + ) -> Self { + $name::new_(interner.db(), data.into_iter().collect::>()) + } + + pub fn inner(&self) -> &smallvec::SmallVec<[$ty; 2]> { + // SAFETY: ¯\_(ツ)_/¯ + salsa::with_attached_database(|db| { + let inner = self.inner_(db); + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + } + + impl rustc_type_ir::inherent::SliceLike for $name { + type Item = $ty; + + type IntoIter = as IntoIterator>::IntoIter; + + fn iter(self) -> Self::IntoIter { + self.inner().clone().into_iter() + } + + fn as_slice(&self) -> &[Self::Item] { + self.inner().as_slice() + } + } + + impl IntoIterator for $name { + type Item = $ty; + type IntoIter = ::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + rustc_type_ir::inherent::SliceLike::iter(self) + } + } + + impl Default for $name { + fn default() -> Self { + $name::new_from_iter(DbInterner::conjure(), []) + } + } + }; +} + +pub use crate::_interned_vec_nolifetime_salsa as interned_vec_nolifetime_salsa; + +#[macro_export] +#[doc(hidden)] +macro_rules! _interned_vec_db { + ($name:ident, $ty:ident) => { + interned_vec_db!($name, $ty, nofold); + + impl<'db> rustc_type_ir::TypeFoldable> for $name<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = + self.iter().map(|v| v.try_fold_with(folder)).collect::>()?; + Ok($name::new_(folder.cx().db(), inner)) + } + fn fold_with>>( + self, + folder: &mut F, + ) -> Self { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = + self.iter().map(|v| v.fold_with(folder)).collect(); + $name::new_(folder.cx().db(), inner) + } + } + + impl<'db> rustc_type_ir::TypeVisitable> for $name<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + use rustc_ast_ir::visit::VisitorResult; + use rustc_type_ir::inherent::SliceLike as _; + rustc_ast_ir::walk_visitable_list!(visitor, self.as_slice().iter()); + V::Result::output() + } + } + }; + ($name:ident, $ty:ident, nofold) => { + #[salsa::interned(constructor = new_)] + pub struct $name<'db> { + #[returns(ref)] + inner_: smallvec::SmallVec<[$ty<'db>; 2]>, + } + + impl<'db> std::fmt::Debug for $name<'db> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.as_slice().fmt(fmt) + } + } + + impl<'db> $name<'db> { + pub fn new_from_iter( + interner: DbInterner<'db>, + data: impl IntoIterator>, + ) -> Self { + $name::new_(interner.db(), data.into_iter().collect::>()) + } + + pub fn inner(&self) -> &smallvec::SmallVec<[$ty<'db>; 2]> { + // SAFETY: ¯\_(ツ)_/¯ + salsa::with_attached_database(|db| { + let inner = self.inner_(db); + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + } + + impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> { + type Item = $ty<'db>; + + type IntoIter = ; 2]> as IntoIterator>::IntoIter; + + fn iter(self) -> Self::IntoIter { + self.inner().clone().into_iter() + } + + fn as_slice(&self) -> &[Self::Item] { + self.inner().as_slice() + } + } + + impl<'db> IntoIterator for $name<'db> { + type Item = $ty<'db>; + type IntoIter = ::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + rustc_type_ir::inherent::SliceLike::iter(self) + } + } + + impl<'db> Default for $name<'db> { + fn default() -> Self { + $name::new_from_iter(DbInterner::conjure(), []) + } + } + }; +} + +pub use crate::_interned_vec_db as interned_vec_db; + +#[derive(Debug, Copy, Clone)] +pub struct DbInterner<'db> { + pub(crate) db: &'db dyn HirDatabase, + pub(crate) krate: Option, + pub(crate) block: Option, +} + +// FIXME: very wrong, see https://github.com/rust-lang/rust/pull/144808 +unsafe impl Send for DbInterner<'_> {} +unsafe impl Sync for DbInterner<'_> {} + +impl<'db> DbInterner<'db> { + // FIXME(next-solver): remove this method + pub fn conjure() -> DbInterner<'db> { + salsa::with_attached_database(|db| DbInterner { + db: unsafe { + std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db.as_view()) + }, + krate: None, + block: None, + }) + .unwrap() + } + + pub fn new_with( + db: &'db dyn HirDatabase, + krate: Option, + block: Option, + ) -> DbInterner<'db> { + DbInterner { db, krate, block } + } + + pub fn db(&self) -> &'db dyn HirDatabase { + self.db + } +} + +// This is intentionally left as `()` +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct Span(()); + +impl<'db> inherent::Span> for Span { + fn dummy() -> Self { + Span(()) + } +} + +interned_vec_nolifetime_salsa!(BoundVarKinds, BoundVarKind, nofold); + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum BoundVarKind { + Ty(BoundTyKind), + Region(BoundRegionKind), + Const, +} + +impl BoundVarKind { + pub fn expect_region(self) -> BoundRegionKind { + match self { + BoundVarKind::Region(lt) => lt, + _ => panic!("expected a region, but found another kind"), + } + } + + pub fn expect_ty(self) -> BoundTyKind { + match self { + BoundVarKind::Ty(ty) => ty, + _ => panic!("expected a type, but found another kind"), + } + } + + pub fn expect_const(self) { + match self { + BoundVarKind::Const => (), + _ => panic!("expected a const, but found another kind"), + } + } +} + +interned_vec_db!(CanonicalVars, CanonicalVarKind, nofold); + +pub struct DepNodeIndex; + +#[derive(Debug)] +pub struct Tracked(T); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Placeholder { + pub universe: UniverseIndex, + pub bound: T, +} + +impl std::fmt::Debug for Placeholder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { + if self.universe == UniverseIndex::ROOT { + write!(f, "!{:?}", self.bound) + } else { + write!(f, "!{}_{:?}", self.universe.index(), self.bound) + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct AllocId; + +interned_vec_nolifetime_salsa!(VariancesOf, Variance, nofold); + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct VariantIdx(usize); + +// FIXME: could/should store actual data? +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum VariantDef { + Struct(StructId), + Union(UnionId), + Enum(EnumVariantId), +} + +impl VariantDef { + pub fn id(&self) -> VariantId { + match self { + VariantDef::Struct(struct_id) => VariantId::StructId(*struct_id), + VariantDef::Union(union_id) => VariantId::UnionId(*union_id), + VariantDef::Enum(enum_variant_id) => VariantId::EnumVariantId(*enum_variant_id), + } + } + + pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Idx, FieldData)> { + let id: VariantId = match self { + VariantDef::Struct(it) => (*it).into(), + VariantDef::Union(it) => (*it).into(), + VariantDef::Enum(it) => (*it).into(), + }; + id.fields(db).fields().iter().map(|(id, data)| (id, data.clone())).collect() + } +} + +/* +/// Definition of a variant -- a struct's fields or an enum variant. +#[derive(Debug, HashStable, TyEncodable, TyDecodable)] +pub struct VariantDef { + /// `DefId` that identifies the variant itself. + /// If this variant belongs to a struct or union, then this is a copy of its `DefId`. + pub def_id: DefId, + /// `DefId` that identifies the variant's constructor. + /// If this variant is a struct variant, then this is `None`. + pub ctor: Option<(CtorKind, DefId)>, + /// Variant or struct name, maybe empty for anonymous adt (struct or union). + pub name: Symbol, + /// Discriminant of this variant. + pub discr: VariantDiscr, + /// Fields of this variant. + pub fields: IndexVec, + /// The error guarantees from parser, if any. + tainted: Option, + /// Flags of the variant (e.g. is field list non-exhaustive)? + flags: VariantFlags, +} +*/ + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct AdtFlags { + is_enum: bool, + is_union: bool, + is_struct: bool, + is_phantom_data: bool, + is_fundamental: bool, + is_box: bool, + is_manually_drop: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AdtDefInner { + pub id: AdtId, + variants: Vec<(VariantIdx, VariantDef)>, + flags: AdtFlags, + repr: ReprOptions, +} + +// We're gonna cheat a little bit and implement `Hash` on only the `DefId` and +// accept there might be collisions for def ids from different crates (or across +// different tests, oh my). +impl std::hash::Hash for AdtDefInner { + #[inline] + fn hash(&self, s: &mut H) { + self.id.hash(s) + } +} + +#[salsa::interned(no_lifetime, constructor = new_)] +pub struct AdtDef { + #[returns(ref)] + data_: AdtDefInner, +} + +impl AdtDef { + pub fn new<'db>(def_id: AdtId, interner: DbInterner<'db>) -> Self { + let db = interner.db(); + let (flags, variants, repr) = match def_id { + AdtId::StructId(struct_id) => { + let data = db.struct_signature(struct_id); + + let flags = AdtFlags { + is_enum: false, + is_union: false, + is_struct: true, + is_phantom_data: data.flags.contains(StructFlags::IS_PHANTOM_DATA), + is_fundamental: data.flags.contains(StructFlags::FUNDAMENTAL), + is_box: data.flags.contains(StructFlags::IS_BOX), + is_manually_drop: data.flags.contains(StructFlags::IS_MANUALLY_DROP), + }; + + let variants = vec![(VariantIdx(0), VariantDef::Struct(struct_id))]; + + let mut repr = ReprOptions::default(); + repr.align = data.repr.and_then(|r| r.align); + repr.pack = data.repr.and_then(|r| r.pack); + repr.int = data.repr.and_then(|r| r.int); + + let mut repr_flags = ReprFlags::empty(); + if flags.is_box { + repr_flags.insert(ReprFlags::IS_LINEAR); + } + if data.repr.is_some_and(|r| r.c()) { + repr_flags.insert(ReprFlags::IS_C); + } + if data.repr.is_some_and(|r| r.simd()) { + repr_flags.insert(ReprFlags::IS_SIMD); + } + repr.flags = repr_flags; + + (flags, variants, repr) + } + AdtId::UnionId(union_id) => { + let data = db.union_signature(union_id); + + let flags = AdtFlags { + is_enum: false, + is_union: true, + is_struct: false, + is_phantom_data: false, + is_fundamental: false, + is_box: false, + is_manually_drop: false, + }; + + let variants = vec![(VariantIdx(0), VariantDef::Union(union_id))]; + + let mut repr = ReprOptions::default(); + repr.align = data.repr.and_then(|r| r.align); + repr.pack = data.repr.and_then(|r| r.pack); + repr.int = data.repr.and_then(|r| r.int); + + let mut repr_flags = ReprFlags::empty(); + if flags.is_box { + repr_flags.insert(ReprFlags::IS_LINEAR); + } + if data.repr.is_some_and(|r| r.c()) { + repr_flags.insert(ReprFlags::IS_C); + } + if data.repr.is_some_and(|r| r.simd()) { + repr_flags.insert(ReprFlags::IS_SIMD); + } + repr.flags = repr_flags; + + (flags, variants, repr) + } + AdtId::EnumId(enum_id) => { + let flags = AdtFlags { + is_enum: true, + is_union: false, + is_struct: false, + is_phantom_data: false, + is_fundamental: false, + is_box: false, + is_manually_drop: false, + }; + + let variants = enum_id + .enum_variants(db) + .variants + .iter() + .enumerate() + .map(|(idx, v)| (VariantIdx(idx), v)) + .map(|(idx, v)| (idx, VariantDef::Enum(v.0))) + .collect(); + + let data = db.enum_signature(enum_id); + + let mut repr = ReprOptions::default(); + repr.align = data.repr.and_then(|r| r.align); + repr.pack = data.repr.and_then(|r| r.pack); + repr.int = data.repr.and_then(|r| r.int); + + let mut repr_flags = ReprFlags::empty(); + if flags.is_box { + repr_flags.insert(ReprFlags::IS_LINEAR); + } + if data.repr.is_some_and(|r| r.c()) { + repr_flags.insert(ReprFlags::IS_C); + } + if data.repr.is_some_and(|r| r.simd()) { + repr_flags.insert(ReprFlags::IS_SIMD); + } + repr.flags = repr_flags; + + (flags, variants, repr) + } + }; + + AdtDef::new_(db, AdtDefInner { id: def_id, variants, flags, repr }) + } + + pub fn inner(&self) -> &AdtDefInner { + salsa::with_attached_database(|db| { + let inner = self.data_(db); + // SAFETY: ¯\_(ツ)_/¯ + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + + pub fn is_enum(&self) -> bool { + self.inner().flags.is_enum + } + + #[inline] + pub fn repr(self) -> ReprOptions { + self.inner().repr + } + + /// Asserts this is a struct or union and returns its unique variant. + pub fn non_enum_variant(self) -> VariantDef { + assert!(self.inner().flags.is_struct || self.inner().flags.is_union); + self.inner().variants[0].1.clone() + } +} + +impl<'db> inherent::AdtDef> for AdtDef { + fn def_id(self) -> as rustc_type_ir::Interner>::DefId { + SolverDefId::AdtId(self.inner().id) + } + + fn is_struct(self) -> bool { + self.inner().flags.is_struct + } + + fn is_phantom_data(self) -> bool { + self.inner().flags.is_phantom_data + } + + fn is_fundamental(self) -> bool { + self.inner().flags.is_fundamental + } + + fn struct_tail_ty( + self, + interner: DbInterner<'db>, + ) -> Option< + rustc_type_ir::EarlyBinder< + DbInterner<'db>, + as rustc_type_ir::Interner>::Ty, + >, + > { + let db = interner.db(); + let hir_def::AdtId::StructId(struct_id) = self.inner().id else { + return None; + }; + let id: VariantId = struct_id.into(); + let field_types = interner.db().field_types_ns(id); + + field_types.iter().last().map(|f| *f.1) + } + + fn all_field_tys( + self, + interner: DbInterner<'db>, + ) -> rustc_type_ir::EarlyBinder< + DbInterner<'db>, + impl IntoIterator as rustc_type_ir::Interner>::Ty>, + > { + let db = interner.db(); + // FIXME: this is disabled just to match the behavior with chalk right now + let field_tys = |id: VariantId| { + let variant_data = id.fields(db); + let fields = if variant_data.fields().is_empty() { + vec![] + } else { + let field_types = db.field_types_ns(id); + variant_data + .fields() + .iter() + .map(|(idx, _)| { + let ty = field_types[idx]; + ty.skip_binder() + }) + .collect() + }; + }; + let field_tys = |id: VariantId| vec![]; + let tys: Vec<_> = match self.inner().id { + hir_def::AdtId::StructId(id) => field_tys(id.into()), + hir_def::AdtId::UnionId(id) => field_tys(id.into()), + hir_def::AdtId::EnumId(id) => id + .enum_variants(db) + .variants + .iter() + .flat_map(|&(variant_id, _, _)| field_tys(variant_id.into())) + .collect(), + }; + + rustc_type_ir::EarlyBinder::bind(tys) + } + + fn sizedness_constraint( + self, + interner: DbInterner<'db>, + sizedness: SizedTraitKind, + ) -> Option< + rustc_type_ir::EarlyBinder< + DbInterner<'db>, + as rustc_type_ir::Interner>::Ty, + >, + > { + if self.is_struct() { + let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; + + let constraint_ty = sizedness_constraint_for_ty(interner, sizedness, tail_ty)?; + + Some(EarlyBinder::bind(constraint_ty)) + } else { + None + } + } + + fn destructor( + self, + interner: DbInterner<'db>, + ) -> Option { + // FIXME(next-solver) + None + } + + fn is_manually_drop(self) -> bool { + self.inner().flags.is_manually_drop + } +} + +impl fmt::Debug for AdtDef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + salsa::with_attached_database(|db| match self.inner().id { + AdtId::StructId(struct_id) => { + let data = db.as_view::().struct_signature(struct_id); + f.write_str(data.name.as_str()) + } + AdtId::UnionId(union_id) => { + let data = db.as_view::().union_signature(union_id); + f.write_str(data.name.as_str()) + } + AdtId::EnumId(enum_id) => { + let data = db.as_view::().enum_signature(enum_id); + f.write_str(data.name.as_str()) + } + }) + .unwrap_or_else(|| f.write_str(&format!("AdtDef({:?})", self.inner().id))) + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Features; + +impl<'db> inherent::Features> for Features { + fn generic_const_exprs(self) -> bool { + false + } + + fn coroutine_clone(self) -> bool { + false + } + + fn associated_const_equality(self) -> bool { + false + } + + fn feature_bound_holds_in_crate(self, symbol: ()) -> bool { + false + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct UnsizingParams(pub(crate) DenseBitSet); + +impl std::ops::Deref for UnsizingParams { + type Target = DenseBitSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub type PatternKind<'db> = rustc_type_ir::PatternKind>; + +#[salsa::interned(constructor = new_, debug)] +pub struct Pattern<'db> { + #[returns(ref)] + kind_: InternedWrapperNoDebug>, +} + +impl<'db> std::fmt::Debug for InternedWrapperNoDebug> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl<'db> Pattern<'db> { + pub fn new(interner: DbInterner<'db>, kind: PatternKind<'db>) -> Self { + Pattern::new_(interner.db(), InternedWrapperNoDebug(kind)) + } + + pub fn inner(&self) -> &PatternKind<'db> { + salsa::with_attached_database(|db| { + let inner = &self.kind_(db).0; + // SAFETY: The caller already has access to a `Ty<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } +} + +impl<'db> Flags for Pattern<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + match self.inner() { + PatternKind::Range { start, end } => { + FlagComputation::for_const_kind(&start.kind()).flags + | FlagComputation::for_const_kind(&end.kind()).flags + } + PatternKind::Or(pats) => { + let mut flags = pats.as_slice()[0].flags(); + for pat in pats.as_slice()[1..].iter() { + flags |= pat.flags(); + } + flags + } + } + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + match self.inner() { + PatternKind::Range { start, end } => { + start.outer_exclusive_binder().max(end.outer_exclusive_binder()) + } + PatternKind::Or(pats) => { + let mut idx = pats.as_slice()[0].outer_exclusive_binder(); + for pat in pats.as_slice()[1..].iter() { + idx = idx.max(pat.outer_exclusive_binder()); + } + idx + } + } + } +} + +impl<'db> rustc_type_ir::inherent::IntoKind for Pattern<'db> { + type Kind = rustc_type_ir::PatternKind>; + fn kind(self) -> Self::Kind { + *self.inner() + } +} + +impl<'db> rustc_type_ir::relate::Relate> for Pattern<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + let tcx = relation.cx(); + match (a.kind(), b.kind()) { + ( + PatternKind::Range { start: start_a, end: end_a }, + PatternKind::Range { start: start_b, end: end_b }, + ) => { + let start = relation.relate(start_a, start_b)?; + let end = relation.relate(end_a, end_b)?; + Ok(Pattern::new(tcx, PatternKind::Range { start, end })) + } + (PatternKind::Or(a), PatternKind::Or(b)) => { + if a.len() != b.len() { + return Err(TypeError::Mismatch); + } + let pats = CollectAndApply::collect_and_apply( + std::iter::zip(a.iter(), b.iter()).map(|(a, b)| relation.relate(a, b)), + |g| PatList::new_from_iter(tcx, g.iter().cloned()), + )?; + Ok(Pattern::new(tcx, PatternKind::Or(pats))) + } + (PatternKind::Range { .. } | PatternKind::Or(_), _) => Err(TypeError::Mismatch), + } + } +} + +interned_vec_db!(PatList, Pattern); + +impl<'db> rustc_type_ir::Interner for DbInterner<'db> { + type DefId = SolverDefId; + type LocalDefId = SolverDefId; + type LocalDefIds = SolverDefIds; + type Span = Span; + + type GenericArgs = GenericArgs<'db>; + type GenericArgsSlice = GenericArgs<'db>; + type GenericArg = GenericArg<'db>; + + type Term = Term<'db>; + + type BoundVarKinds = BoundVarKinds; + type BoundVarKind = BoundVarKind; + + type PredefinedOpaques = PredefinedOpaques<'db>; + + fn mk_predefined_opaques_in_body( + self, + data: rustc_type_ir::solve::PredefinedOpaquesData, + ) -> Self::PredefinedOpaques { + PredefinedOpaques::new(self, data) + } + + type CanonicalVarKinds = CanonicalVars<'db>; + + fn mk_canonical_var_kinds( + self, + kinds: &[rustc_type_ir::CanonicalVarKind], + ) -> Self::CanonicalVarKinds { + CanonicalVars::new_from_iter(self, kinds.iter().cloned()) + } + + type ExternalConstraints = ExternalConstraints<'db>; + + fn mk_external_constraints( + self, + data: rustc_type_ir::solve::ExternalConstraintsData, + ) -> Self::ExternalConstraints { + ExternalConstraints::new(self, data) + } + + type DepNodeIndex = DepNodeIndex; + + type Tracked = Tracked; + + type Ty = Ty<'db>; + type Tys = Tys<'db>; + type FnInputTys = Tys<'db>; + type ParamTy = ParamTy; + type BoundTy = BoundTy; + type PlaceholderTy = PlaceholderTy; + type Symbol = (); + + type ErrorGuaranteed = ErrorGuaranteed; + type BoundExistentialPredicates = BoundExistentialPredicates<'db>; + type AllocId = AllocId; + type Pat = Pattern<'db>; + type PatList = PatList<'db>; + type Safety = Safety; + type Abi = FnAbi; + + type Const = Const<'db>; + type PlaceholderConst = PlaceholderConst; + type ParamConst = ParamConst; + type BoundConst = rustc_type_ir::BoundVar; + type ValueConst = ValueConst<'db>; + type ValTree = Valtree<'db>; + type ExprConst = ExprConst; + + type Region = Region<'db>; + type EarlyParamRegion = EarlyParamRegion; + type LateParamRegion = LateParamRegion; + type BoundRegion = BoundRegion; + type PlaceholderRegion = PlaceholderRegion; + + type RegionAssumptions = RegionAssumptions<'db>; + + type ParamEnv = ParamEnv<'db>; + type Predicate = Predicate<'db>; + type Clause = Clause<'db>; + type Clauses = Clauses<'db>; + + type GenericsOf = Generics; + + type VariancesOf = VariancesOf; + + type AdtDef = AdtDef; + + type Features = Features; + + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { + GenericArgs::new_from_iter(self, args.iter().cloned()) + } + + fn mk_args_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: rustc_type_ir::CollectAndApply, + { + CollectAndApply::collect_and_apply(args, |g| { + GenericArgs::new_from_iter(self, g.iter().cloned()) + }) + } + + type UnsizingParams = UnsizingParams; + + fn mk_tracked( + self, + data: T, + dep_node: Self::DepNodeIndex, + ) -> Self::Tracked { + Tracked(data) + } + + fn get_tracked(self, tracked: &Self::Tracked) -> T { + tracked.0.clone() + } + + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex) { + (task(), DepNodeIndex) + } + + fn with_global_cache( + self, + f: impl FnOnce(&mut rustc_type_ir::search_graph::GlobalCache) -> R, + ) -> R { + salsa::with_attached_database(|db| { + tls_cache::with_cache( + unsafe { + std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>( + db.as_view::(), + ) + }, + f, + ) + }) + .unwrap() + } + + fn canonical_param_env_cache_get_or_insert( + self, + param_env: Self::ParamEnv, + f: impl FnOnce() -> rustc_type_ir::CanonicalParamEnvCacheEntry, + from_entry: impl FnOnce(&rustc_type_ir::CanonicalParamEnvCacheEntry) -> R, + ) -> R { + from_entry(&f()) + } + + fn evaluation_is_concurrent(&self) -> bool { + false + } + + fn expand_abstract_consts>(self, t: T) -> T { + t + } + + fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf { + generics(self.db(), def_id) + } + + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + match def_id { + SolverDefId::FunctionId(def_id) => VariancesOf::new_from_iter( + self, + self.db() + .variances_of(hir_def::GenericDefId::FunctionId(def_id)) + .as_deref() + .unwrap_or_default() + .iter() + .map(|v| v.to_nextsolver(self)), + ), + SolverDefId::AdtId(def_id) => VariancesOf::new_from_iter( + self, + self.db() + .variances_of(hir_def::GenericDefId::AdtId(def_id)) + .as_deref() + .unwrap_or_default() + .iter() + .map(|v| v.to_nextsolver(self)), + ), + SolverDefId::InternedOpaqueTyId(_def_id) => { + // FIXME(next-solver): track variances + VariancesOf::new_from_iter( + self, + (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant), + ) + } + _ => VariancesOf::new_from_iter(self, []), + } + } + + fn type_of(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder { + let def_id = match def_id { + SolverDefId::TypeAliasId(id) => { + use hir_def::Lookup; + match id.lookup(self.db()).container { + ItemContainerId::ImplId(it) => it, + _ => panic!("assoc ty value should be in impl"), + }; + crate::TyDefId::TypeAliasId(id) + } + SolverDefId::AdtId(id) => crate::TyDefId::AdtId(id), + _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), + }; + self.db().ty_ns(def_id) + } + + fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef { + let def_id = match adt_def_id { + SolverDefId::AdtId(adt_id) => adt_id, + _ => panic!("Invalid DefId passed to adt_def"), + }; + AdtDef::new(def_id, self) + } + + fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> rustc_type_ir::AliasTyKind { + // FIXME: not currently creating any others + rustc_type_ir::AliasTyKind::Projection + } + + fn alias_term_kind( + self, + alias: rustc_type_ir::AliasTerm, + ) -> rustc_type_ir::AliasTermKind { + match alias.def_id { + SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, + SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, + SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, + _ => unreachable!("Unexpected alias: {:?}", alias.def_id), + } + } + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + let trait_def_id = self.parent(def_id); + let trait_generics = self.generics_of(trait_def_id); + let trait_args = GenericArgs::new_from_iter( + self, + args.as_slice()[0..trait_generics.own_params.len()].iter().cloned(), + ); + let alias_args = + GenericArgs::new_from_iter(self, args.iter().skip(trait_generics.own_params.len())); + (TraitRef::new_from_args(self, trait_def_id, trait_args), alias_args) + } + + fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool { + // FIXME + true + } + + fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) {} + + fn debug_assert_existential_args_compatible( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) { + } + + fn mk_type_list_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: rustc_type_ir::CollectAndApply, + { + CollectAndApply::collect_and_apply(args, |g| Tys::new_from_iter(self, g.iter().cloned())) + } + + fn parent(self, def_id: Self::DefId) -> Self::DefId { + use hir_def::Lookup; + + let container = match def_id { + SolverDefId::FunctionId(it) => it.lookup(self.db()).container, + SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container, + SolverDefId::ForeignId(it) => it.lookup(self.db()).container, + SolverDefId::ConstId(it) => it.lookup(self.db()).container, + SolverDefId::InternedClosureId(it) => { + return self + .db() + .lookup_intern_closure(it) + .0 + .as_generic_def_id(self.db()) + .unwrap() + .into(); + } + SolverDefId::InternedCoroutineId(it) => { + return self + .db() + .lookup_intern_coroutine(it) + .0 + .as_generic_def_id(self.db()) + .unwrap() + .into(); + } + SolverDefId::StaticId(_) + | SolverDefId::AdtId(_) + | SolverDefId::TraitId(_) + | SolverDefId::ImplId(_) + | SolverDefId::TraitAliasId(_) + | SolverDefId::Ctor(..) + | SolverDefId::InternedOpaqueTyId(..) => panic!(), + }; + + match container { + ItemContainerId::ImplId(it) => it.into(), + ItemContainerId::TraitId(it) => it.into(), + ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => panic!(), + } + } + + fn recursion_limit(self) -> usize { + 50 + } + + fn features(self) -> Self::Features { + Features + } + + fn fn_sig( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder>> + { + let id = match def_id { + SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), + SolverDefId::Ctor(ctor) => match ctor { + super::Ctor::Struct(struct_id) => CallableDefId::StructId(struct_id), + super::Ctor::Enum(enum_variant_id) => CallableDefId::EnumVariantId(enum_variant_id), + }, + def => unreachable!("{:?}", def), + }; + self.db().callable_item_signature_ns(id) + } + + fn coroutine_movability(self, def_id: Self::DefId) -> rustc_ast_ir::Movability { + unimplemented!() + } + + fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId { + unimplemented!() + } + + fn generics_require_sized_self(self, def_id: Self::DefId) -> bool { + let sized_trait = + LangItem::Sized.resolve_trait(self.db(), self.krate.expect("Must have self.krate")); + let Some(sized_id) = sized_trait else { + return false; /* No Sized trait, can't require it! */ + }; + let sized_def_id = sized_id.into(); + + // Search for a predicate like `Self : Sized` amongst the trait bounds. + let predicates = self.predicates_of(def_id); + elaborate(self, predicates.iter_identity()).any(|pred| match pred.kind().skip_binder() { + ClauseKind::Trait(ref trait_pred) => { + trait_pred.def_id() == sized_def_id + && matches!( + trait_pred.self_ty().kind(), + TyKind::Param(ParamTy { index: 0, .. }) + ) + } + ClauseKind::RegionOutlives(_) + | ClauseKind::TypeOutlives(_) + | ClauseKind::Projection(_) + | ClauseKind::ConstArgHasType(_, _) + | ClauseKind::WellFormed(_) + | ClauseKind::ConstEvaluatable(_) + | ClauseKind::HostEffect(..) + | ClauseKind::UnstableFeature(_) => false, + }) + } + + #[tracing::instrument(skip(self), ret)] + fn item_bounds( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + explicit_item_bounds(self, def_id).map_bound(|bounds| { + Clauses::new_from_iter(self, elaborate(self, bounds).collect::>()) + }) + } + + #[tracing::instrument(skip(self), ret)] + fn item_self_bounds( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + explicit_item_bounds(self, def_id).map_bound(|bounds| { + Clauses::new_from_iter( + self, + elaborate(self, bounds).filter_only_self().collect::>(), + ) + }) + } + + fn item_non_self_bounds( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + let all_bounds: FxHashSet<_> = self.item_bounds(def_id).skip_binder().into_iter().collect(); + let own_bounds: FxHashSet<_> = + self.item_self_bounds(def_id).skip_binder().into_iter().collect(); + if all_bounds.len() == own_bounds.len() { + EarlyBinder::bind(Clauses::new_from_iter(self, [])) + } else { + EarlyBinder::bind(Clauses::new_from_iter( + self, + all_bounds.difference(&own_bounds).cloned(), + )) + } + } + + #[tracing::instrument(level = "debug", skip(self), ret)] + fn predicates_of( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap()); + let predicates: Vec<_> = predicates.iter().cloned().collect(); + EarlyBinder::bind(predicates.into_iter()) + } + + #[tracing::instrument(level = "debug", skip(self), ret)] + fn own_predicates_of( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap()); + let predicates: Vec<_> = predicates.iter().cloned().collect(); + EarlyBinder::bind(predicates.into_iter()) + } + + #[tracing::instrument(skip(self), ret)] + fn explicit_super_predicates_of( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> + { + let predicates: Vec<(Clause<'db>, Span)> = self + .db() + .generic_predicates_ns(def_id.try_into().unwrap()) + .iter() + .cloned() + .map(|p| (p, Span::dummy())) + .collect(); + rustc_type_ir::EarlyBinder::bind(predicates) + } + + #[tracing::instrument(skip(self), ret)] + fn explicit_implied_predicates_of( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> + { + let predicates: Vec<(Clause<'db>, Span)> = self + .db() + .generic_predicates_ns(def_id.try_into().unwrap()) + .iter() + .cloned() + .map(|p| (p, Span::dummy())) + .collect(); + rustc_type_ir::EarlyBinder::bind(predicates) + } + + fn impl_super_outlives( + self, + impl_def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + let impl_id = match impl_def_id { + SolverDefId::ImplId(id) => id, + _ => unreachable!(), + }; + let trait_ref = self.db().impl_trait_ns(impl_id).expect("expected an impl of trait"); + trait_ref.map_bound(|trait_ref| { + let clause: Clause<'_> = trait_ref.upcast(self); + Clauses::new_from_iter( + self, + rustc_type_ir::elaborate::elaborate(self, [clause]).filter(|clause| { + matches!( + clause.kind().skip_binder(), + ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_) + ) + }), + ) + }) + } + + fn const_conditions( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder< + Self, + impl IntoIterator>>, + > { + rustc_type_ir::EarlyBinder::bind([unimplemented!()]) + } + + fn has_target_features(self, def_id: Self::DefId) -> bool { + false + } + + fn require_lang_item( + self, + lang_item: rustc_type_ir::lang_items::TraitSolverLangItem, + ) -> Self::DefId { + let lang_item = match lang_item { + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFn => LangItem::AsyncFn, + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnKindHelper => unimplemented!(), + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnKindUpvars => unimplemented!(), + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnMut => LangItem::AsyncFnMut, + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnOnce => LangItem::AsyncFnOnce, + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncFnOnceOutput => { + LangItem::AsyncFnOnceOutput + } + rustc_type_ir::lang_items::TraitSolverLangItem::AsyncIterator => unimplemented!(), + rustc_type_ir::lang_items::TraitSolverLangItem::CallOnceFuture => { + LangItem::CallOnceFuture + } + rustc_type_ir::lang_items::TraitSolverLangItem::CallRefFuture => { + LangItem::CallRefFuture + } + rustc_type_ir::lang_items::TraitSolverLangItem::Clone => LangItem::Clone, + rustc_type_ir::lang_items::TraitSolverLangItem::Copy => LangItem::Copy, + rustc_type_ir::lang_items::TraitSolverLangItem::Coroutine => LangItem::Coroutine, + rustc_type_ir::lang_items::TraitSolverLangItem::CoroutineReturn => { + LangItem::CoroutineReturn + } + rustc_type_ir::lang_items::TraitSolverLangItem::CoroutineYield => { + LangItem::CoroutineYield + } + rustc_type_ir::lang_items::TraitSolverLangItem::Destruct => LangItem::Destruct, + rustc_type_ir::lang_items::TraitSolverLangItem::DiscriminantKind => { + LangItem::DiscriminantKind + } + rustc_type_ir::lang_items::TraitSolverLangItem::Drop => LangItem::Drop, + rustc_type_ir::lang_items::TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + rustc_type_ir::lang_items::TraitSolverLangItem::Fn => LangItem::Fn, + rustc_type_ir::lang_items::TraitSolverLangItem::FnMut => LangItem::FnMut, + rustc_type_ir::lang_items::TraitSolverLangItem::FnOnce => LangItem::FnOnce, + rustc_type_ir::lang_items::TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, + rustc_type_ir::lang_items::TraitSolverLangItem::FusedIterator => unimplemented!(), + rustc_type_ir::lang_items::TraitSolverLangItem::Future => LangItem::Future, + rustc_type_ir::lang_items::TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, + rustc_type_ir::lang_items::TraitSolverLangItem::Iterator => LangItem::Iterator, + rustc_type_ir::lang_items::TraitSolverLangItem::Metadata => LangItem::Metadata, + rustc_type_ir::lang_items::TraitSolverLangItem::Option => LangItem::Option, + rustc_type_ir::lang_items::TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, + rustc_type_ir::lang_items::TraitSolverLangItem::Poll => LangItem::Poll, + rustc_type_ir::lang_items::TraitSolverLangItem::Sized => LangItem::Sized, + rustc_type_ir::lang_items::TraitSolverLangItem::MetaSized => LangItem::MetaSized, + rustc_type_ir::lang_items::TraitSolverLangItem::PointeeSized => LangItem::PointeeSized, + rustc_type_ir::lang_items::TraitSolverLangItem::TransmuteTrait => { + LangItem::TransmuteTrait + } + rustc_type_ir::lang_items::TraitSolverLangItem::Tuple => LangItem::Tuple, + rustc_type_ir::lang_items::TraitSolverLangItem::Unpin => LangItem::Unpin, + rustc_type_ir::lang_items::TraitSolverLangItem::Unsize => LangItem::Unsize, + rustc_type_ir::lang_items::TraitSolverLangItem::BikeshedGuaranteedNoDrop => { + unimplemented!() + } + }; + let target = hir_def::lang_item::lang_item( + self.db(), + self.krate.expect("Must have self.krate"), + lang_item, + ) + .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")); + match target { + hir_def::lang_item::LangItemTarget::EnumId(enum_id) => enum_id.into(), + hir_def::lang_item::LangItemTarget::Function(function_id) => function_id.into(), + hir_def::lang_item::LangItemTarget::ImplDef(impl_id) => impl_id.into(), + hir_def::lang_item::LangItemTarget::Static(static_id) => static_id.into(), + hir_def::lang_item::LangItemTarget::Struct(struct_id) => struct_id.into(), + hir_def::lang_item::LangItemTarget::Union(union_id) => union_id.into(), + hir_def::lang_item::LangItemTarget::TypeAlias(type_alias_id) => type_alias_id.into(), + hir_def::lang_item::LangItemTarget::Trait(trait_id) => trait_id.into(), + hir_def::lang_item::LangItemTarget::EnumVariant(enum_variant_id) => unimplemented!(), + } + } + + #[allow(clippy::match_like_matches_macro)] + fn is_lang_item( + self, + def_id: Self::DefId, + lang_item: rustc_type_ir::lang_items::TraitSolverLangItem, + ) -> bool { + use rustc_type_ir::lang_items::TraitSolverLangItem::*; + + // FIXME: derive PartialEq on TraitSolverLangItem + self.as_lang_item(def_id).map_or(false, |l| match (l, lang_item) { + (AsyncFn, AsyncFn) => true, + (AsyncFnKindHelper, AsyncFnKindHelper) => true, + (AsyncFnKindUpvars, AsyncFnKindUpvars) => true, + (AsyncFnMut, AsyncFnMut) => true, + (AsyncFnOnce, AsyncFnOnce) => true, + (AsyncFnOnceOutput, AsyncFnOnceOutput) => true, + (AsyncIterator, AsyncIterator) => true, + (CallOnceFuture, CallOnceFuture) => true, + (CallRefFuture, CallRefFuture) => true, + (Clone, Clone) => true, + (Copy, Copy) => true, + (Coroutine, Coroutine) => true, + (CoroutineReturn, CoroutineReturn) => true, + (CoroutineYield, CoroutineYield) => true, + (Destruct, Destruct) => true, + (DiscriminantKind, DiscriminantKind) => true, + (Drop, Drop) => true, + (DynMetadata, DynMetadata) => true, + (Fn, Fn) => true, + (FnMut, FnMut) => true, + (FnOnce, FnOnce) => true, + (FnPtrTrait, FnPtrTrait) => true, + (FusedIterator, FusedIterator) => true, + (Future, Future) => true, + (FutureOutput, FutureOutput) => true, + (Iterator, Iterator) => true, + (Metadata, Metadata) => true, + (Option, Option) => true, + (PointeeTrait, PointeeTrait) => true, + (Poll, Poll) => true, + (Sized, Sized) => true, + (TransmuteTrait, TransmuteTrait) => true, + (Tuple, Tuple) => true, + (Unpin, Unpin) => true, + (Unsize, Unsize) => true, + _ => false, + }) + } + + fn as_lang_item( + self, + def_id: Self::DefId, + ) -> Option { + use rustc_type_ir::lang_items::TraitSolverLangItem; + + let def_id: AttrDefId = match def_id { + SolverDefId::TraitId(id) => id.into(), + SolverDefId::TypeAliasId(id) => id.into(), + _ => panic!("Unexpected SolverDefId in as_lang_item"), + }; + let lang_item = self.db().lang_attr(def_id)?; + Some(match lang_item { + LangItem::Sized => TraitSolverLangItem::Sized, + LangItem::MetaSized => TraitSolverLangItem::MetaSized, + LangItem::PointeeSized => TraitSolverLangItem::PointeeSized, + LangItem::Unsize => TraitSolverLangItem::Unsize, + LangItem::StructuralPeq => return None, + LangItem::StructuralTeq => return None, + LangItem::Copy => TraitSolverLangItem::Copy, + LangItem::Clone => TraitSolverLangItem::Clone, + LangItem::Sync => return None, + LangItem::DiscriminantKind => TraitSolverLangItem::DiscriminantKind, + LangItem::Discriminant => return None, + LangItem::PointeeTrait => TraitSolverLangItem::PointeeTrait, + LangItem::Metadata => TraitSolverLangItem::Metadata, + LangItem::DynMetadata => TraitSolverLangItem::DynMetadata, + LangItem::Freeze => return None, + LangItem::FnPtrTrait => TraitSolverLangItem::FnPtrTrait, + LangItem::FnPtrAddr => return None, + LangItem::Drop => TraitSolverLangItem::Drop, + LangItem::Destruct => TraitSolverLangItem::Destruct, + LangItem::CoerceUnsized => return None, + LangItem::DispatchFromDyn => return None, + LangItem::TransmuteOpts => return None, + LangItem::TransmuteTrait => TraitSolverLangItem::TransmuteTrait, + LangItem::Add => return None, + LangItem::Sub => return None, + LangItem::Mul => return None, + LangItem::Div => return None, + LangItem::Rem => return None, + LangItem::Neg => return None, + LangItem::Not => return None, + LangItem::BitXor => return None, + LangItem::BitAnd => return None, + LangItem::BitOr => return None, + LangItem::Shl => return None, + LangItem::Shr => return None, + LangItem::AddAssign => return None, + LangItem::SubAssign => return None, + LangItem::MulAssign => return None, + LangItem::DivAssign => return None, + LangItem::RemAssign => return None, + LangItem::BitXorAssign => return None, + LangItem::BitAndAssign => return None, + LangItem::BitOrAssign => return None, + LangItem::ShlAssign => return None, + LangItem::ShrAssign => return None, + LangItem::Index => return None, + LangItem::IndexMut => return None, + LangItem::UnsafeCell => return None, + LangItem::VaList => return None, + LangItem::Deref => return None, + LangItem::DerefMut => return None, + LangItem::DerefTarget => return None, + LangItem::Receiver => return None, + LangItem::Fn => TraitSolverLangItem::Fn, + LangItem::FnMut => TraitSolverLangItem::FnMut, + LangItem::FnOnce => TraitSolverLangItem::FnOnce, + LangItem::FnOnceOutput => return None, + LangItem::Future => TraitSolverLangItem::Future, + LangItem::CoroutineState => return None, + LangItem::Coroutine => TraitSolverLangItem::Coroutine, + LangItem::CoroutineReturn => TraitSolverLangItem::CoroutineReturn, + LangItem::CoroutineYield => TraitSolverLangItem::CoroutineYield, + LangItem::Unpin => TraitSolverLangItem::Unpin, + LangItem::Pin => return None, + LangItem::PartialEq => return None, + LangItem::PartialOrd => return None, + LangItem::CVoid => return None, + LangItem::Panic => return None, + LangItem::PanicNounwind => return None, + LangItem::PanicFmt => return None, + LangItem::PanicDisplay => return None, + LangItem::ConstPanicFmt => return None, + LangItem::PanicBoundsCheck => return None, + LangItem::PanicMisalignedPointerDereference => return None, + LangItem::PanicInfo => return None, + LangItem::PanicLocation => return None, + LangItem::PanicImpl => return None, + LangItem::PanicCannotUnwind => return None, + LangItem::BeginPanic => return None, + LangItem::FormatAlignment => return None, + LangItem::FormatArgument => return None, + LangItem::FormatArguments => return None, + LangItem::FormatCount => return None, + LangItem::FormatPlaceholder => return None, + LangItem::FormatUnsafeArg => return None, + LangItem::ExchangeMalloc => return None, + LangItem::BoxFree => return None, + LangItem::DropInPlace => return None, + LangItem::AllocLayout => return None, + LangItem::Start => return None, + LangItem::EhPersonality => return None, + LangItem::EhCatchTypeinfo => return None, + LangItem::OwnedBox => return None, + LangItem::PhantomData => return None, + LangItem::ManuallyDrop => return None, + LangItem::MaybeUninit => return None, + LangItem::AlignOffset => return None, + LangItem::Termination => return None, + LangItem::Try => return None, + LangItem::Tuple => TraitSolverLangItem::Tuple, + LangItem::SliceLen => return None, + LangItem::TryTraitFromResidual => return None, + LangItem::TryTraitFromOutput => return None, + LangItem::TryTraitBranch => return None, + LangItem::TryTraitFromYeet => return None, + LangItem::PointerLike => return None, + LangItem::ConstParamTy => return None, + LangItem::Poll => TraitSolverLangItem::Poll, + LangItem::PollReady => return None, + LangItem::PollPending => return None, + LangItem::ResumeTy => return None, + LangItem::GetContext => return None, + LangItem::Context => return None, + LangItem::FuturePoll => return None, + LangItem::FutureOutput => TraitSolverLangItem::FutureOutput, + LangItem::Option => TraitSolverLangItem::Option, + LangItem::OptionSome => return None, + LangItem::OptionNone => return None, + LangItem::ResultOk => return None, + LangItem::ResultErr => return None, + LangItem::ControlFlowContinue => return None, + LangItem::ControlFlowBreak => return None, + LangItem::IntoFutureIntoFuture => return None, + LangItem::IntoIterIntoIter => return None, + LangItem::IteratorNext => return None, + LangItem::Iterator => TraitSolverLangItem::Iterator, + LangItem::PinNewUnchecked => return None, + LangItem::RangeFrom => return None, + LangItem::RangeFull => return None, + LangItem::RangeInclusiveStruct => return None, + LangItem::RangeInclusiveNew => return None, + LangItem::Range => return None, + LangItem::RangeToInclusive => return None, + LangItem::RangeTo => return None, + LangItem::String => return None, + LangItem::CStr => return None, + LangItem::AsyncFn => TraitSolverLangItem::AsyncFn, + LangItem::AsyncFnMut => TraitSolverLangItem::AsyncFnMut, + LangItem::AsyncFnOnce => TraitSolverLangItem::AsyncFnOnce, + LangItem::AsyncFnOnceOutput => TraitSolverLangItem::AsyncFnOnceOutput, + LangItem::CallRefFuture => TraitSolverLangItem::CallRefFuture, + LangItem::CallOnceFuture => TraitSolverLangItem::CallOnceFuture, + LangItem::Ordering => return None, + LangItem::PanicNullPointerDereference => return None, + LangItem::ReceiverTarget => return None, + LangItem::UnsafePinned => return None, + LangItem::AsyncFnOnceOutput => TraitSolverLangItem::AsyncFnOnceOutput, + }) + } + + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator { + let trait_ = match def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + trait_.trait_items(self.db()).associated_types().map(|id| id.into()) + } + + fn for_each_relevant_impl( + self, + trait_def_id: Self::DefId, + self_ty: Self::Ty, + mut f: impl FnMut(Self::DefId), + ) { + let trait_ = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("for_each_relevant_impl called for non-trait"), + }; + + let self_ty_fp = TyFingerprint::for_trait_impl_ns(&self_ty); + let fps: &[TyFingerprint] = match self_ty.kind() { + TyKind::Infer(InferTy::IntVar(..)) => &ALL_INT_FPS, + TyKind::Infer(InferTy::FloatVar(..)) => &ALL_FLOAT_FPS, + _ => self_ty_fp.as_slice(), + }; + + if fps.is_empty() { + for_trait_impls( + self.db(), + self.krate.expect("Must have self.krate"), + self.block, + trait_, + self_ty_fp, + |impls| { + for i in impls.for_trait(trait_) { + use rustc_type_ir::TypeVisitable; + let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| { + b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() + }); + if contains_errors { + continue; + } + + f(SolverDefId::ImplId(i)); + } + ControlFlow::Continue(()) + }, + ); + } else { + for_trait_impls( + self.db(), + self.krate.expect("Must have self.krate"), + self.block, + trait_, + self_ty_fp, + |impls| { + for fp in fps { + for i in impls.for_trait_and_self_ty(trait_, *fp) { + use rustc_type_ir::TypeVisitable; + let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| { + b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() + }); + if contains_errors { + continue; + } + + f(SolverDefId::ImplId(i)); + } + } + ControlFlow::Continue(()) + }, + ); + } + } + + fn has_item_definition(self, def_id: Self::DefId) -> bool { + // FIXME: should check if has value + true + } + + fn impl_is_default(self, impl_def_id: Self::DefId) -> bool { + // FIXME + false + } + + #[tracing::instrument(skip(self), ret)] + fn impl_trait_ref( + self, + impl_def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder> { + let impl_id = match impl_def_id { + SolverDefId::ImplId(id) => id, + _ => panic!("Unexpected SolverDefId in impl_trait_ref"), + }; + + let db = self.db(); + + db.impl_trait_ns(impl_id) + // ImplIds for impls where the trait ref can't be resolved should never reach trait solving + .expect("invalid impl passed to trait solver") + } + + fn impl_polarity(self, impl_def_id: Self::DefId) -> rustc_type_ir::ImplPolarity { + let impl_id = match impl_def_id { + SolverDefId::ImplId(id) => id, + _ => unreachable!(), + }; + let impl_data = self.db().impl_signature(impl_id); + if impl_data.flags.contains(ImplFlags::NEGATIVE) { + ImplPolarity::Negative + } else { + ImplPolarity::Positive + } + } + + fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool { + let trait_ = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("Unexpected SolverDefId in trait_is_auto"), + }; + let trait_data = self.db().trait_signature(trait_); + trait_data.flags.contains(TraitFlags::AUTO) + } + + fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool { + matches!(trait_def_id, SolverDefId::TraitAliasId(_)) + } + + fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool { + let trait_ = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + crate::dyn_compatibility::dyn_compatibility(self.db(), trait_).is_none() + } + + fn trait_is_fundamental(self, def_id: Self::DefId) -> bool { + let trait_ = match def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("Unexpected SolverDefId in trait_is_fundamental"), + }; + let trait_data = self.db().trait_signature(trait_); + trait_data.flags.contains(TraitFlags::FUNDAMENTAL) + } + + fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool { + // FIXME(next-solver) + true + } + + fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool { + // FIXME(next-solver) + false + } + + fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed { + panic!("Bug encountered in next-trait-solver.") + } + + fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool { + // FIXME(next-solver) + true + } + + fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool { + // FIXME(next-solver) + true + } + + fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool { + // FIXME(next-solver) + false + } + + fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool { + // FIXME(next-solver) + false + } + + fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams { + let id = match adt_def_id { + SolverDefId::AdtId(id) => id, + _ => unreachable!(), + }; + let def = AdtDef::new(id, self); + let num_params = self.generics_of(adt_def_id).count(); + + let maybe_unsizing_param_idx = |arg: GenericArg<'db>| match arg.kind() { + GenericArgKind::Type(ty) => match ty.kind() { + rustc_type_ir::TyKind::Param(p) => Some(p.index), + _ => None, + }, + GenericArgKind::Lifetime(_) => None, + GenericArgKind::Const(ct) => match ct.kind() { + rustc_type_ir::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // The last field of the structure has to exist and contain type/const parameters. + let variant = def.non_enum_variant(); + let fields = variant.fields(self.db()); + let Some((tail_field, prefix_fields)) = fields.split_last() else { + return UnsizingParams(DenseBitSet::new_empty(num_params)); + }; + + let field_types = self.db().field_types_ns(variant.id()); + let mut unsizing_params = DenseBitSet::new_empty(num_params); + let ty = field_types[tail_field.0]; + for arg in ty.instantiate_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + } + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in field_types[field.0].instantiate_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.remove(i); + } + } + } + + UnsizingParams(unsizing_params) + } + + fn anonymize_bound_vars>( + self, + value: rustc_type_ir::Binder, + ) -> rustc_type_ir::Binder { + struct Anonymize<'a, 'db> { + interner: DbInterner<'db>, + map: &'a mut FxIndexMap, + } + impl<'db> BoundVarReplacerDelegate<'db> for Anonymize<'_, 'db> { + fn replace_region(&mut self, br: BoundRegion) -> Region<'db> { + let entry = self.map.entry(br.var); + let index = entry.index(); + let var = BoundVar::from_usize(index); + let kind = (*entry.or_insert_with(|| BoundVarKind::Region(BoundRegionKind::Anon))) + .expect_region(); + let br = BoundRegion { var, kind }; + Region::new_bound(self.interner, DebruijnIndex::ZERO, br) + } + fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { + let entry = self.map.entry(bt.var); + let index = entry.index(); + let var = BoundVar::from_usize(index); + let kind = + (*entry.or_insert_with(|| BoundVarKind::Ty(BoundTyKind::Anon))).expect_ty(); + Ty::new_bound(self.interner, DebruijnIndex::ZERO, BoundTy { var, kind }) + } + fn replace_const(&mut self, bv: BoundVar) -> Const<'db> { + let entry = self.map.entry(bv); + let index = entry.index(); + let var = BoundVar::from_usize(index); + let () = (*entry.or_insert_with(|| BoundVarKind::Const)).expect_const(); + Const::new_bound(self.interner, DebruijnIndex::ZERO, var) + } + } + + let mut map = Default::default(); + let delegate = Anonymize { interner: self, map: &mut map }; + let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate); + let bound_vars = CollectAndApply::collect_and_apply(map.into_values(), |xs| { + BoundVarKinds::new_from_iter(self, xs.iter().cloned()) + }); + Binder::bind_with_vars(inner, bound_vars) + } + + fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { + // FIXME(next-solver) + SolverDefIds::new_from_iter(self, []) + } + + fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool { + // FIXME(next-solver) + false + } + + fn explicit_implied_const_bounds( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder< + Self, + impl IntoIterator>>, + > { + // FIXME(next-solver) + rustc_type_ir::EarlyBinder::bind([]) + } + + fn fn_is_const(self, def_id: Self::DefId) -> bool { + let id = match def_id { + SolverDefId::FunctionId(id) => id, + _ => unreachable!(), + }; + self.db().function_signature(id).flags.contains(FnFlags::CONST) + } + + fn impl_is_const(self, def_id: Self::DefId) -> bool { + false + } + + fn opt_alias_variances( + self, + kind: impl Into, + def_id: Self::DefId, + ) -> Option { + None + } + + fn type_of_opaque_hir_typeck( + self, + def_id: Self::LocalDefId, + ) -> rustc_type_ir::EarlyBinder { + // FIXME(next-solver) + unimplemented!() + } + + fn coroutine_hidden_types( + self, + def_id: Self::DefId, + ) -> rustc_type_ir::EarlyBinder< + Self, + rustc_type_ir::Binder>, + > { + // FIXME(next-solver) + unimplemented!() + } + + fn is_default_trait(self, def_id: Self::DefId) -> bool { + self.as_lang_item(def_id).map_or(false, |l| matches!(l, TraitSolverLangItem::Sized)) + } + + fn trait_is_coinductive(self, trait_def_id: Self::DefId) -> bool { + let id = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + self.db().trait_signature(id).flags.contains(TraitFlags::COINDUCTIVE) + } + + fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool { + let id = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + self.db().trait_signature(id).flags.contains(TraitFlags::UNSAFE) + } + + fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool { + false + } + + fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool { + false + } + + fn next_trait_solver_globally(self) -> bool { + true + } + + fn opaque_types_and_coroutines_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::LocalDefIds { + // FIXME(next-solver) + unimplemented!() + } +} + +impl<'db> DbInterner<'db> { + pub fn shift_bound_var_indices(self, bound_vars: usize, value: T) -> T + where + T: rustc_type_ir::TypeFoldable, + { + let shift_bv = |bv: BoundVar| BoundVar::from_usize(bv.as_usize() + bound_vars); + self.replace_escaping_bound_vars_uncached( + value, + FnMutDelegate { + regions: &mut |r: BoundRegion| { + Region::new_bound( + self, + DebruijnIndex::ZERO, + BoundRegion { var: shift_bv(r.var), kind: r.kind }, + ) + }, + types: &mut |t: BoundTy| { + Ty::new_bound( + self, + DebruijnIndex::ZERO, + BoundTy { var: shift_bv(t.var), kind: t.kind }, + ) + }, + consts: &mut |c| Const::new_bound(self, DebruijnIndex::ZERO, shift_bv(c)), + }, + ) + } + + pub fn replace_escaping_bound_vars_uncached>>( + self, + value: T, + delegate: impl BoundVarReplacerDelegate<'db>, + ) -> T { + if !value.has_escaping_bound_vars() { + value + } else { + let mut replacer = BoundVarReplacer::new(self, delegate); + value.fold_with(&mut replacer) + } + } + + pub fn replace_bound_vars_uncached>>( + self, + value: Binder<'db, T>, + delegate: impl BoundVarReplacerDelegate<'db>, + ) -> T { + self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate) + } +} + +macro_rules! TrivialTypeTraversalImpls { + ($($ty:ty,)+) => { + $( + impl<'db> rustc_type_ir::TypeFoldable> for $ty { + fn try_fold_with>>( + self, + _: &mut F, + ) -> ::std::result::Result { + Ok(self) + } + + #[inline] + fn fold_with>>( + self, + _: &mut F, + ) -> Self { + self + } + } + + impl<'db> rustc_type_ir::TypeVisitable> for $ty { + #[inline] + fn visit_with>>( + &self, + _: &mut F) + -> F::Result + { + ::output() + } + } + )+ + }; +} + +TrivialTypeTraversalImpls! { + SolverDefId, + Pattern<'db>, + Safety, + FnAbi, + Span, + ParamConst, + ParamTy, + BoundRegion, + BoundVar, + Placeholder, + Placeholder, + Placeholder, +} + +pub(crate) use tls_cache::with_new_cache; +mod tls_cache { + use crate::db::HirDatabase; + + use super::DbInterner; + use rustc_type_ir::search_graph::GlobalCache; + use std::cell::RefCell; + + scoped_tls::scoped_thread_local!(static GLOBAL_CACHE: RefCell>>); + + pub(crate) fn with_new_cache(f: impl FnOnce() -> T) -> T { + GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), f) + } + + pub(super) fn with_cache<'db, T>( + _db: &'db dyn HirDatabase, + f: impl FnOnce(&mut GlobalCache>) -> T, + ) -> T { + // SAFETY: No idea + let call = move |slot: &RefCell<_>| { + f(unsafe { + std::mem::transmute::< + &mut GlobalCache>, + &mut GlobalCache>, + >(&mut *slot.borrow_mut()) + }) + }; + if GLOBAL_CACHE.is_set() { + GLOBAL_CACHE.with(call) + } else { + GLOBAL_CACHE.set(&RefCell::new(GlobalCache::default()), || GLOBAL_CACHE.with(call)) + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs new file mode 100644 index 0000000000000..4d32b27132357 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs @@ -0,0 +1,267 @@ +//! Things related to IR printing in the next-trait-solver. + +use std::any::type_name_of_val; + +use rustc_type_ir::inherent::SliceLike; +use rustc_type_ir::{self as ty, ir_print::IrPrint}; + +use crate::db::HirDatabase; + +use super::SolverDefId; +use super::interner::DbInterner; + +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::AliasTy, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug(t: &ty::AliasTy, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + salsa::with_attached_database(|db| match t.def_id { + SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( + "AliasTy({:?}[{:?}])", + db.as_view::().type_alias_signature(id).name.as_str(), + t.args + )), + SolverDefId::InternedOpaqueTyId(id) => { + fmt.write_str(&format!("AliasTy({:?}[{:?}])", id, t.args)) + } + _ => panic!("Expected TypeAlias or OpaqueTy."), + }) + .unwrap_or_else(|| fmt.write_str(&format!("AliasTy({:?}[{:?}])", t.def_id, t.args))) + } +} + +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::AliasTerm, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug(t: &ty::AliasTerm, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + salsa::with_attached_database(|db| match t.def_id { + SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( + "AliasTerm({:?}[{:?}])", + db.as_view::().type_alias_signature(id).name.as_str(), + t.args + )), + SolverDefId::InternedOpaqueTyId(id) => { + fmt.write_str(&format!("AliasTerm({:?}[{:?}])", id, t.args)) + } + _ => panic!("Expected TypeAlias or OpaqueTy."), + }) + .unwrap_or_else(|| fmt.write_str(&format!("AliasTerm({:?}[{:?}])", t.def_id, t.args))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::TraitRef, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug(t: &ty::TraitRef, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + salsa::with_attached_database(|db| { + let trait_ = match t.def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("Expected trait."), + }; + let self_ty = &t.args.as_slice()[0]; + let trait_args = &t.args.as_slice()[1..]; + if trait_args.is_empty() { + fmt.write_str(&format!( + "{:?}: {}", + self_ty, + db.as_view::().trait_signature(trait_).name.as_str() + )) + } else { + fmt.write_str(&format!( + "{:?}: {}<{:?}>", + self_ty, + db.as_view::().trait_signature(trait_).name.as_str(), + trait_args + )) + } + }) + .unwrap_or_else(|| fmt.write_str(&format!("TraitRef({:?}[{:?}])", t.def_id, t.args))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::TraitPredicate, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::TraitPredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print( + t: &rustc_type_ir::HostEffectPredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &rustc_type_ir::HostEffectPredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print( + t: &ty::ExistentialTraitRef, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::ExistentialTraitRef, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + salsa::with_attached_database(|db| { + let trait_ = match t.def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("Expected trait."), + }; + fmt.write_str(&format!( + "ExistentialTraitRef({:?}[{:?}])", + db.as_view::().trait_signature(trait_).name.as_str(), + t.args + )) + }) + .unwrap_or_else(|| { + fmt.write_str(&format!("ExistentialTraitRef({:?}[{:?}])", t.def_id, t.args)) + }) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print( + t: &ty::ExistentialProjection, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::ExistentialProjection, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + salsa::with_attached_database(|db| { + let id = match t.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => panic!("Expected trait."), + }; + fmt.write_str(&format!( + "ExistentialProjection(({:?}[{:?}]) -> {:?})", + db.as_view::().type_alias_signature(id).name.as_str(), + t.args, + t.term + )) + }) + .unwrap_or_else(|| { + fmt.write_str(&format!( + "ExistentialProjection(({:?}[{:?}]) -> {:?})", + t.def_id, t.args, t.term + )) + }) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print( + t: &ty::ProjectionPredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::ProjectionPredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + salsa::with_attached_database(|db| { + let id = match t.projection_term.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => panic!("Expected trait."), + }; + fmt.write_str(&format!( + "ProjectionPredicate(({:?}[{:?}]) -> {:?})", + db.as_view::().type_alias_signature(id).name.as_str(), + t.projection_term.args, + t.term + )) + }) + .unwrap_or_else(|| { + fmt.write_str(&format!( + "ProjectionPredicate(({:?}[{:?}]) -> {:?})", + t.projection_term.def_id, t.projection_term.args, t.term + )) + }) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::NormalizesTo, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::NormalizesTo, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print( + t: &ty::SubtypePredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::SubtypePredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::CoercePredicate, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &ty::CoercePredicate, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} +impl<'db> IrPrint> for DbInterner<'db> { + fn print(t: &ty::FnSig, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug(t: &ty::FnSig, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} + +impl<'db> IrPrint>> for DbInterner<'db> { + fn print( + t: &rustc_type_ir::PatternKind>, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Self::print_debug(t, fmt) + } + + fn print_debug( + t: &rustc_type_ir::PatternKind>, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + fmt.write_str(&format!("TODO: {:?}", type_name_of_val(t))) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs new file mode 100644 index 0000000000000..3a3206bef38b5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -0,0 +1,1368 @@ +//! Things useful for mapping to/from Chalk and next-trait-solver types. + +use base_db::Crate; +use chalk_ir::{ + CanonicalVarKind, CanonicalVarKinds, ForeignDefId, InferenceVar, Substitution, TyVariableKind, + WellFormed, fold::Shift, interner::HasInterner, +}; +use hir_def::{ + CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId, + TypeOrConstParamId, TypeParamId, signatures::TraitFlags, +}; +use intern::sym; +use rustc_type_ir::{ + AliasTerm, BoundVar, DebruijnIndex, ExistentialProjection, ExistentialTraitRef, Interner as _, + OutlivesPredicate, ProjectionPredicate, TypeFoldable, TypeSuperFoldable, TypeVisitable, + TypeVisitableExt, UniverseIndex, elaborate, + inherent::{BoundVarLike, Clause as _, IntoKind, PlaceholderLike, SliceLike, Ty as _}, + shift_vars, + solve::Goal, +}; +use salsa::plumbing::AsId; + +use crate::{ + ConcreteConst, ConstScalar, ImplTraitId, Interner, + db::{ + HirDatabase, InternedClosureId, InternedCoroutineId, InternedOpaqueTyId, + InternedTypeOrConstParamId, + }, + from_assoc_type_id, from_chalk_trait_id, + mapping::ToChalk, + next_solver::{ + Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst, + interner::{AdtDef, BoundVarKind, BoundVarKinds, DbInterner}, + }, + to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, +}; + +use super::{ + BoundExistentialPredicate, BoundExistentialPredicates, BoundRegion, BoundRegionKind, BoundTy, + BoundTyKind, Canonical, CanonicalVars, Clause, Clauses, Const, Ctor, EarlyParamRegion, + ErrorGuaranteed, ExistentialPredicate, GenericArg, GenericArgs, ParamConst, ParamEnv, ParamTy, + Placeholder, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind, + Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, Tys, ValueConst, VariancesOf, +}; + +pub fn to_placeholder_idx( + db: &dyn HirDatabase, + id: TypeOrConstParamId, + map: impl Fn(BoundVar) -> T, +) -> Placeholder { + let interned_id = InternedTypeOrConstParamId::new(db, id); + Placeholder { + universe: UniverseIndex::ZERO, + bound: map(BoundVar::from_usize(interned_id.as_id().index() as usize)), + } +} + +pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable>>( + interner: DbInterner<'db>, + binder: rustc_type_ir::Binder, T>, +) -> rustc_type_ir::EarlyBinder, T> { + let mut folder = BinderToEarlyBinder { interner, debruijn: rustc_type_ir::DebruijnIndex::ZERO }; + rustc_type_ir::EarlyBinder::bind(binder.skip_binder().fold_with(&mut folder)) +} + +struct BinderToEarlyBinder<'db> { + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, +} + +impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_binder( + &mut self, + t: rustc_type_ir::Binder, T>, + ) -> rustc_type_ir::Binder, T> + where + T: TypeFoldable>, + { + self.debruijn.shift_in(1); + let result = t.super_fold_with(self); + self.debruijn.shift_out(1); + result + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + match t.kind() { + rustc_type_ir::TyKind::Bound(debruijn, bound_ty) if self.debruijn == debruijn => { + let var: rustc_type_ir::BoundVar = bound_ty.var(); + Ty::new(self.cx(), rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32() })) + } + _ => t.super_fold_with(self), + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + match r.kind() { + rustc_type_ir::ReBound(debruijn, bound_region) if self.debruijn == debruijn => { + let var: rustc_type_ir::BoundVar = bound_region.var(); + Region::new( + self.cx(), + rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { + index: var.as_u32(), + }), + ) + } + _ => r, + } + } + + fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { + match c.kind() { + rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => { + Const::new( + self.cx(), + rustc_type_ir::ConstKind::Param(ParamConst { index: var.as_u32() }), + ) + } + _ => c.super_fold_with(self), + } + } +} + +pub trait ChalkToNextSolver<'db, Out> { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out; +} + +impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Ty<'db> { + Ty::new( + interner, + match self.kind(Interner) { + chalk_ir::TyKind::Adt(adt_id, substitution) => { + let def = AdtDef::new(adt_id.0, interner); + let args = substitution.to_nextsolver(interner); + rustc_type_ir::TyKind::Adt(def, args) + } + chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution) => { + let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(*assoc_type_id)); + let args: GenericArgs<'db> = substitution.to_nextsolver(interner); + let alias_ty = rustc_type_ir::AliasTy::new(interner, def_id, args.iter()); + rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias_ty) + } + chalk_ir::TyKind::Scalar(scalar) => match scalar { + chalk_ir::Scalar::Bool => rustc_type_ir::TyKind::Bool, + chalk_ir::Scalar::Char => rustc_type_ir::TyKind::Char, + chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) + } + chalk_ir::Scalar::Int(chalk_ir::IntTy::I8) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) + } + chalk_ir::Scalar::Int(chalk_ir::IntTy::I16) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) + } + chalk_ir::Scalar::Int(chalk_ir::IntTy::I32) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) + } + chalk_ir::Scalar::Int(chalk_ir::IntTy::I64) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) + } + chalk_ir::Scalar::Int(chalk_ir::IntTy::I128) => { + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::U16) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::U64) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) + } + chalk_ir::Scalar::Uint(chalk_ir::UintTy::U128) => { + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) + } + chalk_ir::Scalar::Float(chalk_ir::FloatTy::F16) => { + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) + } + chalk_ir::Scalar::Float(chalk_ir::FloatTy::F32) => { + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) + } + chalk_ir::Scalar::Float(chalk_ir::FloatTy::F64) => { + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) + } + chalk_ir::Scalar::Float(chalk_ir::FloatTy::F128) => { + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) + } + }, + chalk_ir::TyKind::Tuple(_, substitution) => { + let args = substitution.to_nextsolver(interner); + rustc_type_ir::TyKind::Tuple(args) + } + chalk_ir::TyKind::Array(ty, len) => rustc_type_ir::TyKind::Array( + ty.to_nextsolver(interner), + len.to_nextsolver(interner), + ), + chalk_ir::TyKind::Slice(ty) => { + rustc_type_ir::TyKind::Slice(ty.to_nextsolver(interner)) + } + chalk_ir::TyKind::Raw(mutability, ty) => rustc_type_ir::RawPtr( + ty.to_nextsolver(interner), + mutability.to_nextsolver(interner), + ), + chalk_ir::TyKind::Ref(mutability, lifetime, ty) => rustc_type_ir::TyKind::Ref( + lifetime.to_nextsolver(interner), + ty.to_nextsolver(interner), + mutability.to_nextsolver(interner), + ), + chalk_ir::TyKind::OpaqueType(def_id, substitution) => { + let id: InternedOpaqueTyId = (*def_id).into(); + let args: GenericArgs<'db> = substitution.to_nextsolver(interner); + let alias_ty = rustc_type_ir::AliasTy::new(interner, id.into(), args); + rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty) + } + chalk_ir::TyKind::FnDef(fn_def_id, substitution) => { + let def_id = CallableDefId::from_chalk(interner.db(), *fn_def_id); + let id: SolverDefId = match def_id { + CallableDefId::FunctionId(id) => id.into(), + CallableDefId::StructId(id) => SolverDefId::Ctor(Ctor::Struct(id)), + CallableDefId::EnumVariantId(id) => SolverDefId::Ctor(Ctor::Enum(id)), + }; + rustc_type_ir::TyKind::FnDef(id, substitution.to_nextsolver(interner)) + } + chalk_ir::TyKind::Str => rustc_type_ir::TyKind::Str, + chalk_ir::TyKind::Never => rustc_type_ir::TyKind::Never, + chalk_ir::TyKind::Closure(closure_id, substitution) => { + let id: InternedClosureId = (*closure_id).into(); + rustc_type_ir::TyKind::Closure(id.into(), substitution.to_nextsolver(interner)) + } + chalk_ir::TyKind::Coroutine(coroutine_id, substitution) => { + let id: InternedCoroutineId = (*coroutine_id).into(); + rustc_type_ir::TyKind::Coroutine( + id.into(), + substitution.to_nextsolver(interner), + ) + } + chalk_ir::TyKind::CoroutineWitness(coroutine_id, substitution) => { + let id: InternedCoroutineId = (*coroutine_id).into(); + rustc_type_ir::TyKind::CoroutineWitness( + id.into(), + substitution.to_nextsolver(interner), + ) + } + chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign( + SolverDefId::ForeignId(crate::from_foreign_def_id(*foreign_def_id)), + ), + chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed), + chalk_ir::TyKind::Placeholder(placeholder_index) => { + rustc_type_ir::TyKind::Placeholder(PlaceholderTy::new_anon( + placeholder_index.ui.to_nextsolver(interner), + rustc_type_ir::BoundVar::from_usize(placeholder_index.idx), + )) + } + chalk_ir::TyKind::Dyn(dyn_ty) => { + // exists { for<...> ^1.0: ... } + let bounds = BoundExistentialPredicates::new_from_iter( + interner, + dyn_ty.bounds.skip_binders().iter(Interner).filter_map(|pred| { + // for<...> ^1.0: ... + let (val, binders) = pred.clone().into_value_and_skipped_binders(); + let bound_vars = binders.to_nextsolver(interner); + let clause = match val { + chalk_ir::WhereClause::Implemented(trait_ref) => { + let trait_id = from_chalk_trait_id(trait_ref.trait_id); + if interner + .db() + .trait_signature(trait_id) + .flags + .contains(TraitFlags::AUTO) + { + ExistentialPredicate::AutoTrait(SolverDefId::TraitId( + trait_id, + )) + } else { + let def_id = SolverDefId::TraitId(trait_id); + let args = GenericArgs::new_from_iter( + interner, + trait_ref + .substitution + .iter(Interner) + .skip(1) + .map(|a| a.clone().shifted_out(Interner).unwrap()) + .map(|a| a.to_nextsolver(interner)), + ); + let trait_ref = ExistentialTraitRef::new_from_args( + interner, def_id, args, + ); + ExistentialPredicate::Trait(trait_ref) + } + } + chalk_ir::WhereClause::AliasEq(alias_eq) => { + let (def_id, args) = match &alias_eq.alias { + chalk_ir::AliasTy::Projection(projection) => { + let id = + from_assoc_type_id(projection.associated_ty_id); + let def_id = SolverDefId::TypeAliasId(id); + let generics = interner.generics_of(def_id); + let parent_len = generics.parent_count; + let substs = projection.substitution.iter(Interner).skip(1); + + let args = GenericArgs::new_from_iter( + interner, + substs + .map(|a| { + a.clone().shifted_out(Interner).unwrap() + }) + .map(|a| a.to_nextsolver(interner)), + ); + (def_id, args) + } + chalk_ir::AliasTy::Opaque(opaque_ty) => { + panic!("Invalid ExistentialPredicate (opaques can't be named)."); + } + }; + let term = alias_eq + .ty + .clone() + .shifted_out(Interner) + .unwrap() + .to_nextsolver(interner) + .into(); + let projection = ExistentialProjection::new_from_args( + interner, def_id, args, term, + ); + ExistentialPredicate::Projection(projection) + } + chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { + return None; + } + chalk_ir::WhereClause::TypeOutlives(type_outlives) => return None, + }; + + Some(Binder::bind_with_vars(clause, bound_vars)) + }), + ); + let region = dyn_ty.lifetime.to_nextsolver(interner); + let kind = rustc_type_ir::DynKind::Dyn; + rustc_type_ir::TyKind::Dynamic(bounds, region, kind) + } + chalk_ir::TyKind::Alias(alias_ty) => match alias_ty { + chalk_ir::AliasTy::Projection(projection_ty) => { + let def_id = SolverDefId::TypeAliasId(from_assoc_type_id( + projection_ty.associated_ty_id, + )); + let alias_ty = rustc_type_ir::AliasTy::new_from_args( + interner, + def_id, + projection_ty.substitution.to_nextsolver(interner), + ); + rustc_type_ir::TyKind::Alias( + rustc_type_ir::AliasTyKind::Projection, + alias_ty, + ) + } + chalk_ir::AliasTy::Opaque(opaque_ty) => { + let id: InternedOpaqueTyId = opaque_ty.opaque_ty_id.into(); + let def_id = SolverDefId::InternedOpaqueTyId(id); + let alias_ty = rustc_type_ir::AliasTy::new_from_args( + interner, + def_id, + opaque_ty.substitution.to_nextsolver(interner), + ); + rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty) + } + }, + chalk_ir::TyKind::Function(fn_pointer) => { + let sig_tys = fn_pointer.clone().into_binders(Interner).to_nextsolver(interner); + let header = rustc_type_ir::FnHeader { + abi: fn_pointer.sig.abi, + c_variadic: fn_pointer.sig.variadic, + safety: match fn_pointer.sig.safety { + chalk_ir::Safety::Safe => super::abi::Safety::Safe, + chalk_ir::Safety::Unsafe => super::abi::Safety::Unsafe, + }, + }; + + rustc_type_ir::TyKind::FnPtr(sig_tys, header) + } + chalk_ir::TyKind::BoundVar(bound_var) => rustc_type_ir::TyKind::Bound( + bound_var.debruijn.to_nextsolver(interner), + BoundTy { + var: rustc_type_ir::BoundVar::from_usize(bound_var.index), + kind: BoundTyKind::Anon, + }, + ), + chalk_ir::TyKind::InferenceVar(inference_var, ty_variable_kind) => { + rustc_type_ir::TyKind::Infer( + (*inference_var, *ty_variable_kind).to_nextsolver(interner), + ) + } + }, + ) + } +} + +impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Region<'db> { + Region::new( + interner, + match self.data(Interner) { + chalk_ir::LifetimeData::BoundVar(bound_var) => rustc_type_ir::RegionKind::ReBound( + bound_var.debruijn.to_nextsolver(interner), + BoundRegion { + var: rustc_type_ir::BoundVar::from_u32(bound_var.index as u32), + kind: BoundRegionKind::Anon, + }, + ), + chalk_ir::LifetimeData::InferenceVar(inference_var) => { + rustc_type_ir::RegionKind::ReVar(rustc_type_ir::RegionVid::from_u32( + inference_var.index(), + )) + } + chalk_ir::LifetimeData::Placeholder(placeholder_index) => { + rustc_type_ir::RegionKind::RePlaceholder(PlaceholderRegion::new_anon( + rustc_type_ir::UniverseIndex::from_u32(placeholder_index.ui.counter as u32), + rustc_type_ir::BoundVar::from_u32(placeholder_index.idx as u32), + )) + } + chalk_ir::LifetimeData::Static => rustc_type_ir::RegionKind::ReStatic, + chalk_ir::LifetimeData::Erased => rustc_type_ir::RegionKind::ReErased, + chalk_ir::LifetimeData::Phantom(_, _) => { + unreachable!() + } + chalk_ir::LifetimeData::Error => { + rustc_type_ir::RegionKind::ReError(ErrorGuaranteed) + } + }, + ) + } +} + +impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Const<'db> { + let data = self.data(Interner); + Const::new( + interner, + match &data.value { + chalk_ir::ConstValue::BoundVar(bound_var) => rustc_type_ir::ConstKind::Bound( + bound_var.debruijn.to_nextsolver(interner), + rustc_type_ir::BoundVar::from_usize(bound_var.index), + ), + chalk_ir::ConstValue::InferenceVar(inference_var) => { + rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var( + rustc_type_ir::ConstVid::from_u32(inference_var.index()), + )) + } + chalk_ir::ConstValue::Placeholder(placeholder_index) => { + rustc_type_ir::ConstKind::Placeholder(PlaceholderConst::new( + placeholder_index.ui.to_nextsolver(interner), + rustc_type_ir::BoundVar::from_usize(placeholder_index.idx), + )) + } + chalk_ir::ConstValue::Concrete(concrete_const) => match &concrete_const.interned { + ConstScalar::Bytes(bytes, memory) => { + rustc_type_ir::ConstKind::Value(ValueConst::new( + data.ty.to_nextsolver(interner), + ConstBytes(bytes.clone(), memory.clone()), + )) + } + ConstScalar::UnevaluatedConst(c, subst) => { + let def = match *c { + GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), + GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), + }; + let args = subst.to_nextsolver(interner); + rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(def, args)) + } + ConstScalar::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + }, + }, + ) + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys>> + for chalk_ir::FnSubst +{ + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::FnSigTys> { + rustc_type_ir::FnSigTys { + inputs_and_output: Tys::new_from_iter( + interner, + self.0.iter(Interner).map(|g| g.assert_ty_ref(Interner).to_nextsolver(interner)), + ), + } + } +} + +impl< + 'db, + U: TypeVisitable>, + T: Clone + ChalkToNextSolver<'db, U> + HasInterner, +> ChalkToNextSolver<'db, rustc_type_ir::Binder, U>> for chalk_ir::Binders +{ + fn to_nextsolver( + &self, + interner: DbInterner<'db>, + ) -> rustc_type_ir::Binder, U> { + let (val, binders) = self.clone().into_value_and_skipped_binders(); + rustc_type_ir::Binder::bind_with_vars( + val.to_nextsolver(interner), + binders.to_nextsolver(interner), + ) + } +} + +impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds { + BoundVarKinds::new_from_iter( + interner, + self.iter(Interner).map(|v| v.to_nextsolver(interner)), + ) + } +} + +impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind { + match self { + chalk_ir::VariableKind::Ty(_ty_variable_kind) => BoundVarKind::Ty(BoundTyKind::Anon), + chalk_ir::VariableKind::Lifetime => BoundVarKind::Region(BoundRegionKind::Anon), + chalk_ir::VariableKind::Const(_ty) => BoundVarKind::Const, + } + } +} + +impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> { + match self.data(Interner) { + chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner).into(), + chalk_ir::GenericArgData::Lifetime(lifetime) => lifetime.to_nextsolver(interner).into(), + chalk_ir::GenericArgData::Const(const_) => const_.to_nextsolver(interner).into(), + } + } +} +impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> { + GenericArgs::new_from_iter( + interner, + self.iter(Interner).map(|arg| -> GenericArg<'db> { arg.to_nextsolver(interner) }), + ) + } +} + +impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Tys<'db> { + Tys::new_from_iter( + interner, + self.iter(Interner).map(|arg| -> Ty<'db> { + match arg.data(Interner) { + chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner), + chalk_ir::GenericArgData::Lifetime(_) => unreachable!(), + chalk_ir::GenericArgData::Const(_) => unreachable!(), + } + }), + ) + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { + rustc_type_ir::DebruijnIndex::from_u32(self.depth()) + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex { + rustc_type_ir::UniverseIndex::from_u32(self.counter as u32) + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy> + for (chalk_ir::InferenceVar, chalk_ir::TyVariableKind) +{ + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::InferTy { + match self.1 { + chalk_ir::TyVariableKind::General => { + rustc_type_ir::InferTy::TyVar(rustc_type_ir::TyVid::from_u32(self.0.index())) + } + chalk_ir::TyVariableKind::Integer => { + rustc_type_ir::InferTy::IntVar(rustc_type_ir::IntVid::from_u32(self.0.index())) + } + chalk_ir::TyVariableKind::Float => { + rustc_type_ir::InferTy::FloatVar(rustc_type_ir::FloatVid::from_u32(self.0.index())) + } + } + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_ast_ir::Mutability { + match self { + chalk_ir::Mutability::Mut => rustc_ast_ir::Mutability::Mut, + chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not, + } + } +} + +impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance { + match self { + crate::Variance::Covariant => rustc_type_ir::Variance::Covariant, + crate::Variance::Invariant => rustc_type_ir::Variance::Invariant, + crate::Variance::Contravariant => rustc_type_ir::Variance::Contravariant, + crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant, + } + } +} + +impl<'db> ChalkToNextSolver<'db, Canonical<'db, Goal, Predicate<'db>>>> + for chalk_ir::Canonical>> +{ + fn to_nextsolver( + &self, + interner: DbInterner<'db>, + ) -> Canonical<'db, Goal, Predicate<'db>>> { + let param_env = self.value.environment.to_nextsolver(interner); + let variables = CanonicalVars::new_from_iter( + interner, + self.binders.iter(Interner).map(|k| match &k.kind { + chalk_ir::VariableKind::Ty(ty_variable_kind) => match ty_variable_kind { + TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty( + rustc_type_ir::CanonicalTyVarKind::General(UniverseIndex::ROOT), + ), + TyVariableKind::Integer => { + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) + } + TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Ty( + rustc_type_ir::CanonicalTyVarKind::Float, + ), + }, + chalk_ir::VariableKind::Lifetime => { + rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ROOT) + } + chalk_ir::VariableKind::Const(ty) => { + rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ROOT) + } + }), + ); + Canonical { + max_universe: UniverseIndex::ROOT, + value: Goal::new(interner, param_env, self.value.goal.to_nextsolver(interner)), + variables, + } + } +} + +impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Predicate<'db> { + match self.data(Interner) { + chalk_ir::GoalData::Quantified(quantifier_kind, binders) => { + if !binders.binders.is_empty(Interner) { + panic!("Should not be constructed."); + } + let (val, _) = binders.clone().into_value_and_skipped_binders(); + val.shifted_out(Interner).unwrap().to_nextsolver(interner) + } + chalk_ir::GoalData::Implies(program_clauses, goal) => { + panic!("Should not be constructed.") + } + chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."), + chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."), + chalk_ir::GoalData::EqGoal(eq_goal) => panic!("Should not be constructed."), + chalk_ir::GoalData::SubtypeGoal(subtype_goal) => { + let subtype_predicate = SubtypePredicate { + a: subtype_goal.a.to_nextsolver(interner), + b: subtype_goal.b.to_nextsolver(interner), + a_is_expected: true, + }; + let pred_kind = PredicateKind::Subtype(subtype_predicate); + let pred_kind = Binder::bind_with_vars( + shift_vars(interner, pred_kind, 1), + BoundVarKinds::new_from_iter(interner, []), + ); + Predicate::new(interner, pred_kind) + } + chalk_ir::GoalData::DomainGoal(domain_goal) => { + let pred_kind = domain_goal.to_nextsolver(interner); + let pred_kind = Binder::bind_with_vars( + shift_vars(interner, pred_kind, 1), + BoundVarKinds::new_from_iter(interner, []), + ); + Predicate::new(interner, pred_kind) + } + chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."), + } + } +} + +impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> ParamEnv<'db> { + let clauses = Clauses::new_from_iter( + interner, + self.clauses.iter(Interner).map(|c| c.to_nextsolver(interner)), + ); + let clauses = + Clauses::new_from_iter(interner, elaborate::elaborate(interner, clauses.iter())); + ParamEnv { clauses } + } +} + +impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> { + Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner))) + } +} + +impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> + for chalk_ir::ProgramClauseImplication +{ + fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { + assert!(self.conditions.is_empty(Interner)); + assert!(self.constraints.is_empty(Interner)); + self.consequence.to_nextsolver(interner) + } +} + +impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { + match self { + chalk_ir::DomainGoal::Holds(where_clause) => match where_clause { + chalk_ir::WhereClause::Implemented(trait_ref) => { + let predicate = TraitPredicate { + trait_ref: trait_ref.to_nextsolver(interner), + polarity: rustc_type_ir::PredicatePolarity::Positive, + }; + PredicateKind::Clause(ClauseKind::Trait(predicate)) + } + chalk_ir::WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + chalk_ir::AliasTy::Projection(p) => { + let def_id = + SolverDefId::TypeAliasId(from_assoc_type_id(p.associated_ty_id)); + let args = p.substitution.to_nextsolver(interner); + let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); + let term: Term<'db> = term.into(); + let predicate = ProjectionPredicate { + projection_term: AliasTerm::new_from_args(interner, def_id, args), + term, + }; + PredicateKind::Clause(ClauseKind::Projection(predicate)) + } + chalk_ir::AliasTy::Opaque(opaque) => { + let id: InternedOpaqueTyId = opaque.opaque_ty_id.into(); + let def_id = SolverDefId::InternedOpaqueTyId(id); + let args = opaque.substitution.to_nextsolver(interner); + let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); + let term: Term<'db> = term.into(); + let opaque_ty = Ty::new( + interner, + rustc_type_ir::TyKind::Alias( + rustc_type_ir::AliasTyKind::Opaque, + rustc_type_ir::AliasTy::new_from_args(interner, def_id, args), + ), + ) + .into(); + PredicateKind::AliasRelate( + opaque_ty, + term, + rustc_type_ir::AliasRelationDirection::Equate, + ) + } + }, + chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { + let predicate = OutlivesPredicate( + lifetime_outlives.a.to_nextsolver(interner), + lifetime_outlives.b.to_nextsolver(interner), + ); + PredicateKind::Clause(ClauseKind::RegionOutlives(predicate)) + } + chalk_ir::WhereClause::TypeOutlives(type_outlives) => { + let predicate = OutlivesPredicate( + type_outlives.ty.to_nextsolver(interner), + type_outlives.lifetime.to_nextsolver(interner), + ); + PredicateKind::Clause(ClauseKind::TypeOutlives(predicate)) + } + }, + chalk_ir::DomainGoal::Normalize(normalize) => { + let proj_ty = match &normalize.alias { + chalk_ir::AliasTy::Projection(proj) => proj, + _ => unimplemented!(), + }; + let args: GenericArgs<'db> = proj_ty.substitution.to_nextsolver(interner); + let alias = rustc_type_ir::AliasTerm::new( + interner, + from_assoc_type_id(proj_ty.associated_ty_id).into(), + args, + ); + let term = normalize.ty.to_nextsolver(interner).into(); + let normalizes_to = rustc_type_ir::NormalizesTo { alias, term }; + PredicateKind::NormalizesTo(normalizes_to) + } + chalk_ir::DomainGoal::WellFormed(well_formed) => { + let term = match well_formed { + WellFormed::Trait(_) => panic!("Should not be constructed."), + WellFormed::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)), + }; + PredicateKind::Clause(rustc_type_ir::ClauseKind::WellFormed(term)) + } + chalk_ir::DomainGoal::FromEnv(from_env) => match from_env { + chalk_ir::FromEnv::Trait(trait_ref) => { + let predicate = TraitPredicate { + trait_ref: trait_ref.to_nextsolver(interner), + polarity: rustc_type_ir::PredicatePolarity::Positive, + }; + PredicateKind::Clause(ClauseKind::Trait(predicate)) + } + chalk_ir::FromEnv::Ty(ty) => PredicateKind::Clause(ClauseKind::WellFormed( + Term::Ty(ty.to_nextsolver(interner)), + )), + }, + chalk_ir::DomainGoal::IsLocal(ty) => panic!("Should not be constructed."), + chalk_ir::DomainGoal::IsUpstream(ty) => panic!("Should not be constructed."), + chalk_ir::DomainGoal::IsFullyVisible(ty) => panic!("Should not be constructed."), + chalk_ir::DomainGoal::LocalImplAllowed(trait_ref) => { + panic!("Should not be constructed.") + } + chalk_ir::DomainGoal::Compatible => panic!("Should not be constructed."), + chalk_ir::DomainGoal::DownstreamType(ty) => panic!("Should not be constructed."), + chalk_ir::DomainGoal::Reveal => panic!("Should not be constructed."), + chalk_ir::DomainGoal::ObjectSafe(trait_id) => panic!("Should not be constructed."), + } + } +} + +impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> TraitRef<'db> { + let args = self.substitution.to_nextsolver(interner); + TraitRef::new_from_args( + interner, + SolverDefId::TraitId(from_chalk_trait_id(self.trait_id)), + args, + ) + } +} + +impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause { + fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { + match self { + chalk_ir::WhereClause::Implemented(trait_ref) => { + let predicate = TraitPredicate { + trait_ref: trait_ref.to_nextsolver(interner), + polarity: rustc_type_ir::PredicatePolarity::Positive, + }; + PredicateKind::Clause(ClauseKind::Trait(predicate)) + } + chalk_ir::WhereClause::AliasEq(alias_eq) => { + let projection = match &alias_eq.alias { + chalk_ir::AliasTy::Projection(p) => p, + _ => unimplemented!(), + }; + let def_id = + SolverDefId::TypeAliasId(from_assoc_type_id(projection.associated_ty_id)); + let args = projection.substitution.to_nextsolver(interner); + let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); + let term: Term<'db> = term.into(); + let predicate = ProjectionPredicate { + projection_term: AliasTerm::new_from_args(interner, def_id, args), + term, + }; + PredicateKind::Clause(ClauseKind::Projection(predicate)) + } + chalk_ir::WhereClause::TypeOutlives(type_outlives) => { + let ty = type_outlives.ty.to_nextsolver(interner); + let r = type_outlives.lifetime.to_nextsolver(interner); + PredicateKind::Clause(ClauseKind::TypeOutlives(OutlivesPredicate(ty, r))) + } + chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { + let a = lifetime_outlives.a.to_nextsolver(interner); + let b = lifetime_outlives.b.to_nextsolver(interner); + PredicateKind::Clause(ClauseKind::RegionOutlives(OutlivesPredicate(a, b))) + } + } + } +} + +pub fn convert_canonical_args_for_result<'db>( + interner: DbInterner<'db>, + args: Canonical<'db, Vec>>, +) -> chalk_ir::Canonical> { + let Canonical { value, variables, max_universe } = args; + let binders = CanonicalVarKinds::from_iter( + Interner, + variables.iter().map(|v| match v { + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::General(_)) => { + CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::General), + chalk_ir::UniverseIndex::ROOT, + ) + } + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) => { + CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Integer), + chalk_ir::UniverseIndex::ROOT, + ) + } + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Float) => { + CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::Float), + chalk_ir::UniverseIndex::ROOT, + ) + } + rustc_type_ir::CanonicalVarKind::Region(universe_index) => CanonicalVarKind::new( + chalk_ir::VariableKind::Lifetime, + chalk_ir::UniverseIndex::ROOT, + ), + rustc_type_ir::CanonicalVarKind::Const(universe_index) => CanonicalVarKind::new( + chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner)), + chalk_ir::UniverseIndex::ROOT, + ), + rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(), + rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(), + rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(), + }), + ); + chalk_ir::Canonical { + binders, + value: chalk_ir::ConstrainedSubst { + constraints: chalk_ir::Constraints::empty(Interner), + subst: convert_args_for_result(interner, &value), + }, + } +} + +pub fn convert_args_for_result<'db>( + interner: DbInterner<'db>, + args: &[GenericArg<'db>], +) -> crate::Substitution { + let mut substs = Vec::with_capacity(args.len()); + for arg in args { + match (*arg).kind() { + rustc_type_ir::GenericArgKind::Type(ty) => { + let ty = convert_ty_for_result(interner, ty); + substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner)); + } + rustc_type_ir::GenericArgKind::Lifetime(region) => { + let lifetime = convert_region_for_result(region); + substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner)); + } + rustc_type_ir::GenericArgKind::Const(const_) => { + substs.push( + chalk_ir::GenericArgData::Const(convert_const_for_result(interner, const_)) + .intern(Interner), + ); + } + } + } + Substitution::from_iter(Interner, substs) +} + +pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty { + use crate::{Scalar, TyKind}; + use chalk_ir::{FloatTy, IntTy, UintTy}; + match ty.kind() { + rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool), + rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char), + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => { + TyKind::Scalar(Scalar::Int(IntTy::I8)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => { + TyKind::Scalar(Scalar::Int(IntTy::I16)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => { + TyKind::Scalar(Scalar::Int(IntTy::I32)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => { + TyKind::Scalar(Scalar::Int(IntTy::I64)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => { + TyKind::Scalar(Scalar::Int(IntTy::I128)) + } + rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => { + TyKind::Scalar(Scalar::Int(IntTy::Isize)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => { + TyKind::Scalar(Scalar::Uint(UintTy::U8)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => { + TyKind::Scalar(Scalar::Uint(UintTy::U16)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => { + TyKind::Scalar(Scalar::Uint(UintTy::U32)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => { + TyKind::Scalar(Scalar::Uint(UintTy::U64)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => { + TyKind::Scalar(Scalar::Uint(UintTy::U128)) + } + rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => { + TyKind::Scalar(Scalar::Uint(UintTy::Usize)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => { + TyKind::Scalar(Scalar::Float(FloatTy::F16)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => { + TyKind::Scalar(Scalar::Float(FloatTy::F32)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => { + TyKind::Scalar(Scalar::Float(FloatTy::F64)) + } + rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => { + TyKind::Scalar(Scalar::Float(FloatTy::F128)) + } + rustc_type_ir::TyKind::Str => TyKind::Str, + rustc_type_ir::TyKind::Error(_) => TyKind::Error, + rustc_type_ir::TyKind::Never => TyKind::Never, + + rustc_type_ir::TyKind::Adt(def, args) => { + let adt_id = def.inner().id; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::Adt(chalk_ir::AdtId(adt_id), subst) + } + + rustc_type_ir::TyKind::Infer(infer_ty) => { + let (var, kind) = match infer_ty { + rustc_type_ir::InferTy::TyVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::General) + } + rustc_type_ir::InferTy::IntVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::Integer) + } + rustc_type_ir::InferTy::FloatVar(var) => { + (InferenceVar::from(var.as_u32()), TyVariableKind::Float) + } + rustc_type_ir::InferTy::FreshFloatTy(..) + | rustc_type_ir::InferTy::FreshIntTy(..) + | rustc_type_ir::InferTy::FreshTy(..) => { + panic!("Freshening shouldn't happen.") + } + }; + TyKind::InferenceVar(var, kind) + } + + rustc_type_ir::TyKind::Ref(r, ty, mutability) => { + let mutability = match mutability { + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + }; + let r = convert_region_for_result(r); + let ty = convert_ty_for_result(interner, ty); + TyKind::Ref(mutability, r, ty) + } + + rustc_type_ir::TyKind::Tuple(tys) => { + let size = tys.len(); + let subst = Substitution::from_iter( + Interner, + tys.iter().map(|ty| { + chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty)) + .intern(Interner) + }), + ); + TyKind::Tuple(size, subst) + } + + rustc_type_ir::TyKind::Array(ty, const_) => { + let ty = convert_ty_for_result(interner, ty); + let const_ = convert_const_for_result(interner, const_); + TyKind::Array(ty, const_) + } + + rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind { + rustc_type_ir::AliasTyKind::Projection => { + let assoc_ty_id = match alias_ty.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), + }; + let associated_ty_id = to_assoc_type_id(assoc_ty_id); + let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); + TyKind::AssociatedType(associated_ty_id, substitution) + } + rustc_type_ir::AliasTyKind::Opaque => { + let opaque_ty_id = match alias_ty.def_id { + SolverDefId::InternedOpaqueTyId(id) => id, + _ => unreachable!(), + }; + let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); + TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { + opaque_ty_id: opaque_ty_id.into(), + substitution, + })) + } + rustc_type_ir::AliasTyKind::Inherent => unimplemented!(), + rustc_type_ir::AliasTyKind::Free => unimplemented!(), + }, + + rustc_type_ir::TyKind::Placeholder(placeholder) => { + let ui = chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }; + let placeholder_index = + chalk_ir::PlaceholderIndex { idx: placeholder.bound.var.as_usize(), ui }; + TyKind::Placeholder(placeholder_index) + } + + rustc_type_ir::TyKind::Bound(debruijn_index, ty) => TyKind::BoundVar(chalk_ir::BoundVar { + debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), + index: ty.var.as_usize(), + }), + + rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => { + let num_binders = bound_sig.bound_vars().len(); + let sig = chalk_ir::FnSig { + abi: fn_header.abi, + safety: match fn_header.safety { + crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, + crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: fn_header.c_variadic, + }; + let args = GenericArgs::new_from_iter( + interner, + bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), + ); + let substitution = convert_args_for_result(interner, args.as_slice()); + let substitution = chalk_ir::FnSubst(substitution); + let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; + TyKind::Function(fnptr) + } + + rustc_type_ir::TyKind::Dynamic(preds, region, dyn_kind) => { + assert!(matches!(dyn_kind, rustc_type_ir::DynKind::Dyn)); + let self_ty = Ty::new_bound( + interner, + DebruijnIndex::from_u32(1), + BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) }, + ); + let bounds = chalk_ir::QuantifiedWhereClauses::from_iter( + Interner, + preds.iter().map(|p| { + let binders = chalk_ir::VariableKinds::from_iter( + Interner, + p.bound_vars().iter().map(|b| match b { + BoundVarKind::Ty(kind) => { + chalk_ir::VariableKind::Ty(TyVariableKind::General) + } + BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime, + BoundVarKind::Const => { + chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner)) + } + }), + ); + let where_clause = match p.skip_binder() { + rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { + let trait_ref = TraitRef::new( + interner, + trait_ref.def_id, + [self_ty.into()].into_iter().chain(trait_ref.args.iter()), + ); + let trait_id = match trait_ref.def_id { + SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + let substitution = + convert_args_for_result(interner, trait_ref.args.as_slice()); + let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; + chalk_ir::WhereClause::Implemented(trait_ref) + } + rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => { + let trait_id = match trait_ { + SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + let substitution = chalk_ir::Substitution::empty(Interner); + let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; + chalk_ir::WhereClause::Implemented(trait_ref) + } + rustc_type_ir::ExistentialPredicate::Projection(existential_projection) => { + let projection = ProjectionPredicate { + projection_term: AliasTerm::new( + interner, + existential_projection.def_id, + [self_ty.into()] + .iter() + .chain(existential_projection.args.iter()), + ), + term: existential_projection.term, + }; + let associated_ty_id = match projection.projection_term.def_id { + SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), + _ => unreachable!(), + }; + let substitution = convert_args_for_result( + interner, + projection.projection_term.args.as_slice(), + ); + let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id, + substitution, + }); + let ty = match projection.term { + Term::Ty(ty) => ty, + _ => unreachable!(), + }; + let ty = convert_ty_for_result(interner, ty); + let alias_eq = chalk_ir::AliasEq { alias, ty }; + chalk_ir::WhereClause::AliasEq(alias_eq) + } + }; + chalk_ir::Binders::new(binders, where_clause) + }), + ); + let binders = chalk_ir::VariableKinds::from1( + Interner, + chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), + ); + let bounds = chalk_ir::Binders::new(binders, bounds); + let dyn_ty = chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(region) }; + TyKind::Dyn(dyn_ty) + } + + rustc_type_ir::TyKind::Slice(ty) => { + let ty = convert_ty_for_result(interner, ty); + TyKind::Slice(ty) + } + + rustc_type_ir::TyKind::Foreign(foreign) => { + let def_id = match foreign { + SolverDefId::ForeignId(id) => id, + _ => unreachable!(), + }; + TyKind::Foreign(to_foreign_def_id(def_id)) + } + rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(), + rustc_type_ir::TyKind::RawPtr(ty, mutability) => { + let mutability = match mutability { + rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, + rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, + }; + let ty = convert_ty_for_result(interner, ty); + TyKind::Raw(mutability, ty) + } + rustc_type_ir::TyKind::FnDef(def_id, args) => { + let id = match def_id { + SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), + SolverDefId::Ctor(Ctor::Struct(id)) => CallableDefId::StructId(id), + SolverDefId::Ctor(Ctor::Enum(id)) => CallableDefId::EnumVariantId(id), + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::FnDef(id.to_chalk(interner.db()), subst) + } + + rustc_type_ir::TyKind::Closure(def_id, args) => { + let id = match def_id { + SolverDefId::InternedClosureId(id) => id, + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::Closure(id.into(), subst) + } + rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(), + rustc_type_ir::TyKind::Coroutine(def_id, args) => { + let id = match def_id { + SolverDefId::InternedCoroutineId(id) => id, + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::Coroutine(id.into(), subst) + } + rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { + let id = match def_id { + SolverDefId::InternedCoroutineId(id) => id, + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, args.as_slice()); + TyKind::CoroutineWitness(id.into(), subst) + } + + rustc_type_ir::TyKind::Param(_) => unimplemented!(), + rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(), + } + .intern(Interner) +} + +fn convert_const_for_result<'db>(interner: DbInterner<'db>, const_: Const<'db>) -> crate::Const { + let value: chalk_ir::ConstValue = match const_.kind() { + rustc_type_ir::ConstKind::Param(_) => unimplemented!(), + rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { + chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32())) + } + rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => { + panic!("Vars should not be freshened.") + } + rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { + chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( + chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), + var.index(), + )) + } + rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { + chalk_ir::ConstValue::Placeholder(chalk_ir::PlaceholderIndex { + ui: chalk_ir::UniverseIndex { counter: placeholder_const.universe.as_usize() }, + idx: placeholder_const.bound.as_usize(), + }) + } + rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => { + let id = match unevaluated_const.def { + SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), + SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), + _ => unreachable!(), + }; + let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::UnevaluatedConst(id, subst), + }) + } + rustc_type_ir::ConstKind::Value(value_const) => { + let bytes = value_const.value.inner(); + let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::Bytes(bytes.0.clone(), bytes.1.clone()), + }); + return chalk_ir::ConstData { + ty: convert_ty_for_result(interner, value_const.ty), + value, + } + .intern(Interner); + } + rustc_type_ir::ConstKind::Error(_) => { + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::Unknown, + }) + } + rustc_type_ir::ConstKind::Expr(_) => unimplemented!(), + }; + chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) +} + +fn convert_region_for_result<'db>(region: Region<'db>) -> crate::Lifetime { + match region.kind() { + rustc_type_ir::RegionKind::ReEarlyParam(early) => unimplemented!(), + rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( + chalk_ir::DebruijnIndex::new(db.as_u32()), + bound.var.as_usize(), + )), + ), + rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(), + rustc_type_ir::RegionKind::ReStatic => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Static) + } + rustc_type_ir::RegionKind::ReVar(vid) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())), + ), + rustc_type_ir::RegionKind::RePlaceholder(placeholder) => chalk_ir::Lifetime::new( + Interner, + chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { + idx: placeholder.bound.var.as_usize(), + ui: chalk_ir::UniverseIndex { counter: placeholder.universe.as_usize() }, + }), + ), + rustc_type_ir::RegionKind::ReErased => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Erased) + } + rustc_type_ir::RegionKind::ReError(_) => { + chalk_ir::Lifetime::new(Interner, chalk_ir::LifetimeData::Error) + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs new file mode 100644 index 0000000000000..43589ab2ef139 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs @@ -0,0 +1,167 @@ +//! Things related to opaques in the next-trait-solver. + +use intern::Interned; +use rustc_ast_ir::try_visit; + +use crate::next_solver::SolverDefId; + +use super::{CanonicalVarKind, DbInterner, interned_vec_nolifetime_salsa}; + +pub type OpaqueTypeKey<'db> = rustc_type_ir::OpaqueTypeKey>; +pub type PredefinedOpaquesData<'db> = rustc_type_ir::solve::PredefinedOpaquesData>; +pub type ExternalConstraintsData<'db> = + rustc_type_ir::solve::ExternalConstraintsData>; + +#[salsa::interned(constructor = new_, debug)] +pub struct PredefinedOpaques<'db> { + #[returns(ref)] + kind_: rustc_type_ir::solve::PredefinedOpaquesData>, +} + +impl<'db> PredefinedOpaques<'db> { + pub fn new(interner: DbInterner<'db>, data: PredefinedOpaquesData<'db>) -> Self { + PredefinedOpaques::new_(interner.db(), data) + } + + pub fn inner(&self) -> &PredefinedOpaquesData<'db> { + salsa::with_attached_database(|db| { + let inner = self.kind_(db); + // SAFETY: ¯\_(ツ)_/¯ + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } +} + +impl<'db> rustc_type_ir::TypeVisitable> for PredefinedOpaques<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + self.opaque_types.visit_with(visitor) + } +} + +impl<'db> rustc_type_ir::TypeFoldable> for PredefinedOpaques<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(PredefinedOpaques::new( + folder.cx(), + PredefinedOpaquesData { + opaque_types: self + .opaque_types + .iter() + .cloned() + .map(|opaque| opaque.try_fold_with(folder)) + .collect::>()?, + }, + )) + } + fn fold_with>>(self, folder: &mut F) -> Self { + PredefinedOpaques::new( + folder.cx(), + PredefinedOpaquesData { + opaque_types: self + .opaque_types + .iter() + .cloned() + .map(|opaque| opaque.fold_with(folder)) + .collect(), + }, + ) + } +} + +impl<'db> std::ops::Deref for PredefinedOpaques<'db> { + type Target = PredefinedOpaquesData<'db>; + + fn deref(&self) -> &Self::Target { + self.inner() + } +} + +interned_vec_nolifetime_salsa!(SolverDefIds, SolverDefId); + +#[salsa::interned(constructor = new_, debug)] +pub struct ExternalConstraints<'db> { + #[returns(ref)] + kind_: rustc_type_ir::solve::ExternalConstraintsData>, +} + +impl<'db> ExternalConstraints<'db> { + pub fn new(interner: DbInterner<'db>, data: ExternalConstraintsData<'db>) -> Self { + ExternalConstraints::new_(interner.db(), data) + } + + pub fn inner(&self) -> &ExternalConstraintsData<'db> { + salsa::with_attached_database(|db| { + let inner = self.kind_(db); + // SAFETY: ¯\_(ツ)_/¯ + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } +} + +impl<'db> std::ops::Deref for ExternalConstraints<'db> { + type Target = ExternalConstraintsData<'db>; + + fn deref(&self) -> &Self::Target { + self.inner() + } +} + +impl<'db> rustc_type_ir::TypeVisitable> for ExternalConstraints<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + try_visit!(self.region_constraints.visit_with(visitor)); + try_visit!(self.opaque_types.visit_with(visitor)); + self.normalization_nested_goals.visit_with(visitor) + } +} + +impl<'db> rustc_type_ir::TypeFoldable> for ExternalConstraints<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(ExternalConstraints::new( + folder.cx(), + ExternalConstraintsData { + region_constraints: self.region_constraints.clone().try_fold_with(folder)?, + opaque_types: self + .opaque_types + .iter() + .cloned() + .map(|opaque| opaque.try_fold_with(folder)) + .collect::>()?, + normalization_nested_goals: self + .normalization_nested_goals + .clone() + .try_fold_with(folder)?, + }, + )) + } + fn fold_with>>(self, folder: &mut F) -> Self { + ExternalConstraints::new( + folder.cx(), + ExternalConstraintsData { + region_constraints: self.region_constraints.clone().fold_with(folder), + opaque_types: self + .opaque_types + .iter() + .cloned() + .map(|opaque| opaque.fold_with(folder)) + .collect(), + normalization_nested_goals: self + .normalization_nested_goals + .clone() + .fold_with(folder), + }, + ) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs new file mode 100644 index 0000000000000..50261bb5e3816 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -0,0 +1,894 @@ +//! Things related to predicates. + +use std::cmp::Ordering; + +use intern::Interned; +use rustc_ast_ir::try_visit; +use rustc_type_ir::{ + self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags, + PredicatePolarity, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, Upcast, UpcastFrom, VisitorResult, WithCachedTypeInfo, + elaborate::Elaboratable, + error::{ExpectedFound, TypeError}, + inherent::{IntoKind, SliceLike}, + relate::Relate, +}; +use smallvec::{SmallVec, smallvec}; + +use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db}; + +pub type BoundExistentialPredicate<'db> = Binder<'db, ExistentialPredicate<'db>>; + +pub type TraitRef<'db> = ty::TraitRef>; +pub type AliasTerm<'db> = ty::AliasTerm>; +pub type ProjectionPredicate<'db> = ty::ProjectionPredicate>; +pub type ExistentialPredicate<'db> = ty::ExistentialPredicate>; +pub type ExistentialTraitRef<'db> = ty::ExistentialTraitRef>; +pub type ExistentialProjection<'db> = ty::ExistentialProjection>; +pub type TraitPredicate<'db> = ty::TraitPredicate>; +pub type ClauseKind<'db> = ty::ClauseKind>; +pub type PredicateKind<'db> = ty::PredicateKind>; +pub type NormalizesTo<'db> = ty::NormalizesTo>; +pub type CoercePredicate<'db> = ty::CoercePredicate>; +pub type SubtypePredicate<'db> = ty::SubtypePredicate>; +pub type OutlivesPredicate<'db, T> = ty::OutlivesPredicate, T>; +pub type RegionOutlivesPredicate<'db> = OutlivesPredicate<'db, Region<'db>>; +pub type TypeOutlivesPredicate<'db> = OutlivesPredicate<'db, Ty<'db>>; +pub type PolyTraitPredicate<'db> = Binder<'db, TraitPredicate<'db>>; +pub type PolyRegionOutlivesPredicate<'db> = Binder<'db, RegionOutlivesPredicate<'db>>; +pub type PolyTypeOutlivesPredicate<'db> = Binder<'db, TypeOutlivesPredicate<'db>>; +pub type PolySubtypePredicate<'db> = Binder<'db, SubtypePredicate<'db>>; +pub type PolyCoercePredicate<'db> = Binder<'db, CoercePredicate<'db>>; +pub type PolyProjectionPredicate<'db> = Binder<'db, ProjectionPredicate<'db>>; +pub type PolyTraitRef<'db> = Binder<'db, TraitRef<'db>>; +pub type PolyExistentialTraitRef<'db> = Binder<'db, ExistentialTraitRef<'db>>; +pub type PolyExistentialProjection<'db> = Binder<'db, ExistentialProjection<'db>>; + +/// Compares via an ordering that will not change if modules are reordered or other changes are +/// made to the tree. In particular, this ordering is preserved across incremental compilations. +fn stable_cmp_existential_predicate<'db>( + a: &ExistentialPredicate<'db>, + b: &ExistentialPredicate<'db>, +) -> Ordering { + // FIXME: this is actual unstable - see impl in predicate.rs in `rustc_middle` + match (a, b) { + (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal, + (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => { + // Should sort by def path hash + Ordering::Equal + } + (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) => { + // Should sort by def path hash + Ordering::Equal + } + (ExistentialPredicate::Trait(_), _) => Ordering::Less, + (ExistentialPredicate::Projection(_), ExistentialPredicate::Trait(_)) => Ordering::Greater, + (ExistentialPredicate::Projection(_), _) => Ordering::Less, + (ExistentialPredicate::AutoTrait(_), _) => Ordering::Greater, + } +} +interned_vec_db!(BoundExistentialPredicates, BoundExistentialPredicate); + +impl<'db> rustc_type_ir::inherent::BoundExistentialPredicates> + for BoundExistentialPredicates<'db> +{ + fn principal_def_id(self) -> Option< as rustc_type_ir::Interner>::DefId> { + self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) + } + + fn principal( + self, + ) -> Option< + rustc_type_ir::Binder, rustc_type_ir::ExistentialTraitRef>>, + > { + self.inner()[0] + .map_bound(|this| match this { + ExistentialPredicate::Trait(tr) => Some(tr), + _ => None, + }) + .transpose() + } + + fn auto_traits( + self, + ) -> impl IntoIterator as rustc_type_ir::Interner>::DefId> { + self.iter().filter_map(|predicate| match predicate.skip_binder() { + ExistentialPredicate::AutoTrait(did) => Some(did), + _ => None, + }) + } + + fn projection_bounds( + self, + ) -> impl IntoIterator< + Item = rustc_type_ir::Binder< + DbInterner<'db>, + rustc_type_ir::ExistentialProjection>, + >, + > { + self.iter().filter_map(|predicate| { + predicate + .map_bound(|pred| match pred { + ExistentialPredicate::Projection(projection) => Some(projection), + _ => None, + }) + .transpose() + }) + } +} + +impl<'db> rustc_type_ir::relate::Relate> for BoundExistentialPredicates<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + let interner = relation.cx(); + + // We need to perform this deduplication as we sometimes generate duplicate projections in `a`. + let mut a_v: Vec<_> = a.into_iter().collect(); + let mut b_v: Vec<_> = b.into_iter().collect(); + // `skip_binder` here is okay because `stable_cmp` doesn't look at binders + a_v.sort_by(|a, b| { + stable_cmp_existential_predicate(a.as_ref().skip_binder(), b.as_ref().skip_binder()) + }); + a_v.dedup(); + b_v.sort_by(|a, b| { + stable_cmp_existential_predicate(a.as_ref().skip_binder(), b.as_ref().skip_binder()) + }); + b_v.dedup(); + if a_v.len() != b_v.len() { + return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); + } + + let v = std::iter::zip(a_v, b_v).map( + |(ep_a, ep_b): ( + Binder<'_, ty::ExistentialPredicate<_>>, + Binder<'_, ty::ExistentialPredicate<_>>, + )| { + match (ep_a.skip_binder(), ep_b.skip_binder()) { + (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { + Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))) + } + ( + ty::ExistentialPredicate::Projection(a), + ty::ExistentialPredicate::Projection(b), + ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + ( + ty::ExistentialPredicate::AutoTrait(a), + ty::ExistentialPredicate::AutoTrait(b), + ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), + _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))), + } + }, + ); + + CollectAndApply::collect_and_apply(v, |g| { + BoundExistentialPredicates::new_from_iter(interner, g.iter().cloned()) + }) + } +} + +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] +pub struct InternedWrapperNoDebug(pub(crate) T); + +#[salsa::interned(constructor = new_)] +pub struct Predicate<'db> { + #[returns(ref)] + kind_: InternedWrapperNoDebug>>>, +} + +impl<'db> std::fmt::Debug for Predicate<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner().internee.fmt(f) + } +} + +impl<'db> std::fmt::Debug + for InternedWrapperNoDebug>>> +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Binder<")?; + match self.0.internee.skip_binder() { + rustc_type_ir::PredicateKind::Clause(clause_kind) => { + write!(f, "{clause_kind:?}") + } + rustc_type_ir::PredicateKind::DynCompatible(trait_def_id) => { + write!(f, "the trait `{trait_def_id:?}` is dyn-compatible") + } + rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => { + write!(f, "{subtype_predicate:?}") + } + rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => { + write!(f, "{coerce_predicate:?}") + } + rustc_type_ir::PredicateKind::ConstEquate(c1, c2) => { + write!(f, "the constant `{c1:?}` equals `{c2:?}`") + } + rustc_type_ir::PredicateKind::Ambiguous => write!(f, "ambiguous"), + rustc_type_ir::PredicateKind::NormalizesTo(data) => write!(f, "{data:?}"), + rustc_type_ir::PredicateKind::AliasRelate(t1, t2, dir) => { + write!(f, "{t1:?} {dir:?} {t2:?}") + } + }?; + write!(f, ", [{:?}]>", self.0.internee.bound_vars())?; + Ok(()) + } +} + +impl<'db> Predicate<'db> { + pub fn new(interner: DbInterner<'db>, kind: Binder<'db, PredicateKind<'db>>) -> Self { + let flags = FlagComputation::for_predicate(kind); + let cached = WithCachedTypeInfo { + internee: kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; + Predicate::new_(interner.db(), InternedWrapperNoDebug(cached)) + } + + pub fn inner(&self) -> &WithCachedTypeInfo>> { + salsa::with_attached_database(|db| { + let inner = &self.kind_(db).0; + // SAFETY: The caller already has access to a `Predicate<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + + /// Flips the polarity of a Predicate. + /// + /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. + pub fn flip_polarity(self) -> Option> { + let kind = self + .kind() + .map_bound(|kind| match kind { + PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity, + })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: polarity.flip(), + }))), + + _ => None, + }) + .transpose()?; + + Some(Predicate::new(DbInterner::conjure(), kind)) + } + + pub fn as_trait_clause(self) -> Option> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) + | PredicateKind::NormalizesTo(..) + | PredicateKind::AliasRelate(..) + | PredicateKind::Subtype(..) + | PredicateKind::Coerce(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) + | PredicateKind::DynCompatible(..) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) + | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous => None, + } + } +} + +// FIXME: should make a "header" in interned_vec + +#[derive(Debug, Clone)] +pub struct InternedClausesWrapper<'db>(SmallVec<[Clause<'db>; 2]>, TypeFlags, DebruijnIndex); + +impl<'db> PartialEq for InternedClausesWrapper<'db> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl<'db> Eq for InternedClausesWrapper<'db> {} + +impl<'db> std::hash::Hash for InternedClausesWrapper<'db> { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +type InternedClauses<'db> = Interned>; + +#[salsa::interned(constructor = new_)] +pub struct Clauses<'db> { + #[returns(ref)] + inner_: InternedClausesWrapper<'db>, +} + +impl<'db> Clauses<'db> { + pub fn new_from_iter( + interner: DbInterner<'db>, + data: impl IntoIterator>, + ) -> Self { + let clauses: SmallVec<_> = data.into_iter().collect(); + let flags = FlagComputation::>::for_clauses(&clauses); + let wrapper = InternedClausesWrapper(clauses, flags.flags, flags.outer_exclusive_binder); + Clauses::new_(interner.db(), wrapper) + } + + pub fn inner(&self) -> &InternedClausesWrapper<'db> { + salsa::with_attached_database(|db| { + let inner = self.inner_(db); + // SAFETY: The caller already has access to a `Clauses<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } +} + +impl<'db> std::fmt::Debug for Clauses<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner().0.fmt(f) + } +} + +impl<'db> rustc_type_ir::inherent::Clauses> for Clauses<'db> {} + +impl<'db> rustc_type_ir::inherent::SliceLike for Clauses<'db> { + type Item = Clause<'db>; + + type IntoIter = ; 2]> as IntoIterator>::IntoIter; + + fn iter(self) -> Self::IntoIter { + self.inner().0.clone().into_iter() + } + + fn as_slice(&self) -> &[Self::Item] { + self.inner().0.as_slice() + } +} + +impl<'db> IntoIterator for Clauses<'db> { + type Item = Clause<'db>; + type IntoIter = ::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + rustc_type_ir::inherent::SliceLike::iter(self) + } +} + +impl<'db> Default for Clauses<'db> { + fn default() -> Self { + Clauses::new_from_iter(DbInterner::conjure(), []) + } +} + +impl<'db> rustc_type_ir::TypeSuperFoldable> for Clauses<'db> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let mut clauses: SmallVec<[_; 2]> = SmallVec::with_capacity(self.inner().0.len()); + for c in self { + clauses.push(c.try_fold_with(folder)?); + } + Ok(Clauses::new_from_iter(folder.cx(), clauses)) + } + + fn super_fold_with>>( + self, + folder: &mut F, + ) -> Self { + let mut clauses: SmallVec<[_; 2]> = SmallVec::with_capacity(self.inner().0.len()); + for c in self { + clauses.push(c.fold_with(folder)); + } + Clauses::new_from_iter(folder.cx(), clauses) + } +} + +impl<'db> rustc_type_ir::TypeFoldable> for Clauses<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = + self.iter().map(|v| v.try_fold_with(folder)).collect::>()?; + Ok(Clauses::new_from_iter(folder.cx(), inner)) + } + fn fold_with>>(self, folder: &mut F) -> Self { + use rustc_type_ir::inherent::SliceLike as _; + let inner: smallvec::SmallVec<[_; 2]> = self.iter().map(|v| v.fold_with(folder)).collect(); + Clauses::new_from_iter(folder.cx(), inner) + } +} + +impl<'db> rustc_type_ir::TypeVisitable> for Clauses<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + use rustc_ast_ir::visit::VisitorResult; + use rustc_type_ir::inherent::SliceLike as _; + rustc_ast_ir::walk_visitable_list!(visitor, self.as_slice().iter()); + V::Result::output() + } +} + +impl<'db> rustc_type_ir::Flags for Clauses<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + self.inner().1 + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.inner().2 + } +} + +impl<'db> rustc_type_ir::TypeSuperVisitable> for Clauses<'db> { + fn super_visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + self.as_slice().visit_with(visitor) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] // TODO implement Debug by hand +pub struct Clause<'db>(pub(crate) Predicate<'db>); + +// We could cram the reveal into the clauses like rustc does, probably +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ParamEnv<'db> { + pub(crate) clauses: Clauses<'db>, +} + +impl<'db> ParamEnv<'db> { + pub fn empty() -> Self { + ParamEnv { clauses: Clauses::new_from_iter(DbInterner::conjure(), []) } + } +} + +impl<'db> TypeVisitable> for ParamEnv<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + try_visit!(self.clauses.visit_with(visitor)); + V::Result::output() + } +} + +impl<'db> TypeFoldable> for ParamEnv<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(ParamEnv { clauses: self.clauses.try_fold_with(folder)? }) + } + fn fold_with>>(self, folder: &mut F) -> Self { + ParamEnv { clauses: self.clauses.fold_with(folder) } + } +} + +impl<'db> rustc_type_ir::inherent::ParamEnv> for ParamEnv<'db> { + fn caller_bounds(self) -> impl rustc_type_ir::inherent::SliceLike> { + self.clauses + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ParamEnvAnd<'db, T> { + pub param_env: ParamEnv<'db>, + pub value: T, +} + +impl<'db, T> ParamEnvAnd<'db, T> { + pub fn into_parts(self) -> (ParamEnv<'db>, T) { + (self.param_env, self.value) + } +} + +impl<'db> TypeVisitable> for Predicate<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_predicate(*self) + } +} + +impl<'db> TypeSuperVisitable> for Predicate<'db> { + fn super_visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + (*self).kind().visit_with(visitor) + } +} + +impl<'db> TypeFoldable> for Predicate<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + folder.try_fold_predicate(self) + } + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self) + } +} + +impl<'db> TypeSuperFoldable> for Predicate<'db> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let new = self.kind().try_fold_with(folder)?; + Ok(Predicate::new(folder.cx(), new)) + } + fn super_fold_with>>( + self, + folder: &mut F, + ) -> Self { + let new = self.kind().fold_with(folder); + Predicate::new(folder.cx(), new) + } +} + +impl<'db> Elaboratable> for Predicate<'db> { + fn predicate(&self) -> as rustc_type_ir::Interner>::Predicate { + *self + } + + fn child(&self, clause: as rustc_type_ir::Interner>::Clause) -> Self { + clause.as_predicate() + } + + fn child_with_derived_cause( + &self, + clause: as rustc_type_ir::Interner>::Clause, + _span: as rustc_type_ir::Interner>::Span, + _parent_trait_pred: rustc_type_ir::Binder< + DbInterner<'db>, + rustc_type_ir::TraitPredicate>, + >, + _index: usize, + ) -> Self { + clause.as_predicate() + } +} + +impl<'db> Flags for Predicate<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + self.inner().flags + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.inner().outer_exclusive_binder + } +} + +impl<'db> IntoKind for Predicate<'db> { + type Kind = Binder<'db, PredicateKind<'db>>; + + fn kind(self) -> Self::Kind { + self.inner().internee + } +} + +impl<'db> UpcastFrom, ty::PredicateKind>> for Predicate<'db> { + fn upcast_from(from: ty::PredicateKind>, interner: DbInterner<'db>) -> Self { + Binder::dummy(from).upcast(interner) + } +} +impl<'db> + UpcastFrom, ty::Binder, ty::PredicateKind>>> + for Predicate<'db> +{ + fn upcast_from( + from: ty::Binder, ty::PredicateKind>>, + interner: DbInterner<'db>, + ) -> Self { + Predicate::new(interner, from) + } +} +impl<'db> UpcastFrom, ty::ClauseKind>> for Predicate<'db> { + fn upcast_from(from: ty::ClauseKind>, interner: DbInterner<'db>) -> Self { + Binder::dummy(PredicateKind::Clause(from)).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::Binder, ty::ClauseKind>>> + for Predicate<'db> +{ + fn upcast_from( + from: ty::Binder, ty::ClauseKind>>, + interner: DbInterner<'db>, + ) -> Self { + from.map_bound(PredicateKind::Clause).upcast(interner) + } +} +impl<'db> UpcastFrom, Clause<'db>> for Predicate<'db> { + fn upcast_from(from: Clause<'db>, _interner: DbInterner<'db>) -> Self { + from.0 + } +} +impl<'db> UpcastFrom, ty::NormalizesTo>> for Predicate<'db> { + fn upcast_from(from: ty::NormalizesTo>, interner: DbInterner<'db>) -> Self { + PredicateKind::NormalizesTo(from).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::TraitRef>> for Predicate<'db> { + fn upcast_from(from: ty::TraitRef>, interner: DbInterner<'db>) -> Self { + Binder::dummy(from).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::Binder, ty::TraitRef>>> + for Predicate<'db> +{ + fn upcast_from( + from: ty::Binder, ty::TraitRef>>, + interner: DbInterner<'db>, + ) -> Self { + from.map_bound(|trait_ref| TraitPredicate { + trait_ref, + polarity: PredicatePolarity::Positive, + }) + .upcast(interner) + } +} +impl<'db> UpcastFrom, Binder<'db, ty::TraitPredicate>>> + for Predicate<'db> +{ + fn upcast_from( + from: Binder<'db, ty::TraitPredicate>>, + interner: DbInterner<'db>, + ) -> Self { + from.map_bound(|it| PredicateKind::Clause(ClauseKind::Trait(it))).upcast(interner) + } +} +impl<'db> UpcastFrom, Binder<'db, ProjectionPredicate<'db>>> for Predicate<'db> { + fn upcast_from(from: Binder<'db, ProjectionPredicate<'db>>, interner: DbInterner<'db>) -> Self { + from.map_bound(|it| PredicateKind::Clause(ClauseKind::Projection(it))).upcast(interner) + } +} +impl<'db> UpcastFrom, ProjectionPredicate<'db>> for Predicate<'db> { + fn upcast_from(from: ProjectionPredicate<'db>, interner: DbInterner<'db>) -> Self { + PredicateKind::Clause(ClauseKind::Projection(from)).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::TraitPredicate>> for Predicate<'db> { + fn upcast_from(from: ty::TraitPredicate>, interner: DbInterner<'db>) -> Self { + PredicateKind::Clause(ClauseKind::Trait(from)).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::OutlivesPredicate, Ty<'db>>> + for Predicate<'db> +{ + fn upcast_from( + from: ty::OutlivesPredicate, Ty<'db>>, + interner: DbInterner<'db>, + ) -> Self { + PredicateKind::Clause(ClauseKind::TypeOutlives(from)).upcast(interner) + } +} +impl<'db> UpcastFrom, ty::OutlivesPredicate, Region<'db>>> + for Predicate<'db> +{ + fn upcast_from( + from: ty::OutlivesPredicate, Region<'db>>, + interner: DbInterner<'db>, + ) -> Self { + PredicateKind::Clause(ClauseKind::RegionOutlives(from)).upcast(interner) + } +} + +impl<'db> rustc_type_ir::inherent::Predicate> for Predicate<'db> { + fn as_clause(self) -> Option< as rustc_type_ir::Interner>::Clause> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + + /// Whether this projection can be soundly normalized. + /// + /// Wf predicates must not be normalized, as normalization + /// can remove required bounds which would cause us to + /// unsoundly accept some programs. See #91068. + fn allow_normalization(self) -> bool { + // TODO: this should probably live in rustc_type_ir + match self.inner().as_ref().skip_binder() { + PredicateKind::Clause(ClauseKind::WellFormed(_)) + | PredicateKind::AliasRelate(..) + | PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) + | PredicateKind::Clause(ClauseKind::Projection(_)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) + | PredicateKind::DynCompatible(_) + | PredicateKind::Subtype(_) + | PredicateKind::Coerce(_) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) + | PredicateKind::ConstEquate(_, _) + | PredicateKind::Ambiguous => true, + } + } +} + +impl<'db> Predicate<'db> { + /// Assert that the predicate is a clause. + pub fn expect_clause(self) -> Clause<'db> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Clause(self), + _ => panic!("{self:?} is not a clause"), + } + } +} + +impl<'db> TypeVisitable> for Clause<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_predicate((*self).as_predicate()) + } +} + +impl<'db> TypeFoldable> for Clause<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) + } + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_predicate(self.as_predicate()).expect_clause() + } +} + +impl<'db> IntoKind for Clause<'db> { + type Kind = Binder<'db, ClauseKind<'db>>; + + fn kind(self) -> Self::Kind { + self.0.kind().map_bound(|pk| match pk { + PredicateKind::Clause(kind) => kind, + _ => unreachable!(), + }) + } +} + +impl<'db> Clause<'db> { + pub fn as_predicate(self) -> Predicate<'db> { + self.0 + } +} + +impl<'db> Elaboratable> for Clause<'db> { + fn predicate(&self) -> as rustc_type_ir::Interner>::Predicate { + self.0 + } + + fn child(&self, clause: as rustc_type_ir::Interner>::Clause) -> Self { + clause + } + + fn child_with_derived_cause( + &self, + clause: as rustc_type_ir::Interner>::Clause, + _span: as rustc_type_ir::Interner>::Span, + _parent_trait_pred: rustc_type_ir::Binder< + DbInterner<'db>, + rustc_type_ir::TraitPredicate>, + >, + _index: usize, + ) -> Self { + clause + } +} + +impl<'db> UpcastFrom, ty::Binder, ty::ClauseKind>>> + for Clause<'db> +{ + fn upcast_from( + from: ty::Binder, ty::ClauseKind>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.map_bound(PredicateKind::Clause).upcast(interner)) + } +} +impl<'db> UpcastFrom, ty::TraitRef>> for Clause<'db> { + fn upcast_from(from: ty::TraitRef>, interner: DbInterner<'db>) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> UpcastFrom, ty::Binder, ty::TraitRef>>> + for Clause<'db> +{ + fn upcast_from( + from: ty::Binder, ty::TraitRef>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> UpcastFrom, ty::TraitPredicate>> for Clause<'db> { + fn upcast_from(from: ty::TraitPredicate>, interner: DbInterner<'db>) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> + UpcastFrom, ty::Binder, ty::TraitPredicate>>> + for Clause<'db> +{ + fn upcast_from( + from: ty::Binder, ty::TraitPredicate>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> UpcastFrom, ty::ProjectionPredicate>> for Clause<'db> { + fn upcast_from( + from: ty::ProjectionPredicate>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> + UpcastFrom< + DbInterner<'db>, + ty::Binder, ty::ProjectionPredicate>>, + > for Clause<'db> +{ + fn upcast_from( + from: ty::Binder, ty::ProjectionPredicate>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} + +impl<'db> rustc_type_ir::inherent::Clause> for Clause<'db> { + fn as_predicate(self) -> as rustc_type_ir::Interner>::Predicate { + self.0 + } + + fn instantiate_supertrait( + self, + cx: DbInterner<'db>, + trait_ref: rustc_type_ir::Binder, rustc_type_ir::TraitRef>>, + ) -> Self { + tracing::debug!(?self, ?trait_ref); + // See the rustc impl for a long comment + let bound_pred = self.kind(); + let pred_bound_vars = bound_pred.bound_vars(); + let trait_bound_vars = trait_ref.bound_vars(); + // 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1> + let shifted_pred = + cx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); + // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> + let new = EarlyBinder::bind(shifted_pred).instantiate(cx, trait_ref.skip_binder().args); + // 3) ['x] + ['b] -> ['x, 'b] + let bound_vars = + BoundVarKinds::new_from_iter(cx, trait_bound_vars.iter().chain(pred_bound_vars.iter())); + + let predicate: Predicate<'db> = + ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars).upcast(cx); + predicate.expect_clause() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs new file mode 100644 index 0000000000000..e57808728ae96 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project.rs @@ -0,0 +1,3 @@ +//! Projection code for next-solver. + +pub(crate) mod solve_normalize; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs new file mode 100644 index 0000000000000..a8fb2ae14f1c3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs @@ -0,0 +1,264 @@ +//! Normalization within a next-solver infer context. + +use std::fmt::Debug; + +use rustc_next_trait_solver::placeholder::BoundVarReplacer; +use rustc_type_ir::{ + AliasRelationDirection, FallibleTypeFolder, Flags, Interner, TermKind, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, + inherent::{IntoKind, Span as _, Term as _}, +}; + +use crate::next_solver::{ + Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Span, Term, Ty, + TyKind, + fulfill::{FulfillmentCtxt, NextSolverError}, + infer::{ + InferCtxt, + at::At, + traits::{Obligation, ObligationCause}, + }, + util::PlaceholderReplacer, +}; + +/// Deeply normalize all aliases in `value`. This does not handle inference and expects +/// its input to be already fully resolved. +pub fn deeply_normalize<'db, T>(at: At<'_, 'db>, value: T) -> Result>> +where + T: TypeFoldable>, +{ + assert!(!value.has_escaping_bound_vars()); + deeply_normalize_with_skipped_universes(at, value, vec![]) +} + +/// Deeply normalize all aliases in `value`. This does not handle inference and expects +/// its input to be already fully resolved. +/// +/// Additionally takes a list of universes which represents the binders which have been +/// entered before passing `value` to the function. This is currently needed for +/// `normalize_erasing_regions`, which skips binders as it walks through a type. +pub fn deeply_normalize_with_skipped_universes<'db, T>( + at: At<'_, 'db>, + value: T, + universes: Vec>, +) -> Result>> +where + T: TypeFoldable>, +{ + let (value, coroutine_goals) = + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + at, value, universes, + )?; + assert_eq!(coroutine_goals, vec![]); + + Ok(value) +} + +/// Deeply normalize all aliases in `value`. This does not handle inference and expects +/// its input to be already fully resolved. +/// +/// Additionally takes a list of universes which represents the binders which have been +/// entered before passing `value` to the function. This is currently needed for +/// `normalize_erasing_regions`, which skips binders as it walks through a type. +/// +/// This returns a set of stalled obligations involving coroutines if the typing mode of +/// the underlying infcx has any stalled coroutine def ids. +pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'db, T>( + at: At<'_, 'db>, + value: T, + universes: Vec>, +) -> Result<(T, Vec>>), Vec>> +where + T: TypeFoldable>, +{ + let fulfill_cx = FulfillmentCtxt::new(at.infcx); + let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes }; + let value = value.try_fold_with(&mut folder)?; + let errors = folder.fulfill_cx.select_all_or_error(at.infcx); + if errors.is_empty() { Ok((value, vec![])) } else { Err(errors) } +} + +struct NormalizationFolder<'me, 'db> { + at: At<'me, 'db>, + fulfill_cx: FulfillmentCtxt<'db>, + depth: usize, + universes: Vec>, +} + +impl<'db> NormalizationFolder<'_, 'db> { + fn normalize_alias_term( + &mut self, + alias_term: Term<'db>, + ) -> Result, Vec>> { + let infcx = self.at.infcx; + let tcx = infcx.interner; + let recursion_limit = tcx.recursion_limit(); + if self.depth > recursion_limit { + return Err(vec![]); + } + + self.depth += 1; + + let infer_term = infcx.next_term_var_of_kind(alias_term); + let obligation = Obligation::new( + tcx, + self.at.cause.clone(), + self.at.param_env, + PredicateKind::AliasRelate(alias_term, infer_term, AliasRelationDirection::Equate), + ); + + self.fulfill_cx.register_predicate_obligation(infcx, obligation); + self.select_all_and_stall_coroutine_predicates()?; + + // Alias is guaranteed to be fully structurally resolved, + // so we can super fold here. + let term = infcx.resolve_vars_if_possible(infer_term); + // super-folding the `term` will directly fold the `Ty` or `Const` so + // we have to match on the term and super-fold them manually. + let result = match term.kind() { + TermKind::Ty(ty) => ty.try_super_fold_with(self)?.into(), + TermKind::Const(ct) => ct.try_super_fold_with(self)?.into(), + }; + self.depth -= 1; + Ok(result) + } + + fn select_all_and_stall_coroutine_predicates( + &mut self, + ) -> Result<(), Vec>> { + let errors = self.fulfill_cx.select_where_possible(self.at.infcx); + if !errors.is_empty() { + return Err(errors); + } + + let errors = self.fulfill_cx.collect_remaining_errors(self.at.infcx); + if !errors.is_empty() { + return Err(errors); + } + + Ok(()) + } +} + +impl<'db> FallibleTypeFolder> for NormalizationFolder<'_, 'db> { + type Error = Vec>; + + fn cx(&self) -> DbInterner<'db> { + self.at.infcx.interner + } + + fn try_fold_binder>>( + &mut self, + t: Binder<'db, T>, + ) -> Result, Self::Error> { + self.universes.push(None); + let t = t.try_super_fold_with(self)?; + self.universes.pop(); + Ok(t) + } + + #[tracing::instrument(level = "trace", skip(self), ret)] + fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result, Self::Error> { + let infcx = self.at.infcx; + debug_assert_eq!(ty, infcx.shallow_resolve(ty)); + if !ty.has_aliases() { + return Ok(ty); + } + + let TyKind::Alias(..) = ty.kind() else { return ty.try_super_fold_with(self) }; + + if ty.has_escaping_bound_vars() { + let (ty, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); + let result = self.normalize_alias_term(ty.into())?.expect_type(); + Ok(PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result, + )) + } else { + Ok(self.normalize_alias_term(ty.into())?.expect_type()) + } + } + + #[tracing::instrument(level = "trace", skip(self), ret)] + fn try_fold_const(&mut self, ct: Const<'db>) -> Result, Self::Error> { + let infcx = self.at.infcx; + debug_assert_eq!(ct, infcx.shallow_resolve_const(ct)); + if !ct.has_aliases() { + return Ok(ct); + } + + let ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) }; + + if ct.has_escaping_bound_vars() { + let (ct, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct); + let result = self.normalize_alias_term(ct.into())?.expect_const(); + Ok(PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result, + )) + } else { + Ok(self.normalize_alias_term(ct.into())?.expect_const()) + } + } +} + +// Deeply normalize a value and return it +pub(crate) fn deeply_normalize_for_diagnostics<'db, T: TypeFoldable>>( + infcx: &InferCtxt<'db>, + param_env: ParamEnv<'db>, + t: T, +) -> T { + t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder { + at: infcx.at(&ObligationCause::dummy(), param_env), + }) +} + +struct DeeplyNormalizeForDiagnosticsFolder<'a, 'db> { + at: At<'a, 'db>, +} + +impl<'db> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.at.infcx.interner + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + let infcx = self.at.infcx; + let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + }); + match result { + Ok((ty, _)) => ty, + Err(_) => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + let infcx = self.at.infcx; + let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + }); + match result { + Ok((ct, _)) => ct, + Err(_) => ct.super_fold_with(self), + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs new file mode 100644 index 0000000000000..c59cdac5f99f6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -0,0 +1,332 @@ +//! Things related to regions. + +use intern::{Interned, Symbol}; +use rustc_type_ir::{ + BoundVar, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable, VisitorResult, + inherent::{IntoKind, PlaceholderLike, SliceLike}, + relate::Relate, +}; + +use crate::next_solver::{GenericArg, OutlivesPredicate}; + +use super::{ + ErrorGuaranteed, SolverDefId, interned_vec_db, + interner::{BoundVarKind, DbInterner, Placeholder}, +}; + +type RegionKind<'db> = rustc_type_ir::RegionKind>; + +#[salsa::interned(constructor = new_, debug)] +pub struct Region<'db> { + #[returns(ref)] + kind_: RegionKind<'db>, +} + +impl<'db> Region<'db> { + pub fn new(interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { + Region::new_(interner.db(), kind) + } + + pub fn inner(&self) -> &RegionKind<'db> { + salsa::with_attached_database(|db| { + let inner = self.kind_(db); + // SAFETY: The caller already has access to a `Region<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute::<&RegionKind<'_>, &RegionKind<'db>>(inner) } + }) + .unwrap() + } + + pub fn new_early_param( + interner: DbInterner<'db>, + early_bound_region: EarlyParamRegion, + ) -> Self { + Region::new(interner, RegionKind::ReEarlyParam(early_bound_region)) + } + + pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderRegion) -> Self { + Region::new(interner, RegionKind::RePlaceholder(placeholder)) + } + + pub fn new_var(interner: DbInterner<'db>, v: RegionVid) -> Region<'db> { + Region::new(interner, RegionKind::ReVar(v)) + } + + pub fn is_placeholder(&self) -> bool { + matches!(self.inner(), RegionKind::RePlaceholder(..)) + } + + pub fn is_static(&self) -> bool { + matches!(self.inner(), RegionKind::ReStatic) + } + + pub fn error(interner: DbInterner<'db>) -> Self { + Region::new(interner, RegionKind::ReError(ErrorGuaranteed)) + } + + pub fn type_flags(&self) -> TypeFlags { + let mut flags = TypeFlags::empty(); + + match &self.inner() { + RegionKind::ReVar(..) => { + flags |= TypeFlags::HAS_FREE_REGIONS; + flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags |= TypeFlags::HAS_RE_INFER; + } + RegionKind::RePlaceholder(..) => { + flags |= TypeFlags::HAS_FREE_REGIONS; + flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags |= TypeFlags::HAS_RE_PLACEHOLDER; + } + RegionKind::ReEarlyParam(..) => { + flags |= TypeFlags::HAS_FREE_REGIONS; + flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags |= TypeFlags::HAS_RE_PARAM; + } + RegionKind::ReLateParam(..) => { + flags |= TypeFlags::HAS_FREE_REGIONS; + flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS; + } + RegionKind::ReStatic => { + flags |= TypeFlags::HAS_FREE_REGIONS; + } + RegionKind::ReBound(..) => { + flags |= TypeFlags::HAS_RE_BOUND; + } + RegionKind::ReErased => { + flags |= TypeFlags::HAS_RE_ERASED; + } + RegionKind::ReError(..) => { + flags |= TypeFlags::HAS_FREE_REGIONS; + flags |= TypeFlags::HAS_ERROR; + } + } + + flags + } +} + +pub type PlaceholderRegion = Placeholder; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct EarlyParamRegion { + pub index: u32, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +/// The parameter representation of late-bound function parameters, "some region +/// at least as big as the scope `fr.scope`". +/// +/// Similar to a placeholder region as we create `LateParam` regions when entering a binder +/// except they are always in the root universe and instead of using a boundvar to distinguish +/// between others we use the `DefId` of the parameter. For this reason the `bound_region` field +/// should basically always be `BoundRegionKind::Named` as otherwise there is no way of telling +/// different parameters apart. +pub struct LateParamRegion { + pub scope: SolverDefId, + pub bound_region: BoundRegionKind, +} + +impl std::fmt::Debug for LateParamRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ReLateParam({:?}, {:?})", self.scope, self.bound_region) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum BoundRegionKind { + /// An anonymous region parameter for a given fn (&T) + Anon, + + /// Named region parameters for functions (a in &'a T) + /// + /// The `DefId` is needed to distinguish free regions in + /// the event of shadowing. + Named(SolverDefId), + + /// Anonymous region for the implicit env pointer parameter + /// to a closure + ClosureEnv, +} + +impl std::fmt::Debug for BoundRegionKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + BoundRegionKind::Anon => write!(f, "BrAnon"), + BoundRegionKind::Named(did) => { + write!(f, "BrNamed({did:?})") + } + BoundRegionKind::ClosureEnv => write!(f, "BrEnv"), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct BoundRegion { + pub var: BoundVar, + pub kind: BoundRegionKind, +} + +impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion { + fn index(self) -> u32 { + self.index + } +} + +impl std::fmt::Debug for EarlyParamRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#{}", self.index) + // write!(f, "{}/#{}", self.name, self.index) + } +} + +impl<'db> rustc_type_ir::inherent::BoundVarLike> for BoundRegion { + fn var(self) -> BoundVar { + self.var + } + + fn assert_eq(self, var: BoundVarKind) { + assert_eq!(self.kind, var.expect_region()) + } +} + +impl core::fmt::Debug for BoundRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.kind { + BoundRegionKind::Anon => write!(f, "{:?}", self.var), + BoundRegionKind::ClosureEnv => write!(f, "{:?}.Env", self.var), + BoundRegionKind::Named(def) => { + write!(f, "{:?}.Named({:?})", self.var, def) + } + } + } +} + +impl BoundRegionKind { + pub fn is_named(&self) -> bool { + matches!(self, BoundRegionKind::Named(_)) + } + + pub fn get_name(&self) -> Option { + None + } + + pub fn get_id(&self) -> Option { + match self { + BoundRegionKind::Named(id) => Some(*id), + _ => None, + } + } +} + +impl<'db> IntoKind for Region<'db> { + type Kind = RegionKind<'db>; + + fn kind(self) -> Self::Kind { + *self.inner() + } +} + +impl<'db> TypeVisitable> for Region<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_region(*self) + } +} + +impl<'db> TypeFoldable> for Region<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + folder.try_fold_region(self) + } + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_region(self) + } +} + +impl<'db> Relate> for Region<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + relation.regions(a, b) + } +} + +impl<'db> Flags for Region<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + self.type_flags() + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + match &self.inner() { + RegionKind::ReBound(debruijn, _) => debruijn.shifted_in(1), + _ => INNERMOST, + } + } +} + +impl<'db> rustc_type_ir::inherent::Region> for Region<'db> { + fn new_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: BoundRegion, + ) -> Self { + Region::new(interner, RegionKind::ReBound(debruijn, var)) + } + + fn new_anon_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: rustc_type_ir::BoundVar, + ) -> Self { + Region::new( + interner, + RegionKind::ReBound(debruijn, BoundRegion { var, kind: BoundRegionKind::Anon }), + ) + } + + fn new_static(interner: DbInterner<'db>) -> Self { + Region::new(interner, RegionKind::ReStatic) + } + + fn new_placeholder( + interner: DbInterner<'db>, + var: as rustc_type_ir::Interner>::PlaceholderRegion, + ) -> Self { + Region::new(interner, RegionKind::RePlaceholder(var)) + } +} + +impl<'db> PlaceholderLike> for PlaceholderRegion { + type Bound = BoundRegion; + + fn universe(self) -> rustc_type_ir::UniverseIndex { + self.universe + } + + fn var(self) -> rustc_type_ir::BoundVar { + self.bound.var + } + + fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self { + Placeholder { universe: ui, bound: self.bound } + } + + fn new(ui: rustc_type_ir::UniverseIndex, bound: Self::Bound) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { + Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } } + } +} + +type GenericArgOutlivesPredicate<'db> = OutlivesPredicate<'db, GenericArg<'db>>; + +interned_vec_db!(RegionAssumptions, GenericArgOutlivesPredicate); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs new file mode 100644 index 0000000000000..45888ac4d2352 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -0,0 +1,289 @@ +//! Defining `SolverContext` for next-trait-solver. + +use hir_def::{AssocItemId, GeneralConstId, TypeAliasId}; +use rustc_next_trait_solver::delegate::SolverDelegate; +use rustc_type_ir::{ + InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex, + inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _}, + lang_items::TraitSolverLangItem, + solve::{Certainty, NoSolution}, +}; + +use crate::{ + TraitRefExt, + db::HirDatabase, + next_solver::{ + ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, + mapping::{ChalkToNextSolver, convert_args_for_result}, + util::sizedness_fast_path, + }, +}; + +use super::{ + Canonical, CanonicalVarValues, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + ParamEnv, Predicate, SolverDefId, Span, Ty, UnevaluatedConst, + infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt}, +}; + +pub type Goal<'db, P> = rustc_type_ir::solve::Goal, P>; + +#[repr(transparent)] +pub(crate) struct SolverContext<'db>(pub(crate) InferCtxt<'db>); + +impl<'a, 'db> From<&'a InferCtxt<'db>> for &'a SolverContext<'db> { + fn from(infcx: &'a InferCtxt<'db>) -> Self { + // SAFETY: `repr(transparent)` + unsafe { std::mem::transmute(infcx) } + } +} + +impl<'db> std::ops::Deref for SolverContext<'db> { + type Target = InferCtxt<'db>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'db> SolverDelegate for SolverContext<'db> { + type Interner = DbInterner<'db>; + type Infcx = InferCtxt<'db>; + + fn cx(&self) -> Self::Interner { + self.0.interner + } + + fn build_with_canonical( + cx: Self::Interner, + canonical: &rustc_type_ir::CanonicalQueryInput, + ) -> (Self, V, rustc_type_ir::CanonicalVarValues) + where + V: rustc_type_ir::TypeFoldable, + { + let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(canonical); + (SolverContext(infcx), value, vars) + } + + fn fresh_var_for_kind_with_span( + &self, + arg: ::GenericArg, + span: ::Span, + ) -> ::GenericArg { + unimplemented!() + } + + fn leak_check( + &self, + max_input_universe: rustc_type_ir::UniverseIndex, + ) -> Result<(), NoSolution> { + Ok(()) + } + + fn well_formed_goals( + &self, + param_env: ::ParamEnv, + arg: ::Term, + ) -> Option< + Vec< + rustc_type_ir::solve::Goal< + Self::Interner, + ::Predicate, + >, + >, + > { + unimplemented!() + } + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec< + rustc_type_ir::OutlivesPredicate< + Self::Interner, + ::GenericArg, + >, + > { + // FIXME: add if we care about regions + vec![] + } + + fn instantiate_canonical( + &self, + canonical: rustc_type_ir::Canonical, + values: rustc_type_ir::CanonicalVarValues, + ) -> V + where + V: rustc_type_ir::TypeFoldable, + { + canonical.instantiate(self.cx(), &values) + } + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: rustc_type_ir::CanonicalVarKind, + _span: ::Span, + universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex, + ) -> ::GenericArg { + self.0.instantiate_canonical_var(cv_info, universe_map) + } + + fn add_item_bounds_for_hidden_type( + &self, + def_id: ::DefId, + args: ::GenericArgs, + param_env: ::ParamEnv, + hidden_ty: ::Ty, + goals: &mut Vec< + rustc_type_ir::solve::Goal< + Self::Interner, + ::Predicate, + >, + >, + ) { + unimplemented!() + } + + fn fetch_eligible_assoc_item( + &self, + goal_trait_ref: rustc_type_ir::TraitRef, + trait_assoc_def_id: ::DefId, + impl_def_id: ::DefId, + ) -> Result::DefId>, ErrorGuaranteed> { + let impl_id = match impl_def_id { + SolverDefId::ImplId(id) => id, + _ => panic!("Unexpected SolverDefId"), + }; + let trait_assoc_id = match trait_assoc_def_id { + SolverDefId::TypeAliasId(id) => id, + _ => panic!("Unexpected SolverDefId"), + }; + let trait_ref = self + .0 + .interner + .db() + .impl_trait(impl_id) + // ImplIds for impls where the trait ref can't be resolved should never reach solver + .expect("invalid impl passed to next-solver") + .into_value_and_skipped_binders() + .0; + let trait_ = trait_ref.hir_trait_id(); + let trait_data = trait_.trait_items(self.0.interner.db()); + let id = + impl_id.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> { + match item { + (_, AssocItemId::TypeAliasId(type_alias)) => { + let name = &self.0.interner.db().type_alias_signature(*type_alias).name; + let found_trait_assoc_id = trait_data.associated_type_by_name(name)?; + (found_trait_assoc_id == trait_assoc_id).then_some(*type_alias) + } + _ => None, + } + }); + Ok(id.map(SolverDefId::TypeAliasId)) + } + + fn is_transmutable( + &self, + dst: ::Ty, + src: ::Ty, + assume: ::Const, + ) -> Result { + unimplemented!() + } + + fn evaluate_const( + &self, + param_env: ::ParamEnv, + uv: rustc_type_ir::UnevaluatedConst, + ) -> Option<::Const> { + let c = match uv.def { + SolverDefId::ConstId(c) => GeneralConstId::ConstId(c), + SolverDefId::StaticId(c) => GeneralConstId::StaticId(c), + _ => unreachable!(), + }; + let subst = convert_args_for_result(self.interner, uv.args.as_slice()); + let ec = self.cx().db.const_eval(c, subst, None).ok()?; + Some(ec.to_nextsolver(self.interner)) + } + + fn compute_goal_fast_path( + &self, + goal: rustc_type_ir::solve::Goal< + Self::Interner, + ::Predicate, + >, + span: ::Span, + ) -> Option { + if let Some(trait_pred) = goal.predicate.as_trait_clause() { + if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() + // We don't do this fast path when opaques are defined since we may + // eventually use opaques to incompletely guide inference via ty var + // self types. + // FIXME: Properly consider opaques here. + && self.inner.borrow_mut().opaque_types().is_empty() + { + return Some(Certainty::AMBIGUOUS); + } + + if trait_pred.polarity() == PredicatePolarity::Positive { + match self.0.cx().as_lang_item(trait_pred.def_id()) { + Some(TraitSolverLangItem::Sized) | Some(TraitSolverLangItem::MetaSized) => { + let predicate = self.resolve_vars_if_possible(goal.predicate); + if sizedness_fast_path(self.cx(), predicate, goal.param_env) { + return Some(Certainty::Yes); + } + } + Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { + let self_ty = + self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); + // Unlike `Sized` traits, which always prefer the built-in impl, + // `Copy`/`Clone` may be shadowed by a param-env candidate which + // could force a lifetime error or guide inference. While that's + // not generally desirable, it is observable, so for now let's + // ignore this fast path for types that have regions or infer. + if !self_ty + .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER) + && self_ty.is_trivially_pure_clone_copy() + { + return Some(Certainty::Yes); + } + } + _ => {} + } + } + } + + let pred = goal.predicate.kind(); + match pred.no_bound_vars()? { + PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => Some(Certainty::Yes), + PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => Some(Certainty::Yes), + PredicateKind::Subtype(SubtypePredicate { a, b, .. }) + | PredicateKind::Coerce(CoercePredicate { a, b }) => { + if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { + // FIXME: We also need to register a subtype relation between these vars + // when those are added, and if they aren't in the same sub root then + // we should mark this goal as `has_changed`. + Some(Certainty::AMBIGUOUS) + } else { + None + } + } + PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, _)) => { + if self.shallow_resolve_const(ct).is_ct_infer() { + Some(Certainty::AMBIGUOUS) + } else { + None + } + } + PredicateKind::Clause(ClauseKind::WellFormed(arg)) => { + if arg.is_trivially_wf(self.interner) { + Some(Certainty::Yes) + } else if arg.is_infer() { + Some(Certainty::AMBIGUOUS) + } else { + None + } + } + _ => None, + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs new file mode 100644 index 0000000000000..0c0fe686b77d1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -0,0 +1,943 @@ +//! Things related to tys in the next-trait-solver. + +use intern::{Interned, Symbol, sym}; +use rustc_abi::{Float, Integer, Size}; +use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; +use rustc_type_ir::{ + BoundVar, ClosureKind, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, + TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, UintTy, + WithCachedTypeInfo, + inherent::{ + AdtDef, BoundVarLike, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, SliceLike, + }, + relate::Relate, + solve::SizedTraitKind, + walk::TypeWalker, +}; +use salsa::plumbing::{AsId, FromId}; +use smallvec::SmallVec; + +use crate::{ + db::HirDatabase, + interner::InternedWrapperNoDebug, + next_solver::util::{CoroutineArgsExt, IntegerTypeExt}, +}; + +use super::{ + BoundVarKind, DbInterner, GenericArgs, Placeholder, SolverDefId, interned_vec_db, + util::{FloatExt, IntegerExt}, +}; + +pub type TyKind<'db> = rustc_type_ir::TyKind>; +pub type FnHeader<'db> = rustc_type_ir::FnHeader>; + +#[salsa::interned(constructor = new_)] +pub struct Ty<'db> { + #[returns(ref)] + kind_: InternedWrapperNoDebug>>, +} + +const _: () = { + const fn is_copy() {} + is_copy::>(); +}; + +impl<'db> Ty<'db> { + pub fn new(interner: DbInterner<'db>, kind: TyKind<'db>) -> Self { + let flags = FlagComputation::for_kind(&kind); + let cached = WithCachedTypeInfo { + internee: kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; + Ty::new_(interner.db(), InternedWrapperNoDebug(cached)) + } + + pub fn inner(&self) -> &WithCachedTypeInfo> { + salsa::with_attached_database(|db| { + let inner = &self.kind_(db).0; + // SAFETY: The caller already has access to a `Ty<'db>`, so borrowchecking will + // make sure that our returned value is valid for the lifetime `'db`. + unsafe { std::mem::transmute(inner) } + }) + .unwrap() + } + + pub fn new_param(interner: DbInterner<'db>, index: u32, name: Symbol) -> Self { + Ty::new(interner, TyKind::Param(ParamTy { index })) + } + + pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderTy) -> Self { + Ty::new(interner, TyKind::Placeholder(placeholder)) + } + + pub fn new_infer(interner: DbInterner<'db>, infer: InferTy) -> Self { + Ty::new(interner, TyKind::Infer(infer)) + } + + pub fn new_int_var(interner: DbInterner<'db>, v: IntVid) -> Self { + Ty::new_infer(interner, InferTy::IntVar(v)) + } + + pub fn new_float_var(interner: DbInterner<'db>, v: FloatVid) -> Self { + Ty::new_infer(interner, InferTy::FloatVar(v)) + } + + pub fn new_int(interner: DbInterner<'db>, i: IntTy) -> Self { + Ty::new(interner, TyKind::Int(i)) + } + + pub fn new_uint(interner: DbInterner<'db>, ui: UintTy) -> Self { + Ty::new(interner, TyKind::Uint(ui)) + } + + pub fn new_float(interner: DbInterner<'db>, f: FloatTy) -> Self { + Ty::new(interner, TyKind::Float(f)) + } + + pub fn new_fresh(interner: DbInterner<'db>, n: u32) -> Self { + Ty::new_infer(interner, InferTy::FreshTy(n)) + } + + pub fn new_fresh_int(interner: DbInterner<'db>, n: u32) -> Self { + Ty::new_infer(interner, InferTy::FreshIntTy(n)) + } + + pub fn new_fresh_float(interner: DbInterner<'db>, n: u32) -> Self { + Ty::new_infer(interner, InferTy::FreshFloatTy(n)) + } + + /// Returns the `Size` for primitive types (bool, uint, int, char, float). + pub fn primitive_size(self, interner: DbInterner<'db>) -> Size { + match self.kind() { + TyKind::Bool => Size::from_bytes(1), + TyKind::Char => Size::from_bytes(4), + TyKind::Int(ity) => Integer::from_int_ty(&interner, ity).size(), + TyKind::Uint(uty) => Integer::from_uint_ty(&interner, uty).size(), + TyKind::Float(fty) => Float::from_float_ty(fty).size(), + _ => panic!("non primitive type"), + } + } + + pub fn int_size_and_signed(self, interner: DbInterner<'db>) -> (Size, bool) { + match self.kind() { + TyKind::Int(ity) => (Integer::from_int_ty(&interner, ity).size(), true), + TyKind::Uint(uty) => (Integer::from_uint_ty(&interner, uty).size(), false), + _ => panic!("non integer discriminant"), + } + } + + pub fn walk(self) -> TypeWalker> { + TypeWalker::new(self.into()) + } + + /// Fast path helper for testing if a type is `Sized` or `MetaSized`. + /// + /// Returning true means the type is known to implement the sizedness trait. Returning `false` + /// means nothing -- could be sized, might not be. + /// + /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized` + /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with + /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck. + /// This is why this method doesn't return `Option`. + #[tracing::instrument(skip(tcx), level = "debug")] + pub fn has_trivial_sizedness(self, tcx: DbInterner<'db>, sizedness: SizedTraitKind) -> bool { + match self.kind() { + TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) + | TyKind::Uint(_) + | TyKind::Int(_) + | TyKind::Bool + | TyKind::Float(_) + | TyKind::FnDef(..) + | TyKind::FnPtr(..) + | TyKind::UnsafeBinder(_) + | TyKind::RawPtr(..) + | TyKind::Char + | TyKind::Ref(..) + | TyKind::Coroutine(..) + | TyKind::CoroutineWitness(..) + | TyKind::Array(..) + | TyKind::Pat(..) + | TyKind::Closure(..) + | TyKind::CoroutineClosure(..) + | TyKind::Never + | TyKind::Error(_) => true, + + TyKind::Str | TyKind::Slice(_) | TyKind::Dynamic(_, _, _) => match sizedness { + SizedTraitKind::Sized => false, + SizedTraitKind::MetaSized => true, + }, + + TyKind::Foreign(..) => match sizedness { + SizedTraitKind::Sized | SizedTraitKind::MetaSized => false, + }, + + TyKind::Tuple(tys) => { + tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)) + } + + TyKind::Adt(def, args) => def + .sizedness_constraint(tcx, sizedness) + .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)), + + TyKind::Alias(..) | TyKind::Param(_) | TyKind::Placeholder(..) | TyKind::Bound(..) => { + false + } + + TyKind::Infer(InferTy::TyVar(_)) => false, + + TyKind::Infer( + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_), + ) => { + panic!("`has_trivial_sizedness` applied to unexpected type: {self:?}") + } + } + } + + /// Fast path helper for primitives which are always `Copy` and which + /// have a side-effect-free `Clone` impl. + /// + /// Returning true means the type is known to be pure and `Copy+Clone`. + /// Returning `false` means nothing -- could be `Copy`, might not be. + /// + /// This is mostly useful for optimizations, as these are the types + /// on which we can replace cloning with dereferencing. + pub fn is_trivially_pure_clone_copy(self) -> bool { + match self.kind() { + TyKind::Bool | TyKind::Char | TyKind::Never => true, + + // These aren't even `Clone` + TyKind::Str | TyKind::Slice(..) | TyKind::Foreign(..) | TyKind::Dynamic(..) => false, + + TyKind::Infer(InferTy::FloatVar(_) | InferTy::IntVar(_)) + | TyKind::Int(..) + | TyKind::Uint(..) + | TyKind::Float(..) => true, + + // ZST which can't be named are fine. + TyKind::FnDef(..) => true, + + TyKind::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(), + + // A 100-tuple isn't "trivial", so doing this only for reasonable sizes. + TyKind::Tuple(field_tys) => { + field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy) + } + + TyKind::Pat(ty, _) => ty.is_trivially_pure_clone_copy(), + + // Sometimes traits aren't implemented for every ABI or arity, + // because we can't be generic over everything yet. + TyKind::FnPtr(..) => false, + + // Definitely absolutely not copy. + TyKind::Ref(_, _, Mutability::Mut) => false, + + // The standard library has a blanket Copy impl for shared references and raw pointers, + // for all unsized types. + TyKind::Ref(_, _, Mutability::Not) | TyKind::RawPtr(..) => true, + + TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) => false, + + // Might be, but not "trivial" so just giving the safe answer. + TyKind::Adt(..) | TyKind::Closure(..) | TyKind::CoroutineClosure(..) => false, + + TyKind::UnsafeBinder(_) => false, + + // Needs normalization or revealing to determine, so no is the safe answer. + TyKind::Alias(..) => false, + + TyKind::Param(..) + | TyKind::Placeholder(..) + | TyKind::Bound(..) + | TyKind::Infer(..) + | TyKind::Error(..) => false, + } + } + + pub fn is_trivially_wf(self, tcx: DbInterner<'db>) -> bool { + match self.kind() { + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Str + | TyKind::Never + | TyKind::Param(_) + | TyKind::Placeholder(_) + | TyKind::Bound(..) => true, + + TyKind::Slice(ty) => { + ty.is_trivially_wf(tcx) && ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) + } + TyKind::RawPtr(ty, _) => ty.is_trivially_wf(tcx), + + TyKind::FnPtr(sig_tys, _) => { + sig_tys.skip_binder().inputs_and_output.iter().all(|ty| ty.is_trivially_wf(tcx)) + } + TyKind::Ref(_, ty, _) => ty.is_global() && ty.is_trivially_wf(tcx), + + TyKind::Infer(infer) => match infer { + InferTy::TyVar(_) => false, + InferTy::IntVar(_) | InferTy::FloatVar(_) => true, + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => true, + }, + + TyKind::Adt(_, _) + | TyKind::Tuple(_) + | TyKind::Array(..) + | TyKind::Foreign(_) + | TyKind::Pat(_, _) + | TyKind::FnDef(..) + | TyKind::UnsafeBinder(..) + | TyKind::Dynamic(..) + | TyKind::Closure(..) + | TyKind::CoroutineClosure(..) + | TyKind::Coroutine(..) + | TyKind::CoroutineWitness(..) + | TyKind::Alias(..) + | TyKind::Error(_) => false, + } + } +} + +impl<'db> std::fmt::Debug for Ty<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner().internee.fmt(f) + } +} + +impl<'db> std::fmt::Debug for InternedWrapperNoDebug>> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.internee.fmt(f) + } +} + +impl<'db> IntoKind for Ty<'db> { + type Kind = TyKind<'db>; + + fn kind(self) -> Self::Kind { + self.inner().internee + } +} + +impl<'db> TypeVisitable> for Ty<'db> { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_ty(*self) + } +} + +impl<'db> TypeSuperVisitable> for Ty<'db> { + fn super_visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + match (*self).kind() { + TyKind::RawPtr(ty, _mutbl) => ty.visit_with(visitor), + TyKind::Array(typ, sz) => { + try_visit!(typ.visit_with(visitor)); + sz.visit_with(visitor) + } + TyKind::Slice(typ) => typ.visit_with(visitor), + TyKind::Adt(_, args) => args.visit_with(visitor), + TyKind::Dynamic(ref trait_ty, ref reg, _) => { + try_visit!(trait_ty.visit_with(visitor)); + reg.visit_with(visitor) + } + TyKind::Tuple(ts) => ts.visit_with(visitor), + TyKind::FnDef(_, args) => args.visit_with(visitor), + TyKind::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor), + TyKind::UnsafeBinder(f) => f.visit_with(visitor), + TyKind::Ref(r, ty, _) => { + try_visit!(r.visit_with(visitor)); + ty.visit_with(visitor) + } + TyKind::Coroutine(_did, ref args) => args.visit_with(visitor), + TyKind::CoroutineWitness(_did, ref args) => args.visit_with(visitor), + TyKind::Closure(_did, ref args) => args.visit_with(visitor), + TyKind::CoroutineClosure(_did, ref args) => args.visit_with(visitor), + TyKind::Alias(_, ref data) => data.visit_with(visitor), + + TyKind::Pat(ty, pat) => { + try_visit!(ty.visit_with(visitor)); + pat.visit_with(visitor) + } + + TyKind::Error(guar) => guar.visit_with(visitor), + + TyKind::Bool + | TyKind::Char + | TyKind::Str + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Infer(_) + | TyKind::Bound(..) + | TyKind::Placeholder(..) + | TyKind::Param(..) + | TyKind::Never + | TyKind::Foreign(..) => V::Result::output(), + } + } +} + +impl<'db> TypeFoldable> for Ty<'db> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + folder.try_fold_ty(self) + } + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_ty(self) + } +} + +impl<'db> TypeSuperFoldable> for Ty<'db> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let kind = match self.kind() { + TyKind::RawPtr(ty, mutbl) => TyKind::RawPtr(ty.try_fold_with(folder)?, mutbl), + TyKind::Array(typ, sz) => { + TyKind::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?) + } + TyKind::Slice(typ) => TyKind::Slice(typ.try_fold_with(folder)?), + TyKind::Adt(tid, args) => TyKind::Adt(tid, args.try_fold_with(folder)?), + TyKind::Dynamic(trait_ty, region, representation) => TyKind::Dynamic( + trait_ty.try_fold_with(folder)?, + region.try_fold_with(folder)?, + representation, + ), + TyKind::Tuple(ts) => TyKind::Tuple(ts.try_fold_with(folder)?), + TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.try_fold_with(folder)?), + TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.try_fold_with(folder)?, hdr), + TyKind::UnsafeBinder(f) => TyKind::UnsafeBinder(f.try_fold_with(folder)?), + TyKind::Ref(r, ty, mutbl) => { + TyKind::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl) + } + TyKind::Coroutine(did, args) => TyKind::Coroutine(did, args.try_fold_with(folder)?), + TyKind::CoroutineWitness(did, args) => { + TyKind::CoroutineWitness(did, args.try_fold_with(folder)?) + } + TyKind::Closure(did, args) => TyKind::Closure(did, args.try_fold_with(folder)?), + TyKind::CoroutineClosure(did, args) => { + TyKind::CoroutineClosure(did, args.try_fold_with(folder)?) + } + TyKind::Alias(kind, data) => TyKind::Alias(kind, data.try_fold_with(folder)?), + TyKind::Pat(ty, pat) => { + TyKind::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?) + } + + TyKind::Bool + | TyKind::Char + | TyKind::Str + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Error(_) + | TyKind::Infer(_) + | TyKind::Param(..) + | TyKind::Bound(..) + | TyKind::Placeholder(..) + | TyKind::Never + | TyKind::Foreign(..) => return Ok(self), + }; + + Ok(if self.kind() == kind { self } else { Ty::new(folder.cx(), kind) }) + } + fn super_fold_with>>( + self, + folder: &mut F, + ) -> Self { + let kind = match self.kind() { + TyKind::RawPtr(ty, mutbl) => TyKind::RawPtr(ty.fold_with(folder), mutbl), + TyKind::Array(typ, sz) => TyKind::Array(typ.fold_with(folder), sz.fold_with(folder)), + TyKind::Slice(typ) => TyKind::Slice(typ.fold_with(folder)), + TyKind::Adt(tid, args) => TyKind::Adt(tid, args.fold_with(folder)), + TyKind::Dynamic(trait_ty, region, representation) => TyKind::Dynamic( + trait_ty.fold_with(folder), + region.fold_with(folder), + representation, + ), + TyKind::Tuple(ts) => TyKind::Tuple(ts.fold_with(folder)), + TyKind::FnDef(def_id, args) => TyKind::FnDef(def_id, args.fold_with(folder)), + TyKind::FnPtr(sig_tys, hdr) => TyKind::FnPtr(sig_tys.fold_with(folder), hdr), + TyKind::UnsafeBinder(f) => TyKind::UnsafeBinder(f.fold_with(folder)), + TyKind::Ref(r, ty, mutbl) => { + TyKind::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl) + } + TyKind::Coroutine(did, args) => TyKind::Coroutine(did, args.fold_with(folder)), + TyKind::CoroutineWitness(did, args) => { + TyKind::CoroutineWitness(did, args.fold_with(folder)) + } + TyKind::Closure(did, args) => TyKind::Closure(did, args.fold_with(folder)), + TyKind::CoroutineClosure(did, args) => { + TyKind::CoroutineClosure(did, args.fold_with(folder)) + } + TyKind::Alias(kind, data) => TyKind::Alias(kind, data.fold_with(folder)), + TyKind::Pat(ty, pat) => TyKind::Pat(ty.fold_with(folder), pat.fold_with(folder)), + + TyKind::Bool + | TyKind::Char + | TyKind::Str + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Error(_) + | TyKind::Infer(_) + | TyKind::Param(..) + | TyKind::Bound(..) + | TyKind::Placeholder(..) + | TyKind::Never + | TyKind::Foreign(..) => return self, + }; + + if self.kind() == kind { self } else { Ty::new(folder.cx(), kind) } + } +} + +impl<'db> Relate> for Ty<'db> { + fn relate>>( + relation: &mut R, + a: Self, + b: Self, + ) -> rustc_type_ir::relate::RelateResult, Self> { + relation.tys(a, b) + } +} + +impl<'db> Flags for Ty<'db> { + fn flags(&self) -> rustc_type_ir::TypeFlags { + self.inner().flags + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.inner().outer_exclusive_binder + } +} + +impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { + fn new_unit(interner: DbInterner<'db>) -> Self { + Ty::new(interner, TyKind::Tuple(Default::default())) + } + + fn new_bool(interner: DbInterner<'db>) -> Self { + Ty::new(interner, TyKind::Bool) + } + + fn new_u8(interner: DbInterner<'db>) -> Self { + Ty::new(interner, TyKind::Uint(rustc_type_ir::UintTy::U8)) + } + + fn new_usize(interner: DbInterner<'db>) -> Self { + Ty::new(interner, TyKind::Uint(rustc_type_ir::UintTy::Usize)) + } + + fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferTy) -> Self { + Ty::new(interner, TyKind::Infer(var)) + } + + fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::TyVid) -> Self { + Ty::new(interner, TyKind::Infer(rustc_type_ir::InferTy::TyVar(var))) + } + + fn new_param(interner: DbInterner<'db>, param: ParamTy) -> Self { + Ty::new(interner, TyKind::Param(param)) + } + + fn new_placeholder(interner: DbInterner<'db>, param: PlaceholderTy) -> Self { + Ty::new(interner, TyKind::Placeholder(param)) + } + + fn new_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: BoundTy, + ) -> Self { + Ty::new(interner, TyKind::Bound(debruijn, var)) + } + + fn new_anon_bound( + interner: DbInterner<'db>, + debruijn: rustc_type_ir::DebruijnIndex, + var: BoundVar, + ) -> Self { + Ty::new(interner, TyKind::Bound(debruijn, BoundTy { var, kind: BoundTyKind::Anon })) + } + + fn new_alias( + interner: DbInterner<'db>, + kind: rustc_type_ir::AliasTyKind, + alias_ty: rustc_type_ir::AliasTy>, + ) -> Self { + Ty::new(interner, TyKind::Alias(kind, alias_ty)) + } + + fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self { + Ty::new(interner, TyKind::Error(guar)) + } + + fn new_adt( + interner: DbInterner<'db>, + adt_def: as rustc_type_ir::Interner>::AdtDef, + args: GenericArgs<'db>, + ) -> Self { + Ty::new(interner, TyKind::Adt(adt_def, args)) + } + + fn new_foreign( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + ) -> Self { + Ty::new(interner, TyKind::Foreign(def_id)) + } + + fn new_dynamic( + interner: DbInterner<'db>, + preds: as rustc_type_ir::Interner>::BoundExistentialPredicates, + region: as rustc_type_ir::Interner>::Region, + kind: rustc_type_ir::DynKind, + ) -> Self { + Ty::new(interner, TyKind::Dynamic(preds, region, kind)) + } + + fn new_coroutine( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + Ty::new(interner, TyKind::Coroutine(def_id, args)) + } + + fn new_coroutine_closure( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + Ty::new(interner, TyKind::CoroutineClosure(def_id, args)) + } + + fn new_closure( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + Ty::new(interner, TyKind::Closure(def_id, args)) + } + + fn new_coroutine_witness( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) + } + + fn new_ptr(interner: DbInterner<'db>, ty: Self, mutbl: rustc_ast_ir::Mutability) -> Self { + Ty::new(interner, TyKind::RawPtr(ty, mutbl)) + } + + fn new_ref( + interner: DbInterner<'db>, + region: as rustc_type_ir::Interner>::Region, + ty: Self, + mutbl: rustc_ast_ir::Mutability, + ) -> Self { + Ty::new(interner, TyKind::Ref(region, ty, mutbl)) + } + + fn new_array_with_const_len( + interner: DbInterner<'db>, + ty: Self, + len: as rustc_type_ir::Interner>::Const, + ) -> Self { + Ty::new(interner, TyKind::Array(ty, len)) + } + + fn new_slice(interner: DbInterner<'db>, ty: Self) -> Self { + Ty::new(interner, TyKind::Slice(ty)) + } + + fn new_tup( + interner: DbInterner<'db>, + tys: &[ as rustc_type_ir::Interner>::Ty], + ) -> Self { + Ty::new(interner, TyKind::Tuple(Tys::new_from_iter(interner, tys.iter().cloned()))) + } + + fn new_tup_from_iter(interner: DbInterner<'db>, iter: It) -> T::Output + where + It: Iterator, + T: rustc_type_ir::CollectAndApply, + { + T::collect_and_apply(iter, |ts| Ty::new_tup(interner, ts)) + } + + fn new_fn_def( + interner: DbInterner<'db>, + def_id: as rustc_type_ir::Interner>::DefId, + args: as rustc_type_ir::Interner>::GenericArgs, + ) -> Self { + Ty::new(interner, TyKind::FnDef(def_id, args)) + } + + fn new_fn_ptr( + interner: DbInterner<'db>, + sig: rustc_type_ir::Binder, rustc_type_ir::FnSig>>, + ) -> Self { + let (sig_tys, header) = sig.split(); + Ty::new(interner, TyKind::FnPtr(sig_tys, header)) + } + + fn new_pat( + interner: DbInterner<'db>, + ty: Self, + pat: as rustc_type_ir::Interner>::Pat, + ) -> Self { + Ty::new(interner, TyKind::Pat(ty, pat)) + } + + fn tuple_fields(self) -> as rustc_type_ir::Interner>::Tys { + match self.kind() { + TyKind::Tuple(args) => args, + _ => panic!("tuple_fields called on non-tuple: {self:?}"), + } + } + + fn to_opt_closure_kind(self) -> Option { + match self.kind() { + TyKind::Int(int_ty) => match int_ty { + IntTy::I8 => Some(ClosureKind::Fn), + IntTy::I16 => Some(ClosureKind::FnMut), + IntTy::I32 => Some(ClosureKind::FnOnce), + _ => unreachable!("cannot convert type `{:?}` to a closure kind", self), + }, + + // "Bound" types appear in canonical queries when the + // closure type is not yet known, and `Placeholder` and `Param` + // may be encountered in generic `AsyncFnKindHelper` goals. + TyKind::Bound(..) | TyKind::Placeholder(_) | TyKind::Param(_) | TyKind::Infer(_) => { + None + } + + TyKind::Error(_) => Some(ClosureKind::Fn), + + _ => unreachable!("cannot convert type `{:?}` to a closure kind", self), + } + } + + fn from_closure_kind(interner: DbInterner<'db>, kind: rustc_type_ir::ClosureKind) -> Self { + match kind { + ClosureKind::Fn => Ty::new(interner, TyKind::Int(IntTy::I8)), + ClosureKind::FnMut => Ty::new(interner, TyKind::Int(IntTy::I16)), + ClosureKind::FnOnce => Ty::new(interner, TyKind::Int(IntTy::I32)), + } + } + + fn from_coroutine_closure_kind( + interner: DbInterner<'db>, + kind: rustc_type_ir::ClosureKind, + ) -> Self { + match kind { + ClosureKind::Fn | ClosureKind::FnMut => Ty::new(interner, TyKind::Int(IntTy::I16)), + ClosureKind::FnOnce => Ty::new(interner, TyKind::Int(IntTy::I32)), + } + } + + fn discriminant_ty( + self, + interner: DbInterner<'db>, + ) -> as rustc_type_ir::Interner>::Ty { + match self.kind() { + TyKind::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(interner), + TyKind::Coroutine(_, args) => args.as_coroutine().discr_ty(interner), + + TyKind::Param(_) | TyKind::Alias(..) | TyKind::Infer(InferTy::TyVar(_)) => { + /* + let assoc_items = tcx.associated_item_def_ids( + tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + ); + TyKind::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) + */ + unimplemented!() + } + + TyKind::Pat(ty, _) => ty.discriminant_ty(interner), + + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Adt(..) + | TyKind::Foreign(_) + | TyKind::Str + | TyKind::Array(..) + | TyKind::Slice(_) + | TyKind::RawPtr(_, _) + | TyKind::Ref(..) + | TyKind::FnDef(..) + | TyKind::FnPtr(..) + | TyKind::Dynamic(..) + | TyKind::Closure(..) + | TyKind::CoroutineClosure(..) + | TyKind::CoroutineWitness(..) + | TyKind::Never + | TyKind::Tuple(_) + | TyKind::Error(_) + | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => { + Ty::new(interner, TyKind::Uint(UintTy::U8)) + } + + TyKind::Bound(..) + | TyKind::Placeholder(_) + | TyKind::Infer( + InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_), + ) => { + panic!( + "`dself.iter().map(|v| v.try_fold_with(folder)).collect::>()?iscriminant_ty` applied to unexpected type: {self:?}" + ) + } + TyKind::UnsafeBinder(..) => unimplemented!(), + } + } + + fn new_unsafe_binder( + interner: DbInterner<'db>, + ty: rustc_type_ir::Binder< + DbInterner<'db>, + as rustc_type_ir::Interner>::Ty, + >, + ) -> Self { + Ty::new(interner, TyKind::UnsafeBinder(ty.into())) + } + + fn has_unsafe_fields(self) -> bool { + false + } +} + +interned_vec_db!(Tys, Ty); + +impl<'db> rustc_type_ir::inherent::Tys> for Tys<'db> { + fn inputs(self) -> as rustc_type_ir::Interner>::FnInputTys { + Tys::new_from_iter( + DbInterner::conjure(), + self.as_slice().split_last().unwrap().1.iter().cloned(), + ) + } + + fn output(self) -> as rustc_type_ir::Interner>::Ty { + *self.as_slice().split_last().unwrap().0 + } +} + +pub type PlaceholderTy = Placeholder; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct ParamTy { + pub index: u32, +} + +impl ParamTy { + pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> { + Ty::new_param(interner, self.index, sym::MISSING_NAME.clone()) + } +} + +impl std::fmt::Debug for ParamTy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#{}", self.index) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct BoundTy { + pub var: BoundVar, + pub kind: BoundTyKind, +} + +impl std::fmt::Debug for BoundTy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + BoundTyKind::Anon => write!(f, "{:?}", self.var), + BoundTyKind::Param(def_id) => write!(f, "{def_id:?}"), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum BoundTyKind { + Anon, + Param(SolverDefId), +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct ErrorGuaranteed; + +impl<'db> TypeVisitable> for ErrorGuaranteed { + fn visit_with>>( + &self, + visitor: &mut V, + ) -> V::Result { + visitor.visit_error(*self) + } +} + +impl<'db> TypeFoldable> for ErrorGuaranteed { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + Ok(self) + } + fn fold_with>>(self, folder: &mut F) -> Self { + self + } +} + +impl ParamLike for ParamTy { + fn index(self) -> u32 { + self.index + } +} + +impl<'db> BoundVarLike> for BoundTy { + fn var(self) -> BoundVar { + self.var + } + + fn assert_eq(self, var: BoundVarKind) { + assert_eq!(self.kind, var.expect_ty()) + } +} + +impl<'db> PlaceholderLike> for PlaceholderTy { + type Bound = BoundTy; + + fn universe(self) -> rustc_type_ir::UniverseIndex { + self.universe + } + + fn var(self) -> BoundVar { + self.bound.var + } + + fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self { + Placeholder { universe: ui, bound: self.bound } + } + + fn new(ui: rustc_type_ir::UniverseIndex, bound: BoundTy) -> Self { + Placeholder { universe: ui, bound } + } + + fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self { + Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs new file mode 100644 index 0000000000000..cedc203f7f5aa --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -0,0 +1,1064 @@ +//! Various utilities for the next-trait-solver. + +use std::iter; +use std::ops::{self, ControlFlow}; + +use base_db::Crate; +use hir_def::lang_item::LangItem; +use hir_def::{BlockId, HasModule, ItemContainerId, Lookup}; +use intern::sym; +use la_arena::Idx; +use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions}; +use rustc_type_ir::data_structures::IndexMap; +use rustc_type_ir::inherent::{ + AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike, + Ty as _, +}; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::SizedTraitKind; +use rustc_type_ir::{ + BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity, + TypeFlags, TypeVisitable, TypeVisitableExt, +}; +use rustc_type_ir::{ + ConstKind, CoroutineArgs, FloatTy, IntTy, RegionKind, TypeFolder, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitor, UintTy, UniverseIndex, inherent::IntoKind, +}; +use rustc_type_ir::{InferCtxtLike, TypeFoldable}; + +use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext}; +use crate::next_solver::infer::InferCtxt; +use crate::next_solver::{ + CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion, + TypingMode, +}; +use crate::{ + db::HirDatabase, + from_foreign_def_id, + method_resolution::{TraitImpls, TyFingerprint}, +}; + +use super::fold::{BoundVarReplacer, FnMutDelegate}; +use super::generics::generics; +use super::{ + AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds, + CanonicalVars, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArg, + GenericArgs, Predicate, PredicateKind, ProjectionPredicate, Region, SolverContext, SolverDefId, + Term, TraitPredicate, TraitRef, Ty, TyKind, +}; + +#[derive(Clone, Debug)] +pub struct Discr<'db> { + /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). + pub val: u128, + pub ty: Ty<'db>, +} + +impl<'db> Discr<'db> { + /// Adds `1` to the value and wraps around if the maximum for the type is reached. + pub fn wrap_incr(self, interner: DbInterner<'db>) -> Self { + self.checked_add(interner, 1).0 + } + pub fn checked_add(self, interner: DbInterner<'db>, n: u128) -> (Self, bool) { + let (size, signed) = self.ty.int_size_and_signed(interner); + let (val, oflo) = if signed { + let min = size.signed_int_min(); + let max = size.signed_int_max(); + let val = size.sign_extend(self.val); + assert!(n < (i128::MAX as u128)); + let n = n as i128; + let oflo = val > max - n; + let val = if oflo { min + (n - (max - val) - 1) } else { val + n }; + // zero the upper bits + let val = val as u128; + let val = size.truncate(val); + (val, oflo) + } else { + let max = size.unsigned_int_max(); + let val = self.val; + let oflo = val > max - n; + let val = if oflo { n - (max - val) - 1 } else { val + n }; + (val, oflo) + }; + (Self { val, ty: self.ty }, oflo) + } +} + +pub trait IntegerTypeExt { + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>; + fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db>; + fn disr_incr<'db>( + &self, + interner: DbInterner<'db>, + val: Option>, + ) -> Option>; +} + +impl IntegerTypeExt for IntegerType { + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> { + match self { + IntegerType::Pointer(true) => Ty::new(interner, TyKind::Int(IntTy::Isize)), + IntegerType::Pointer(false) => Ty::new(interner, TyKind::Uint(UintTy::Usize)), + IntegerType::Fixed(i, s) => i.to_ty(interner, *s), + } + } + + fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db> { + Discr { val: 0, ty: self.to_ty(interner) } + } + + fn disr_incr<'db>( + &self, + interner: DbInterner<'db>, + val: Option>, + ) -> Option> { + if let Some(val) = val { + assert_eq!(self.to_ty(interner), val.ty); + let (new, oflo) = val.checked_add(interner, 1); + if oflo { None } else { Some(new) } + } else { + Some(self.initial_discriminant(interner)) + } + } +} + +pub trait IntegerExt { + fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db>; + fn from_int_ty(cx: &C, ity: IntTy) -> Integer; + fn from_uint_ty(cx: &C, ity: UintTy) -> Integer; + fn repr_discr<'db>( + interner: DbInterner<'db>, + ty: Ty<'db>, + repr: &ReprOptions, + min: i128, + max: i128, + ) -> (Integer, bool); +} + +impl IntegerExt for Integer { + #[inline] + fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db> { + use Integer::*; + match (*self, signed) { + (I8, false) => Ty::new(interner, TyKind::Uint(UintTy::U8)), + (I16, false) => Ty::new(interner, TyKind::Uint(UintTy::U16)), + (I32, false) => Ty::new(interner, TyKind::Uint(UintTy::U32)), + (I64, false) => Ty::new(interner, TyKind::Uint(UintTy::U64)), + (I128, false) => Ty::new(interner, TyKind::Uint(UintTy::U128)), + (I8, true) => Ty::new(interner, TyKind::Int(IntTy::I8)), + (I16, true) => Ty::new(interner, TyKind::Int(IntTy::I16)), + (I32, true) => Ty::new(interner, TyKind::Int(IntTy::I32)), + (I64, true) => Ty::new(interner, TyKind::Int(IntTy::I64)), + (I128, true) => Ty::new(interner, TyKind::Int(IntTy::I128)), + } + } + + fn from_int_ty(cx: &C, ity: IntTy) -> Integer { + use Integer::*; + match ity { + IntTy::I8 => I8, + IntTy::I16 => I16, + IntTy::I32 => I32, + IntTy::I64 => I64, + IntTy::I128 => I128, + IntTy::Isize => cx.data_layout().ptr_sized_integer(), + } + } + fn from_uint_ty(cx: &C, ity: UintTy) -> Integer { + use Integer::*; + match ity { + UintTy::U8 => I8, + UintTy::U16 => I16, + UintTy::U32 => I32, + UintTy::U64 => I64, + UintTy::U128 => I128, + UintTy::Usize => cx.data_layout().ptr_sized_integer(), + } + } + + /// Finds the appropriate Integer type and signedness for the given + /// signed discriminant range and `#[repr]` attribute. + /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but + /// that shouldn't affect anything, other than maybe debuginfo. + fn repr_discr<'db>( + interner: DbInterner<'db>, + ty: Ty<'db>, + repr: &ReprOptions, + min: i128, + max: i128, + ) -> (Integer, bool) { + // Theoretically, negative values could be larger in unsigned representation + // than the unsigned representation of the signed minimum. However, if there + // are any negative values, the only valid unsigned representation is u128 + // which can fit all i128 values, so the result remains unaffected. + let unsigned_fit = Integer::fit_unsigned(std::cmp::max(min as u128, max as u128)); + let signed_fit = std::cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); + + if let Some(ity) = repr.int { + let discr = Integer::from_attr(&interner, ity); + let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; + if discr < fit { + panic!( + "Integer::repr_discr: `#[repr]` hint too small for \ + discriminant range of enum `{ty:?}`" + ) + } + return (discr, ity.is_signed()); + } + + let at_least = if repr.c() { + // This is usually I32, however it can be different on some platforms, + // notably hexagon and arm-none/thumb-none + interner.data_layout().c_enum_min_size + } else { + // repr(Rust) enums try to be as small as possible + Integer::I8 + }; + + // If there are no negative values, we can use the unsigned fit. + if min >= 0 { + (std::cmp::max(unsigned_fit, at_least), false) + } else { + (std::cmp::max(signed_fit, at_least), true) + } + } +} + +pub trait FloatExt { + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>; + fn from_float_ty(fty: FloatTy) -> Self; +} + +impl FloatExt for Float { + #[inline] + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> { + use Float::*; + match *self { + F16 => Ty::new(interner, TyKind::Float(FloatTy::F16)), + F32 => Ty::new(interner, TyKind::Float(FloatTy::F32)), + F64 => Ty::new(interner, TyKind::Float(FloatTy::F64)), + F128 => Ty::new(interner, TyKind::Float(FloatTy::F128)), + } + } + + fn from_float_ty(fty: FloatTy) -> Self { + use Float::*; + match fty { + FloatTy::F16 => F16, + FloatTy::F32 => F32, + FloatTy::F64 => F64, + FloatTy::F128 => F128, + } + } +} + +pub trait PrimitiveExt { + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>; + fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>; +} + +impl PrimitiveExt for Primitive { + #[inline] + fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> { + match *self { + Primitive::Int(i, signed) => i.to_ty(interner, signed), + Primitive::Float(f) => f.to_ty(interner), + Primitive::Pointer(_) => Ty::new( + interner, + TyKind::RawPtr( + Ty::new(interner, TyKind::Tuple(Default::default())), + rustc_ast_ir::Mutability::Mut, + ), + ), + } + } + + /// Return an *integer* type matching this primitive. + /// Useful in particular when dealing with enum discriminants. + #[inline] + fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> { + match *self { + Primitive::Int(i, signed) => i.to_ty(interner, signed), + Primitive::Pointer(_) => { + let signed = false; + interner.data_layout().ptr_sized_integer().to_ty(interner, signed) + } + Primitive::Float(_) => panic!("floats do not have an int type"), + } + } +} + +impl<'db> HasDataLayout for DbInterner<'db> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { + unimplemented!() + } +} + +pub trait CoroutineArgsExt<'db> { + fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db>; +} + +impl<'db> CoroutineArgsExt<'db> for CoroutineArgs> { + /// The type of the state discriminant used in the coroutine type. + #[inline] + fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db> { + Ty::new(interner, TyKind::Uint(UintTy::U32)) + } +} + +/// Finds the max universe present +pub struct MaxUniverse { + max_universe: UniverseIndex, +} + +impl Default for MaxUniverse { + fn default() -> Self { + Self::new() + } +} + +impl MaxUniverse { + pub fn new() -> Self { + MaxUniverse { max_universe: UniverseIndex::ROOT } + } + + pub fn max_universe(self) -> UniverseIndex { + self.max_universe + } +} + +impl<'db> TypeVisitor> for MaxUniverse { + type Result = (); + + fn visit_ty(&mut self, t: Ty<'db>) { + if let TyKind::Placeholder(placeholder) = t.kind() { + self.max_universe = UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: Const<'db>) { + if let ConstKind::Placeholder(placeholder) = c.kind() { + self.max_universe = UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: Region<'db>) { + if let RegionKind::RePlaceholder(placeholder) = r.kind() { + self.max_universe = UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + } +} + +pub struct BottomUpFolder<'db, F, G, H> +where + F: FnMut(Ty<'db>) -> Ty<'db>, + G: FnMut(Region<'db>) -> Region<'db>, + H: FnMut(Const<'db>) -> Const<'db>, +{ + pub interner: DbInterner<'db>, + pub ty_op: F, + pub lt_op: G, + pub ct_op: H, +} + +impl<'db, F, G, H> TypeFolder> for BottomUpFolder<'db, F, G, H> +where + F: FnMut(Ty<'db>) -> Ty<'db>, + G: FnMut(Region<'db>) -> Region<'db>, + H: FnMut(Const<'db>) -> Const<'db>, +{ + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + let t = ty.super_fold_with(self); + (self.ty_op)(t) + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + // This one is a little different, because `super_fold_with` is not + // implemented on non-recursive `Region`. + (self.lt_op)(r) + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + let ct = ct.super_fold_with(self); + (self.ct_op)(ct) + } +} + +pub(crate) fn for_trait_impls( + db: &dyn HirDatabase, + krate: Crate, + block: Option, + trait_id: hir_def::TraitId, + self_ty_fp: Option, + mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>, +) -> ControlFlow<()> { + // Note: Since we're using `impls_for_trait` and `impl_provided_for`, + // only impls where the trait can be resolved should ever reach Chalk. + // `impl_datum` relies on that and will panic if the trait can't be resolved. + let in_deps = db.trait_impls_in_deps(krate); + let in_self = db.trait_impls_in_crate(krate); + let trait_module = trait_id.module(db); + let type_module = match self_ty_fp { + Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(db)), + Some(TyFingerprint::ForeignType(type_id)) => Some(from_foreign_def_id(type_id).module(db)), + Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(db)), + _ => None, + }; + + let mut def_blocks = + [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]; + + let block_impls = iter::successors(block, |&block_id| { + cov_mark::hit!(block_local_impls); + block_id.loc(db).module.containing_block() + }) + .inspect(|&block_id| { + // make sure we don't search the same block twice + def_blocks.iter_mut().for_each(|block| { + if *block == Some(block_id) { + *block = None; + } + }); + }) + .filter_map(|block_id| db.trait_impls_in_block(block_id)); + f(&in_self)?; + for it in in_deps.iter().map(ops::Deref::deref) { + f(it)?; + } + for it in block_impls { + f(&it)?; + } + for it in def_blocks.into_iter().flatten().filter_map(|it| db.trait_impls_in_block(it)) { + f(&it)?; + } + ControlFlow::Continue(()) +} + +// FIXME(next-trait-solver): uplift +pub fn sizedness_constraint_for_ty<'db>( + interner: DbInterner<'db>, + sizedness: SizedTraitKind, + ty: Ty<'db>, +) -> Option> { + use rustc_type_ir::TyKind::*; + + match ty.kind() { + // these are always sized + Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) + | FnPtr(..) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) + | CoroutineWitness(..) | Never => None, + + // these are never sized + Str | Slice(..) | Dynamic(_, _, rustc_type_ir::DynKind::Dyn) => match sizedness { + // Never `Sized` + SizedTraitKind::Sized => Some(ty), + // Always `MetaSized` + SizedTraitKind::MetaSized => None, + }, + + // Maybe `Sized` or `MetaSized` + Param(..) | Alias(..) | Error(_) => Some(ty), + + // We cannot instantiate the binder, so just return the *original* type back, + // but only if the inner type has a sized constraint. Thus we skip the binder, + // but don't actually use the result from `sized_constraint_for_ty`. + UnsafeBinder(inner_ty) => { + sizedness_constraint_for_ty(interner, sizedness, inner_ty.skip_binder()).map(|_| ty) + } + + // Never `MetaSized` or `Sized` + Foreign(..) => Some(ty), + + // Recursive cases + Pat(ty, _) => sizedness_constraint_for_ty(interner, sizedness, ty), + + Tuple(tys) => tys + .into_iter() + .last() + .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)), + + Adt(adt, args) => { + let tail_ty = + EarlyBinder::bind(adt.all_field_tys(interner).skip_binder().into_iter().last()?) + .instantiate(interner, args); + sizedness_constraint_for_ty(interner, sizedness, tail_ty) + } + + Placeholder(..) | Bound(..) | Infer(..) => { + panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty") + } + } +} + +pub fn apply_args_to_binder<'db, T: TypeFoldable>>( + b: Binder<'db, T>, + args: GenericArgs<'db>, + interner: DbInterner<'db>, +) -> T { + let types = &mut |ty: BoundTy| args.as_slice()[ty.var.index()].expect_ty(); + let regions = &mut |region: BoundRegion| args.as_slice()[region.var.index()].expect_region(); + let consts = &mut |const_: BoundVar| args.as_slice()[const_.index()].expect_const(); + let mut instantiate = BoundVarReplacer::new(interner, FnMutDelegate { types, regions, consts }); + b.skip_binder().fold_with(&mut instantiate) +} + +pub(crate) fn mini_canonicalize<'db, T: TypeFoldable>>( + mut context: SolverContext<'db>, + val: T, +) -> Canonical, T> { + let mut canon = MiniCanonicalizer { + context: &mut context, + db: DebruijnIndex::ZERO, + vars: IndexMap::default(), + }; + let canon_val = val.fold_with(&mut canon); + let vars = canon.vars; + Canonical { + value: canon_val, + max_universe: UniverseIndex::from_u32(1), + variables: CanonicalVars::new_from_iter( + context.cx(), + vars.iter().map(|(k, v)| match (*k).kind() { + GenericArgKind::Type(ty) => match ty.kind() { + TyKind::Int(..) | TyKind::Uint(..) => { + rustc_type_ir::CanonicalVarKind::Ty(rustc_type_ir::CanonicalTyVarKind::Int) + } + TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Ty( + rustc_type_ir::CanonicalTyVarKind::Float, + ), + _ => rustc_type_ir::CanonicalVarKind::Ty( + rustc_type_ir::CanonicalTyVarKind::General(UniverseIndex::ZERO), + ), + }, + GenericArgKind::Lifetime(_) => { + rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO) + } + GenericArgKind::Const(_) => { + rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ZERO) + } + }), + ), + } +} + +struct MiniCanonicalizer<'a, 'db> { + context: &'a mut SolverContext<'db>, + db: DebruijnIndex, + vars: IndexMap, usize>, +} + +impl<'db> TypeFolder> for MiniCanonicalizer<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.context.cx() + } + + fn fold_binder>>( + &mut self, + t: rustc_type_ir::Binder, T>, + ) -> rustc_type_ir::Binder, T> { + self.db.shift_in(1); + let res = t.map_bound(|t| t.fold_with(self)); + self.db.shift_out(1); + res + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + match t.kind() { + rustc_type_ir::TyKind::Bound(db, _) => { + if db >= self.db { + panic!("Unexpected bound var"); + } + t + } + rustc_type_ir::TyKind::Infer(infer) => { + let t = match infer { + rustc_type_ir::InferTy::TyVar(vid) => { + self.context.opportunistic_resolve_ty_var(vid) + } + rustc_type_ir::InferTy::IntVar(vid) => { + self.context.opportunistic_resolve_int_var(vid) + } + rustc_type_ir::InferTy::FloatVar(vid) => { + self.context.opportunistic_resolve_float_var(vid) + } + _ => t, + }; + let len = self.vars.len(); + let var = *self.vars.entry(t.into()).or_insert(len); + Ty::new( + self.cx(), + TyKind::Bound( + self.db, + BoundTy { kind: super::BoundTyKind::Anon, var: BoundVar::from_usize(var) }, + ), + ) + } + _ => t.super_fold_with(self), + } + } + + fn fold_region( + &mut self, + r: as rustc_type_ir::Interner>::Region, + ) -> as rustc_type_ir::Interner>::Region { + match r.kind() { + RegionKind::ReBound(db, _) => { + if db >= self.db { + panic!("Unexpected bound var"); + } + r + } + RegionKind::ReVar(vid) => { + let len = self.vars.len(); + let var = *self.vars.entry(r.into()).or_insert(len); + Region::new( + self.cx(), + RegionKind::ReBound( + self.db, + BoundRegion { + kind: super::BoundRegionKind::Anon, + var: BoundVar::from_usize(var), + }, + ), + ) + } + _ => r, + } + } + + fn fold_const( + &mut self, + c: as rustc_type_ir::Interner>::Const, + ) -> as rustc_type_ir::Interner>::Const { + match c.kind() { + ConstKind::Bound(db, _) => { + if db >= self.db { + panic!("Unexpected bound var"); + } + c + } + ConstKind::Infer(infer) => { + let len = self.vars.len(); + let var = *self.vars.entry(c.into()).or_insert(len); + Const::new(self.cx(), ConstKind::Bound(self.db, BoundVar::from_usize(var))) + } + _ => c.super_fold_with(self), + } + } +} + +pub fn explicit_item_bounds<'db>( + interner: DbInterner<'db>, + def_id: SolverDefId, +) -> EarlyBinder<'db, Clauses<'db>> { + let db = interner.db(); + match def_id { + SolverDefId::TypeAliasId(type_alias) => { + let trait_ = match type_alias.lookup(db).container { + ItemContainerId::TraitId(t) => t, + _ => panic!("associated type not in trait"), + }; + + // Lower bounds -- we could/should maybe move this to a separate query in `lower` + let type_alias_data = db.type_alias_signature(type_alias); + let generic_params = generics(db, type_alias.into()); + let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + type_alias.into(), + LifetimeElisionKind::AnonymousReportError, + ); + + let trait_args = GenericArgs::identity_for_item(interner, trait_.into()); + let item_args = GenericArgs::identity_for_item(interner, def_id); + let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args); + + let mut bounds = Vec::new(); + for bound in &type_alias_data.bounds { + ctx.lower_type_bound(bound, interner_ty, false).for_each(|pred| { + bounds.push(pred); + }); + } + + if !ctx.unsized_types.contains(&interner_ty) { + let sized_trait = LangItem::Sized + .resolve_trait(ctx.db, interner.krate.expect("Must have interner.krate")); + let sized_bound = sized_trait.map(|trait_id| { + let trait_ref = TraitRef::new_from_args( + interner, + trait_id.into(), + GenericArgs::new_from_iter(interner, [interner_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) + }); + bounds.extend(sized_bound); + bounds.shrink_to_fit(); + } + + rustc_type_ir::EarlyBinder::bind(Clauses::new_from_iter(interner, bounds)) + } + SolverDefId::InternedOpaqueTyId(id) => { + let full_id = db.lookup_intern_impl_trait_id(id); + match full_id { + crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { + let datas = db + .return_type_impl_traits_ns(func) + .expect("impl trait id without impl traits"); + let datas = (*datas).as_ref().skip_binder(); + let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())]; + EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone())) + } + crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => { + let datas = db + .type_alias_impl_traits_ns(alias) + .expect("impl trait id without impl traits"); + let datas = (*datas).as_ref().skip_binder(); + let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())]; + EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone())) + } + crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { + if let Some((future_trait, future_output)) = LangItem::Future + .resolve_trait(db, interner.krate.expect("Must have interner.krate")) + .and_then(|trait_| { + let alias = trait_.trait_items(db).associated_type_by_name( + &hir_expand::name::Name::new_symbol_root(sym::Output.clone()), + )?; + Some((trait_, alias)) + }) + { + let args = GenericArgs::identity_for_item(interner, def_id); + let out = args.as_slice()[0]; + let mut predicates = vec![]; + + let item_ty = Ty::new_alias( + interner, + rustc_type_ir::AliasTyKind::Opaque, + AliasTy::new_from_args(interner, def_id, args), + ); + + let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + polarity: rustc_type_ir::PredicatePolarity::Positive, + trait_ref: TraitRef::new_from_args( + interner, + future_trait.into(), + GenericArgs::new_from_iter(interner, [item_ty.into()]), + ), + })); + predicates.push(Clause(Predicate::new( + interner, + Binder::bind_with_vars( + kind, + BoundVarKinds::new_from_iter( + interner, + [BoundVarKind::Ty(BoundTyKind::Anon)], + ), + ), + ))); + let sized_trait = LangItem::Sized + .resolve_trait(db, interner.krate.expect("Must have interner.krate")); + if let Some(sized_trait_) = sized_trait { + let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { + polarity: rustc_type_ir::PredicatePolarity::Positive, + trait_ref: TraitRef::new_from_args( + interner, + sized_trait_.into(), + GenericArgs::new_from_iter(interner, [item_ty.into()]), + ), + })); + predicates.push(Clause(Predicate::new( + interner, + Binder::bind_with_vars( + kind, + BoundVarKinds::new_from_iter( + interner, + [BoundVarKind::Ty(BoundTyKind::Anon)], + ), + ), + ))); + } + let kind = + PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate { + projection_term: AliasTerm::new_from_args( + interner, + future_output.into(), + GenericArgs::new_from_iter(interner, [item_ty.into()]), + ), + term: match out.kind() { + GenericArgKind::Lifetime(lt) => panic!(), + GenericArgKind::Type(ty) => Term::Ty(ty), + GenericArgKind::Const(const_) => Term::Const(const_), + }, + })); + predicates.push(Clause(Predicate::new( + interner, + Binder::bind_with_vars( + kind, + BoundVarKinds::new_from_iter( + interner, + [BoundVarKind::Ty(BoundTyKind::Anon)], + ), + ), + ))); + EarlyBinder::bind(Clauses::new_from_iter(interner, predicates)) + } else { + // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. + EarlyBinder::bind(Clauses::new_from_iter(interner, [])) + } + } + } + } + _ => panic!("Unexpected GeneridDefId"), + } +} + +pub struct ContainsTypeErrors; + +impl<'db> TypeVisitor> for ContainsTypeErrors { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result { + match t.kind() { + rustc_type_ir::TyKind::Error(_) => ControlFlow::Break(()), + _ => t.super_visit_with(self), + } + } +} + +/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. +pub struct PlaceholderReplacer<'a, 'db> { + infcx: &'a InferCtxt<'db>, + mapped_regions: FxIndexMap, + mapped_types: FxIndexMap, BoundTy>, + mapped_consts: FxIndexMap, + universe_indices: &'a [Option], + current_index: DebruijnIndex, +} + +impl<'a, 'db> PlaceholderReplacer<'a, 'db> { + pub fn replace_placeholders>>( + infcx: &'a InferCtxt<'db>, + mapped_regions: FxIndexMap, + mapped_types: FxIndexMap, BoundTy>, + mapped_consts: FxIndexMap, + universe_indices: &'a [Option], + value: T, + ) -> T { + let mut replacer = PlaceholderReplacer { + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + current_index: INNERMOST, + }; + value.fold_with(&mut replacer) + } +} + +impl<'db> TypeFolder> for PlaceholderReplacer<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn fold_binder>>( + &mut self, + t: Binder<'db, T>, + ) -> Binder<'db, T> { + if !t.has_placeholders() && !t.has_infer() { + return t; + } + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r0: Region<'db>) -> Region<'db> { + let r1 = match r0.kind() { + RegionKind::ReVar(vid) => self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.infcx.interner, vid), + _ => r0, + }; + + let r2 = match r1.kind() { + RegionKind::RePlaceholder(p) => { + let replace_var = self.mapped_regions.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| panic!("Unexpected placeholder universe.")); + let db = DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + Region::new_bound(self.cx(), db, *replace_var) + } + None => r1, + } + } + _ => r1, + }; + + tracing::debug!(?r0, ?r1, ?r2, "fold_region"); + + r2 + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + let ty = self.infcx.shallow_resolve(ty); + match ty.kind() { + TyKind::Placeholder(p) => { + let replace_var = self.mapped_types.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| panic!("Unexpected placeholder universe.")); + let db = DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + Ty::new_bound(self.infcx.interner, db, *replace_var) + } + None => { + if ty.has_infer() { + ty.super_fold_with(self) + } else { + ty + } + } + } + } + + _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self), + _ => ty, + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + let ct = self.infcx.shallow_resolve_const(ct); + if let ConstKind::Placeholder(p) = ct.kind() { + let replace_var = self.mapped_consts.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| panic!("Unexpected placeholder universe.")); + let db = DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + Const::new_bound(self.infcx.interner, db, *replace_var) + } + None => { + if ct.has_infer() { + ct.super_fold_with(self) + } else { + ct + } + } + } + } else { + ct.super_fold_with(self) + } + } +} + +pub(crate) fn needs_normalization<'db, T: TypeVisitable>>( + infcx: &InferCtxt<'db>, + value: &T, +) -> bool { + let mut flags = TypeFlags::HAS_ALIAS; + + // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`, + // so we can ignore those. + match infcx.typing_mode() { + // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis + TypingMode::Coherence + | TypingMode::Analysis { .. } + | TypingMode::Borrowck { .. } + | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(TypeFlags::HAS_TY_OPAQUE), + TypingMode::PostAnalysis => {} + } + + value.has_type_flags(flags) +} + +pub fn sizedness_fast_path<'db>( + tcx: DbInterner<'db>, + predicate: Predicate<'db>, + param_env: ParamEnv<'db>, +) -> bool { + // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like + // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to + // canonicalize and all that for such cases. + if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder() + && trait_pred.polarity == PredicatePolarity::Positive + { + let sizedness = match tcx.as_lang_item(trait_pred.def_id()) { + Some(TraitSolverLangItem::Sized) => SizedTraitKind::Sized, + Some(TraitSolverLangItem::MetaSized) => SizedTraitKind::MetaSized, + _ => return false, + }; + + // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature + // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` + // is pending a proper fix + if matches!(sizedness, SizedTraitKind::MetaSized) { + return true; + } + + if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) { + tracing::debug!("fast path -- trivial sizedness"); + return true; + } + + if matches!(trait_pred.self_ty().kind(), TyKind::Param(_) | TyKind::Placeholder(_)) { + for clause in param_env.caller_bounds().iter() { + if let ClauseKind::Trait(clause_pred) = clause.kind().skip_binder() + && clause_pred.polarity == PredicatePolarity::Positive + && clause_pred.self_ty() == trait_pred.self_ty() + && (clause_pred.def_id() == trait_pred.def_id() + || (sizedness == SizedTraitKind::MetaSized + && tcx.is_lang_item(clause_pred.def_id(), TraitSolverLangItem::Sized))) + { + return true; + } + } + } + } + + false +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 9605a0b4124d8..fc31973022bdd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -12,9 +12,6 @@ mod simple; mod traits; mod type_alias_impl_traits; -use std::env; -use std::sync::LazyLock; - use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ @@ -35,8 +32,6 @@ use syntax::{ ast::{self, AstNode, HasName}, }; use test_fixture::WithFixture; -use tracing_subscriber::{Registry, layer::SubscriberExt}; -use tracing_tree::HierarchicalLayer; use triomphe::Arc; use crate::{ @@ -44,6 +39,7 @@ use crate::{ db::HirDatabase, display::{DisplayTarget, HirDisplay}, infer::{Adjustment, TypeMismatch}, + setup_tracing, test_db::TestDB, }; @@ -51,23 +47,6 @@ use crate::{ // against snapshots of the expected results using expect. Use // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. -fn setup_tracing() -> Option { - static ENABLE: LazyLock = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok()); - if !*ENABLE { - return None; - } - - let filter: tracing_subscriber::filter::Targets = - env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); - let layer = HierarchicalLayer::default() - .with_indent_lines(true) - .with_ansi(false) - .with_indent_amount(2) - .with_writer(std::io::stderr); - let subscriber = Registry::default().with(filter).with(layer); - Some(tracing::subscriber::set_default(subscriber)) -} - #[track_caller] fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_impl(ra_fixture, false, true, false) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index dbc68eeba1e64..5893894c33ab7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -12,9 +12,10 @@ use crate::display::{DisplayTarget, HirDisplay}; use crate::mir::MirSpan; use crate::test_db::TestDB; -use super::visit_module; +use super::{setup_tracing, visit_module}; fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + let _tracing = setup_tracing(); let (db, file_id) = TestDB::with_single_file(ra_fixture); let module = db.module_for_file(file_id.file_id(&db)); let def_map = module.def_map(&db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 3894b4b6f7bad..3b7d4d2184a59 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -96,7 +96,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { foo(&[1]) - // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?11, Not)), Pointer(Unsize) } else { &[1] }; @@ -148,7 +148,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?11, Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; @@ -484,6 +484,8 @@ fn test() { ); } +// FIXME(next-solver): We could learn more from the `&S` -> `&dyn Foo` coercion if we followed the rustc model +// where unsized is successful if all unsizing trait goals are certain (and non-unsizing goals are delayed). #[test] fn coerce_unsize_trait_object_simple() { check_types( @@ -503,8 +505,8 @@ fn test() { //^ S let obj: &dyn Bar<_, i8, i16> = &S; //^ S - let obj: &dyn Foo = &S; - //^ S + //let obj: &dyn Foo = &S; + // S<{unknown}, {unknown}> }"#, ); } @@ -543,9 +545,9 @@ struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; - //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]> + //^^^^^^^^^^^^^^^^^^^^^ type: &'? Foo<[usize; 3]> let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); - //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]> + //^^^^^^^^^^^^^^^^^^^^^^^^^^ type: &'? Bar<[usize; 3]> } "#, ); @@ -899,7 +901,7 @@ impl core::ops::Index for StructMut { fn index(&self, index: usize) -> &Self::Output { &() } } -impl core::ops::IndexMut for StructMut { +impl core::ops::IndexMut for StructMut { fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () } } fn test() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 3159499e86707..df9061d23bf5d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -519,6 +519,7 @@ impl SomeStruct { ); } +// FIXME(next-solver): does this test make sense with fast path? #[test] fn add_struct_invalidates_trait_solve() { let (mut db, file_id) = TestDB::with_single_file( @@ -559,7 +560,7 @@ fn main() { let _inference_result = db.infer(def); } }, - &[("trait_solve_shim", 2)], + &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ "source_root_crates_shim", @@ -606,21 +607,17 @@ fn main() { "callable_item_signature_shim", "adt_variance_shim", "variances_of_shim", - "trait_solve_shim", - "trait_datum_shim", - "generic_predicates_shim", - "adt_datum_shim", "trait_impls_in_deps_shim", "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", "type_for_adt_tracked", - "impl_datum_shim", - "generic_predicates_shim", - "program_clauses_for_chalk_env_shim", + "impl_trait_with_diagnostics_ns_shim", + "impl_self_ty_with_diagnostics_ns_shim", + "generic_predicates_ns_shim", + "generic_predicates_ns_shim", "value_ty_shim", "generic_predicates_shim", - "trait_solve_shim", "lang_item", ] "#]], @@ -703,10 +700,13 @@ fn main() { "impl_signature_with_source_map_shim", "impl_signature_shim", "callable_item_signature_shim", - "generic_predicates_shim", "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", + "impl_trait_with_diagnostics_ns_shim", + "impl_self_ty_with_diagnostics_ns_shim", + "generic_predicates_ns_shim", + "generic_predicates_ns_shim", "generic_predicates_shim", ] "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index ea7a113cae3f6..5d088e40cdeda 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -197,17 +197,17 @@ fn expr_macro_def_expanded_in_various_places() { 39..442 '{ ...!(); }': () 73..94 'spam!(...am!())': {unknown} 100..119 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter - 100..119 'for _ ...!() {}': IntoIterator::IntoIter + 100..119 'for _ ...!() {}': {unknown} 100..119 'for _ ...!() {}': ! - 100..119 'for _ ...!() {}': IntoIterator::IntoIter - 100..119 'for _ ...!() {}': &'? mut IntoIterator::IntoIter - 100..119 'for _ ...!() {}': fn next>(&'? mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> - 100..119 'for _ ...!() {}': Option> + 100..119 'for _ ...!() {}': {unknown} + 100..119 'for _ ...!() {}': &'? mut {unknown} + 100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 100..119 'for _ ...!() {}': Option<{unknown}> 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () - 104..105 '_': IntoIterator::Item + 104..105 '_': {unknown} 117..119 '{}': () 124..134 '|| spam!()': impl Fn() -> isize 140..156 'while ...!() {}': ! @@ -291,17 +291,17 @@ fn expr_macro_rules_expanded_in_various_places() { 53..456 '{ ...!(); }': () 87..108 'spam!(...am!())': {unknown} 114..133 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter - 114..133 'for _ ...!() {}': IntoIterator::IntoIter + 114..133 'for _ ...!() {}': {unknown} 114..133 'for _ ...!() {}': ! - 114..133 'for _ ...!() {}': IntoIterator::IntoIter - 114..133 'for _ ...!() {}': &'? mut IntoIterator::IntoIter - 114..133 'for _ ...!() {}': fn next>(&'? mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> - 114..133 'for _ ...!() {}': Option> + 114..133 'for _ ...!() {}': {unknown} + 114..133 'for _ ...!() {}': &'? mut {unknown} + 114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 114..133 'for _ ...!() {}': Option<{unknown}> 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () - 118..119 '_': IntoIterator::Item + 118..119 '_': {unknown} 131..133 '{}': () 138..148 '|| spam!()': impl Fn() -> isize 154..170 'while ...!() {}': ! diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index c58ca6c67a8de..f09b3ef6bfd0f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1134,6 +1134,7 @@ fn test() { (S {}).method(); } fn dyn_trait_super_trait_not_in_scope() { check_infer( r#" + //- minicore: dispatch_from_dyn mod m { pub trait SuperTrait { fn foo(&self) -> u32 { 0 } @@ -1309,7 +1310,7 @@ fn main() { fn dyn_trait_method_priority() { check_types( r#" -//- minicore: from +//- minicore: from, dispatch_from_dyn trait Trait { fn into(&self) -> usize { 0 } } @@ -1823,6 +1824,33 @@ fn test() { ); } +#[test] +fn deref_fun_3() { + check_types( + r#" +//- minicore: receiver + +struct A(T, U); +struct B(T); +struct C(T); + +impl core::ops::Deref for A, u32> { + type Target = B; + fn deref(&self) -> &B { &self.0 } +} + +fn make() -> T { loop {} } + +fn test() { + let a1 = A(make(), make()); + let _: usize = (*a1).0; + a1; + //^^ A, u32> +} +"#, + ); +} + #[test] fn deref_into_inference_var() { check_types( @@ -2077,7 +2105,7 @@ impl Foo { } fn test() { Box::new(Foo).foo(); - //^^^^^^^^^^^^^ adjustments: Deref(None), Borrow(Ref('?3, Not)) + //^^^^^^^^^^^^^ adjustments: Deref(None), Borrow(Ref('?5, Not)) } "#, ); @@ -2095,7 +2123,7 @@ impl Foo { use core::mem::ManuallyDrop; fn test() { ManuallyDrop::new(Foo).foo(); - //^^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('?4, Not)) + //^^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('?6, Not)) } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index c4c17a93c9cd6..25061e1dbdb9d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -773,7 +773,7 @@ fn issue_4800() { "#, expect![[r#" 379..383 'self': &'? mut PeerSet - 401..424 '{ ... }': dyn Future + '? + 401..424 '{ ... }': dyn Future + 'static 411..418 'loop {}': ! 416..418 '{}': () 575..579 'self': &'? mut Self @@ -781,6 +781,9 @@ fn issue_4800() { ); } +// FIXME(next-solver): Though `Repeat: IntoIterator` does not hold here, we +// should be able to do better at given type hints (with Chalk, we did `IntoIterator::Item>`) +// From what I can tell, the point of this test is to not panic though. #[test] fn issue_4966() { check_infer( @@ -824,11 +827,11 @@ fn issue_4966() { 311..317 'repeat': Repeat f64>> 320..345 'Repeat...nner }': Repeat f64>> 338..343 'inner': Map f64> - 356..359 'vec': Vec f64>>>> - 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> - 362..379 'from_i...epeat)': Vec f64>>>> + 356..359 'vec': Vec<{unknown}> + 362..371 'from_iter': fn from_iter<{unknown}, Repeat f64>>>(Repeat f64>>) -> Vec<{unknown}> + 362..379 'from_i...epeat)': Vec<{unknown}> 372..378 'repeat': Repeat f64>> - 386..389 'vec': Vec f64>>>> + 386..389 'vec': Vec<{unknown}> 386..399 'vec.foo_bar()': {unknown} "#]], ); @@ -1224,6 +1227,8 @@ fn mamba(a: U32!(), p: u32) -> u32 { #[test] fn for_loop_block_expr_iterable() { + // FIXME(next-solver): it would be nice to be able to hint `IntoIterator::IntoIter<()>` instead of just `{unknown}` + // (even though `(): IntoIterator` does not hold) check_infer( r#" //- minicore: iterator @@ -1236,17 +1241,17 @@ fn test() { expect![[r#" 10..68 '{ ... } }': () 16..66 'for _ ... }': fn into_iter<()>(()) -> <() as IntoIterator>::IntoIter - 16..66 'for _ ... }': IntoIterator::IntoIter<()> + 16..66 'for _ ... }': {unknown} 16..66 'for _ ... }': ! - 16..66 'for _ ... }': IntoIterator::IntoIter<()> - 16..66 'for _ ... }': &'? mut IntoIterator::IntoIter<()> - 16..66 'for _ ... }': fn next>(&'? mut IntoIterator::IntoIter<()>) -> Option< as Iterator>::Item> - 16..66 'for _ ... }': Option> + 16..66 'for _ ... }': {unknown} + 16..66 'for _ ... }': &'? mut {unknown} + 16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 16..66 'for _ ... }': Option<{unknown}> 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () 16..66 'for _ ... }': () - 20..21 '_': IntoIterator::Item<()> + 20..21 '_': {unknown} 25..39 '{ let x = 0; }': () 31..32 'x': i32 35..36 '0': i32 @@ -1283,7 +1288,6 @@ fn test() { #[test] fn bug_11242() { - // FIXME: wrong, should be u32 check_types( r#" fn foo() @@ -1292,7 +1296,7 @@ where B: IntoIterator, { let _x: ::Item; - // ^^ {unknown} + // ^^ u32 } pub trait Iterator { @@ -1495,7 +1499,7 @@ fn regression_11688_2() { fn regression_11688_3() { check_types( r#" - //- minicore: iterator + //- minicore: iterator, dispatch_from_dyn struct Ar(T); fn f( num_zeros: usize, @@ -1514,6 +1518,7 @@ fn regression_11688_3() { fn regression_11688_4() { check_types( r#" + //- minicore: dispatch_from_dyn trait Bar { fn baz(&self) -> [i32; C]; } @@ -2035,11 +2040,11 @@ fn issue_17734() { r#" fn test() { let x = S::foo::<'static, &()>(&S); - // ^ Wrap<'?, ()> + // ^ Wrap<'static, ()> let x = S::foo::<&()>(&S); // ^ Wrap<'?, ()> let x = S.foo::<'static, &()>(); - // ^ Wrap<'?, ()> + // ^ Wrap<'static, ()> let x = S.foo::<&()>(); // ^ Wrap<'?, ()> } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index b154e59878571..a995a45f6e752 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2923,7 +2923,7 @@ fn test { // ^^ impl Fn() let c4 = f1(); - // ^^ impl FnOnce() + ?Sized + // ^^ impl FnOnce() f2(|| { 0 }); // ^^^^^^^^ impl FnOnce() -> i32 @@ -3922,7 +3922,7 @@ fn foo() { expect![[r#" 110..127 '{ ...z(); }': () 116..122 'T::baz': fn baz() -> <{unknown} as Foo>::Gat<'?> - 116..124 'T::baz()': Foo::Gat<'?, {unknown}> + 116..124 'T::baz()': {unknown} "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 56e31a1af1b9c..2e4346a86973b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1691,7 +1691,7 @@ fn test>(x: T, y: impl Trait) { get2(y); get(set(S)); get2(set(S)); - get2(S::); + get2(S::); }"#, expect![[r#" 49..50 't': T @@ -1703,7 +1703,7 @@ fn test>(x: T, y: impl Trait) { 166..167 't': T 256..257 'x': T 262..263 'y': impl Trait - 289..397 '{ ...r>); }': () + 289..399 '{ ...e>); }': () 295..298 'get': fn get(T) -> ::Type 295..301 'get(x)': u32 299..300 'x': T @@ -1726,9 +1726,9 @@ fn test>(x: T, y: impl Trait) { 367..370 'set': fn set>(S) -> S 367..373 'set(S)': S 371..372 'S': S - 380..384 'get2': fn get2>(S) -> str - 380..394 'get2(S::)': str - 385..393 'S::': S + 380..384 'get2': fn get2>(S) -> usize + 380..396 'get2(S...size>)': usize + 385..395 'S::': S "#]], ); } @@ -2740,7 +2740,7 @@ impl> Foo { fn dyn_trait_through_chalk() { check_types( r#" -//- minicore: deref +//- minicore: deref, unsize, dispatch_from_dyn struct Box {} impl core::ops::Deref for Box { type Target = T; @@ -3228,7 +3228,7 @@ fn foo() { fn infer_dyn_fn_output() { check_types( r#" -//- minicore: fn +//- minicore: fn, dispatch_from_dyn fn foo() { let f: &dyn Fn() -> i32; f(); @@ -4255,8 +4255,8 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { 127..128 'v': &'? (dyn Trait = &'a i32> + '?) 164..195 '{ ...f(); }': () 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': &'? i32 - 170..192 'v.get:...eref()': &'? i32 + 170..184 'v.get::()': {unknown} + 170..192 'v.get:...eref()': &'? {unknown} "#]], ); } @@ -4785,30 +4785,30 @@ fn allowed2<'a>(baz: impl Baz) {} fn allowed3(baz: impl Baz>) {} "#, expect![[r#" - 139..140 'f': impl Fn({unknown}) + ?Sized + 139..140 'f': impl Fn({unknown}) 161..193 '{ ...oo); }': () 171..174 'foo': S 177..178 'S': S - 184..185 'f': impl Fn({unknown}) + ?Sized + 184..185 'f': impl Fn({unknown}) 184..190 'f(foo)': () 186..189 'foo': S - 251..252 'f': impl Fn(&'? {unknown}) + ?Sized + 251..252 'f': impl Fn(&'? {unknown}) 274..307 '{ ...oo); }': () 284..287 'foo': S 290..291 'S': S - 297..298 'f': impl Fn(&'? {unknown}) + ?Sized + 297..298 'f': impl Fn(&'? {unknown}) 297..304 'f(&foo)': () 299..303 '&foo': &'? S 300..303 'foo': S - 325..328 'bar': impl Bar<{unknown}> + ?Sized + 325..328 'bar': impl Bar<{unknown}> 350..352 '{}': () - 405..408 'bar': impl Bar<&'? {unknown}> + ?Sized + 405..408 'bar': impl Bar<&'? {unknown}> 431..433 '{}': () - 447..450 'baz': impl Baz + ?Sized + 447..450 'baz': impl Baz 480..482 '{}': () - 500..503 'baz': impl Baz + ?Sized + 500..503 'baz': impl Baz 544..546 '{}': () - 560..563 'baz': impl Baz> + ?Sized + 560..563 'baz': impl Baz> 598..600 '{}': () "#]], ) @@ -4930,3 +4930,67 @@ fn main() { "#]], ); } + +#[test] +fn new_solver_crash_1() { + check_infer( + r#" +pub trait Deserializer<'de> { + type Error; +} + +fn deserialize_abs_pathbuf<'de, D>(de: D) -> D::Error +where + D: Deserializer<'de>, +{ +} +"#, + expect![[r#" + 84..86 'de': D + 135..138 '{ }': Deserializer::Error<'de, D> + "#]], + ); +} + +#[test] +fn new_solver_crash_2() { + check_infer( + r#" +//- minicore: deref, send, sync +use core::ops::Deref; + +trait Error {} + +struct AnyhowError; + +impl Deref for AnyhowError { + type Target = dyn Error + Send + Sync; + + fn deref(&self) -> &Self::Target { loop {} } +} + +impl AnyhowError { + fn downcast(self) {} +} + + +fn main() { + let e = AnyhowError; + e.downcast::<()>(); +} +"#, + expect![[r#" + 147..151 'self': &'? AnyhowError + 170..181 '{ loop {} }': &'? (dyn Error + Send + Sync + 'static) + 172..179 'loop {}': ! + 177..179 '{}': () + 223..227 'self': AnyhowError + 229..231 '{}': () + 246..298 '{ ...>(); }': () + 256..257 'e': AnyhowError + 260..271 'AnyhowError': AnyhowError + 277..278 'e': AnyhowError + 277..295 'e.down...<()>()': () + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs index f53409af2b30c..fe4cf7a3da527 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs @@ -10,6 +10,7 @@ use crate::{ }; use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId}; +#[allow(unused)] pub(crate) use unsafe_tls::{set_current_program, with_current_program}; pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase); @@ -136,6 +137,7 @@ mod unsafe_tls { if PROGRAM.is_set() { PROGRAM.with(|prog| op(Some(prog))) } else { op(None) } } + #[allow(dead_code)] pub(crate) fn set_current_program(p: &dyn HirDatabase, op: OP) -> R where OP: FnOnce() -> R, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 08b9d242e71d2..51cf5be1372ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -1,43 +1,38 @@ //! Trait solving using Chalk. use core::fmt; -use std::env::var; use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable}; -use chalk_recursive::Cache; -use chalk_solve::{Solver, logging_db::LoggingRustIrDatabase, rust_ir}; +use chalk_solve::rust_ir; use base_db::Crate; use hir_def::{BlockId, TraitId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; +use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt}; +use rustc_type_ir::{ + InferCtxtLike, TypingMode, + inherent::{SliceLike, Span as _}, + solve::Certainty, +}; use span::Edition; -use stdx::{never, panic_context}; +use stdx::never; use triomphe::Arc; use crate::{ - AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, ProjectionTy, - ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase, - infer::unify::InferenceTable, utils::UnevaluatedConstEvaluatorFolder, + AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, + ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, + db::HirDatabase, + infer::unify::InferenceTable, + next_solver::{ + DbInterner, GenericArg, SolverContext, Span, + infer::{DbInternerInferExt, InferCtxt}, + mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, + util::mini_canonicalize, + }, + utils::UnevaluatedConstEvaluatorFolder, }; -/// This controls how much 'time' we give the Chalk solver before giving up. -const CHALK_SOLVER_FUEL: i32 = 1000; - -#[derive(Debug, Copy, Clone)] -pub(crate) struct ChalkContext<'a> { - pub(crate) db: &'a dyn HirDatabase, - pub(crate) krate: Crate, - pub(crate) block: Option, -} - -fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { - let overflow_depth = - var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500); - let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150); - chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new())) -} - /// A set of clauses that we assume to be true. E.g. if we are inside this function: /// ```rust /// fn foo(t: T) {} @@ -103,13 +98,43 @@ pub(crate) fn normalize_projection_query( table.resolve_completely(ty) } +fn identity_subst( + binders: chalk_ir::CanonicalVarKinds, +) -> chalk_ir::Canonical> { + let identity_subst = chalk_ir::Substitution::from_iter( + Interner, + binders.iter(Interner).enumerate().map(|(index, c)| { + let index_db = chalk_ir::BoundVar::new(DebruijnIndex::INNERMOST, index); + match &c.kind { + chalk_ir::VariableKind::Ty(_) => { + chalk_ir::GenericArgData::Ty(TyKind::BoundVar(index_db).intern(Interner)) + .intern(Interner) + } + chalk_ir::VariableKind::Lifetime => chalk_ir::GenericArgData::Lifetime( + chalk_ir::LifetimeData::BoundVar(index_db).intern(Interner), + ) + .intern(Interner), + chalk_ir::VariableKind::Const(ty) => chalk_ir::GenericArgData::Const( + chalk_ir::ConstData { + ty: ty.clone(), + value: chalk_ir::ConstValue::BoundVar(index_db), + } + .intern(Interner), + ) + .intern(Interner), + } + }), + ); + chalk_ir::Canonical { binders, value: identity_subst } +} + /// Solve a trait goal using Chalk. pub(crate) fn trait_solve_query( db: &dyn HirDatabase, krate: Crate, block: Option, goal: Canonical>, -) -> Option { +) -> NextTraitSolveResult { let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db .trait_signature(it.hir_trait_id()) @@ -128,7 +153,7 @@ pub(crate) fn trait_solve_query( && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) { // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible - return Some(Solution::Ambig(Guidance::Unknown)); + return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone())); } // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So @@ -139,71 +164,148 @@ pub(crate) fn trait_solve_query( // We currently don't deal with universes (I think / hope they're not yet // relevant for our use cases?) - let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; - solve(db, krate, block, &u_canonical) + next_trait_solve(db, krate, block, goal) } -fn solve( - db: &dyn HirDatabase, +fn solve_nextsolver<'db>( + db: &'db dyn HirDatabase, krate: Crate, block: Option, goal: &chalk_ir::UCanonical>>, -) -> Option> { - let _p = tracing::info_span!("solve", ?krate, ?block).entered(); - let context = ChalkContext { db, krate, block }; - tracing::debug!("solve goal: {:?}", goal); - let mut solver = create_chalk_solver(); - - let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); - - let should_continue = || { - db.unwind_if_revision_cancelled(); - let remaining = fuel.get(); - fuel.set(remaining - 1); - if remaining == 0 { - tracing::debug!("fuel exhausted"); +) -> Result< + (HasChanged, Certainty, rustc_type_ir::Canonical, Vec>>), + rustc_type_ir::solve::NoSolution, +> { + // FIXME: should use analysis_in_body, but that needs GenericDefId::Block + let context = SolverContext( + DbInterner::new_with(db, Some(krate), block) + .infer_ctxt() + .build(TypingMode::non_body_analysis()), + ); + + match goal.canonical.value.goal.data(Interner) { + // FIXME: args here should be...what? not empty + GoalData::All(goals) if goals.is_empty(Interner) => { + return Ok((HasChanged::No, Certainty::Yes, mini_canonicalize(context, vec![]))); } - remaining > 0 - }; + _ => {} + } - let mut solve = || { - let _ctx = if is_chalk_debug() || is_chalk_print() { - Some(panic_context::enter(format!("solving {goal:?}"))) - } else { - None - }; - let solution = if is_chalk_print() { - let logging_db = - LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context)); - solver.solve_limited(&logging_db.0, goal, &should_continue) - } else { - solver.solve_limited(&context, goal, &should_continue) - }; - - tracing::debug!("solve({:?}) => {:?}", goal, solution); - - solution - }; + let goal = goal.canonical.to_nextsolver(context.cx()); + tracing::info!(?goal); + + let (goal, var_values) = context.instantiate_canonical(&goal); + tracing::info!(?var_values); + + let res = context.evaluate_root_goal(goal, Span::dummy(), None); - // don't set the TLS for Chalk unless Chalk debugging is active, to make - // extra sure we only use it for debugging - if is_chalk_debug() { crate::tls::set_current_program(db, solve) } else { solve() } + let vars = + var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect(); + let canonical_var_values = mini_canonicalize(context, vars); + + let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values)); + + tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); + + res +} + +#[derive(Clone, Debug, PartialEq)] +pub enum NextTraitSolveResult { + Certain(chalk_ir::Canonical>), + Uncertain(chalk_ir::Canonical>), + NoSolution, } -struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase>); +impl NextTraitSolveResult { + pub fn no_solution(&self) -> bool { + matches!(self, NextTraitSolveResult::NoSolution) + } + + pub fn certain(&self) -> bool { + matches!(self, NextTraitSolveResult::Certain(..)) + } -impl Drop for LoggingRustIrDatabaseLoggingOnDrop<'_> { - fn drop(&mut self) { - tracing::info!("chalk program:\n{}", self.0); + pub fn uncertain(&self) -> bool { + matches!(self, NextTraitSolveResult::Uncertain(..)) } } -fn is_chalk_debug() -> bool { - std::env::var("CHALK_DEBUG").is_ok() +/// Solve a trait goal using Chalk. +pub fn next_trait_solve( + db: &dyn HirDatabase, + krate: Crate, + block: Option, + goal: Canonical>, +) -> NextTraitSolveResult { + let detail = match &goal.value.goal.data(Interner) { + GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { + db.trait_signature(it.hir_trait_id()).name.display(db, Edition::LATEST).to_string() + } + GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), + _ => "??".to_owned(), + }; + let _p = tracing::info_span!("next_trait_solve", ?detail).entered(); + tracing::info!("next_trait_solve({:?})", goal.value.goal); + + if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { + alias: AliasTy::Projection(projection_ty), + .. + }))) = &goal.value.goal.data(Interner) + && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) + { + // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible + // FIXME + return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone())); + } + + // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So + // we should get rid of it when talking to chalk. + let goal = goal + .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST) + .unwrap(); + + // We currently don't deal with universes (I think / hope they're not yet + // relevant for our use cases?) + let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; + tracing::info!(?u_canonical); + + let next_solver_res = solve_nextsolver(db, krate, block, &u_canonical); + + match next_solver_res { + Err(_) => NextTraitSolveResult::NoSolution, + Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( + convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args), + ), + Ok((_, Certainty::Maybe(_), args)) => { + let subst = convert_canonical_args_for_result( + DbInterner::new_with(db, Some(krate), block), + args, + ); + NextTraitSolveResult::Uncertain(chalk_ir::Canonical { + binders: subst.binders, + value: subst.value.subst, + }) + } + } } -fn is_chalk_print() -> bool { - std::env::var("CHALK_PRINT").is_ok() +/// Solve a trait goal using Chalk. +pub fn next_trait_solve_in_ctxt<'db, 'a>( + infer_ctxt: &'a InferCtxt<'db>, + goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>, +) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> { + tracing::info!(?goal); + + let context = <&SolverContext<'db>>::from(infer_ctxt); + + let res = context.evaluate_root_goal(goal, Span::dummy(), None); + + let res = res.map(|r| (r.has_changed, r.certainty)); + + tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); + + res } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index c68ff706e4814..dfa39384320de 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -22,6 +22,8 @@ tracing.workspace = true triomphe.workspace = true indexmap.workspace = true +ra-ap-rustc_type_ir.workspace = true + # local deps base-db.workspace = true cfg.workspace = true @@ -36,6 +38,9 @@ span.workspace = true [dev-dependencies] expect-test.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +tracing-tree.workspace = true # local deps test-utils.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index a323f97997c68..475906ae51a11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -20,6 +20,12 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] +#[cfg(feature = "in-rust-tree")] +extern crate rustc_type_ir; + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_type_ir as rustc_type_ir; + mod attrs; mod from_id; mod has_source; @@ -54,7 +60,10 @@ use hir_def::{ }, item_tree::ImportAlias, layout::{self, ReprOptions, TargetDataLayout}, - nameres::{self, assoc::TraitItems, diagnostics::DefDiagnostic}, + nameres::{ + assoc::TraitItems, + diagnostics::{DefDiagnostic, DefDiagnosticKind}, + }, per_ns::PerNs, resolver::{HasResolver, Resolver}, signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, @@ -76,11 +85,11 @@ use hir_ty::{ layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution, mir::{MutBorrowKind, interpret_mir}, + next_solver::{DbInterner, GenericArgs, SolverDefId, infer::InferCtxt}, primitive::UintTy, traits::FnTrait, }; use itertools::Itertools; -use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; @@ -187,6 +196,10 @@ pub struct CrateDependency { } impl Crate { + pub fn base(self) -> base_db::Crate { + self.id + } + pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin { self.id.data(db).origin.clone() } @@ -1247,6 +1260,25 @@ pub struct Field { pub(crate) id: LocalFieldId, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InstantiatedField<'db> { + pub(crate) inner: Field, + pub(crate) args: GenericArgs<'db>, +} + +impl<'db> InstantiatedField<'db> { + /// Returns the type as in the signature of the struct. + pub fn ty(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { + let krate = self.inner.krate(db); + let interner = DbInterner::new_with(db, Some(krate.base()), None); + + let var_id = self.inner.parent.into(); + let field = db.field_types_ns(var_id)[self.inner.id]; + let ty = field.instantiate(interner, self.args); + TypeNs::new(db, var_id, ty) + } +} + #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct TupleField { pub owner: DefWithBodyId, @@ -1444,6 +1476,11 @@ impl Struct { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { db.attrs(self.id.into()).is_unstable() } + + pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> { + let args = infer_ctxt.fresh_args_for_item(self.id.into()); + InstantiatedStruct { inner: self, args } + } } impl HasVisibility for Struct { @@ -1454,6 +1491,35 @@ impl HasVisibility for Struct { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InstantiatedStruct<'db> { + pub(crate) inner: Struct, + pub(crate) args: GenericArgs<'db>, +} + +impl<'db> InstantiatedStruct<'db> { + pub fn fields(self, db: &dyn HirDatabase) -> Vec> { + self.inner + .id + .fields(db) + .fields() + .iter() + .map(|(id, _)| InstantiatedField { + inner: Field { parent: self.inner.into(), id }, + args: self.args, + }) + .collect() + } + + pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { + let krate = self.inner.krate(db); + let interner = DbInterner::new_with(db, Some(krate.base()), None); + + let ty = db.ty_ns(self.inner.id.into()); + TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Union { pub(crate) id: UnionId, @@ -1598,6 +1664,22 @@ impl HasVisibility for Enum { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InstantiatedEnum<'db> { + pub(crate) inner: Enum, + pub(crate) args: GenericArgs<'db>, +} + +impl<'db> InstantiatedEnum<'db> { + pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { + let krate = self.inner.krate(db); + let interner = DbInterner::new_with(db, Some(krate.base()), None); + + let ty = db.ty_ns(self.inner.id.into()); + TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) + } +} + impl From<&Variant> for DefWithBodyId { fn from(&v: &Variant) -> Self { DefWithBodyId::VariantId(v.into()) @@ -1673,6 +1755,38 @@ impl Variant { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { db.attrs(self.id.into()).is_unstable() } + + pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> { + let args = + infer_ctxt.fresh_args_for_item(self.parent_enum(infer_ctxt.interner.db()).id.into()); + InstantiatedVariant { inner: self, args } + } +} + +// FIXME: Rename to `EnumVariant` +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InstantiatedVariant<'db> { + pub(crate) inner: Variant, + pub(crate) args: GenericArgs<'db>, +} + +impl<'db> InstantiatedVariant<'db> { + pub fn parent_enum(self, db: &dyn HirDatabase) -> InstantiatedEnum<'db> { + InstantiatedEnum { inner: self.inner.id.lookup(db).parent.into(), args: self.args } + } + + pub fn fields(self, db: &dyn HirDatabase) -> Vec> { + self.inner + .id + .fields(db) + .fields() + .iter() + .map(|(id, _)| InstantiatedField { + inner: Field { parent: self.inner.into(), id }, + args: self.args, + }) + .collect() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -5072,7 +5186,7 @@ impl<'db> Type<'db> { binders: CanonicalVarKinds::empty(Interner), }; - db.trait_solve(self.env.krate, self.env.block, goal).is_some() + !db.trait_solve(self.env.krate, self.env.block, goal).no_solution() } pub fn normalize_trait_assoc_type( @@ -5827,6 +5941,55 @@ impl<'db> Type<'db> { } } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct TypeNs<'db> { + env: Arc, + ty: hir_ty::next_solver::Ty<'db>, + _pd: PhantomCovariantLifetime<'db>, +} + +impl<'db> TypeNs<'db> { + fn new( + db: &'db dyn HirDatabase, + lexical_env: impl HasResolver, + ty: hir_ty::next_solver::Ty<'db>, + ) -> Self { + let resolver = lexical_env.resolver(db); + let environment = resolver + .generic_def() + .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + TypeNs { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + } + + // FIXME: Find better API that also handles const generics + pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool { + let args = GenericArgs::new_from_iter( + infcx.interner, + [self.ty].into_iter().chain(args.iter().map(|t| t.ty)).map(|t| t.into()), + ); + let trait_ref = hir_ty::next_solver::TraitRef::new( + infcx.interner, + SolverDefId::TraitId(trait_.id), + args, + ); + + let pred_kind = rustc_type_ir::Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(rustc_type_ir::TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )); + let predicate = hir_ty::next_solver::Predicate::new(infcx.interner, pred_kind); + let goal = hir_ty::next_solver::Goal::new( + infcx.interner, + hir_ty::next_solver::ParamEnv::empty(), + predicate, + ); + let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal); + res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) + } +} + #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct InlineAsmOperand { owner: DefWithBodyId, @@ -6476,3 +6639,6 @@ pub fn resolve_absolute_path<'a, I: Iterator + Clone + 'a>( fn as_name_opt(name: Option) -> Name { name.map_or_else(Name::missing, |name| name.as_name()) } + +pub use hir_ty::next_solver; +pub use hir_ty::setup_tracing; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index af949a0649899..cb83c67c99535 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,3 +1,4 @@ +use hir::next_solver::{DbInterner, TypingMode}; use ide_db::{RootDatabase, famous_defs::FamousDefs}; use syntax::ast::{self, AstNode, HasName}; @@ -80,17 +81,20 @@ fn existing_from_impl( sema: &'_ hir::Semantics<'_, RootDatabase>, variant: &ast::Variant, ) -> Option<()> { + let db = sema.db; let variant = sema.to_def(variant)?; - let enum_ = variant.parent_enum(sema.db); - let krate = enum_.module(sema.db).krate(); - + let krate = variant.module(db).krate(); let from_trait = FamousDefs(sema, krate).core_convert_From()?; + let interner = DbInterner::new_with(db, Some(krate.base()), None); + use hir::next_solver::infer::DbInternerInferExt; + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let enum_type = enum_.ty(sema.db); - - let wrapped_type = variant.fields(sema.db).first()?.ty(sema.db); - - if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) { Some(()) } else { None } + let variant = variant.instantiate_infer(&infcx); + let enum_ = variant.parent_enum(sema.db); + let field_ty = variant.fields(sema.db).first()?.ty(sema.db); + let enum_ty = enum_.ty(sema.db); + tracing::debug!(?enum_, ?field_ty, ?enum_ty); + enum_ty.impls_trait(infcx, from_trait, &[field_ty]).then_some(()) } #[cfg(test)] @@ -119,15 +123,19 @@ impl From for A { ); } + // FIXME(next-solver): it would be nice to not be *required* to resolve the + // path in order to properly generate assists #[test] fn test_generate_from_impl_for_enum_complicated_path() { check_assist( generate_from_impl_for_enum, r#" //- minicore: from +mod foo { pub mod bar { pub mod baz { pub struct Boo; } } } enum A { $0One(foo::bar::baz::Boo) } "#, r#" +mod foo { pub mod bar { pub mod baz { pub struct Boo; } } } enum A { One(foo::bar::baz::Boo) } impl From for A { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 6076d5cb5cedf..deef4a9aac6db 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -1,4 +1,5 @@ use ast::make; +use hir::next_solver::{DbInterner, TypingMode}; use hir::{HasCrate, ModuleDef, Semantics}; use ide_db::{ RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast, @@ -47,6 +48,7 @@ pub(crate) fn generate_single_field_struct_from( let strukt_name = ctx.find_node_at_offset::()?; let adt = ast::Adt::cast(strukt_name.syntax().parent()?)?; let ast::Adt::Struct(strukt) = adt else { + tracing::debug!(?adt); return None; }; @@ -57,10 +59,12 @@ pub(crate) fn generate_single_field_struct_from( let constructors = make_constructors(ctx, module, &types); if constructors.iter().filter(|expr| expr.is_none()).count() != 1 { + tracing::debug!(?constructors); return None; } let main_field_i = constructors.iter().position(Option::is_none)?; if from_impl_exists(&strukt, main_field_i, &ctx.sema).is_some() { + tracing::debug!(?strukt, ?main_field_i); return None; } @@ -200,6 +204,7 @@ fn get_fields(strukt: &ast::Struct) -> Option<(Option>, Vec, assist_label: Option<&str>, ) { + let _tracing = setup_tracing(); let (mut db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before); db.enable_proc_attr_macros(); let text_without_caret = db.file_text(file_with_caret_id.file_id(&db)).text(&db).to_string(); @@ -318,7 +319,9 @@ fn check_with_config( _ => AssistResolveStrategy::All, }; let mut acc = Assists::new(&ctx, resolve); - handler(&mut acc, &ctx); + salsa::attach(&db, || { + handler(&mut acc, &ctx); + }); let mut res = acc.finish(); let assist = match assist_label { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index f75123324f377..129964f8387a3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1384,14 +1384,15 @@ fn baz() { fn skip_iter() { check_no_kw( r#" - //- minicore: iterator + //- minicore: iterator, clone, builtin_impls fn foo() { [].$0 } "#, expect![[r#" - me clone() (as Clone) fn(&self) -> Self - me into_iter() (as IntoIterator) fn(self) -> ::IntoIter + me clone() (as Clone) fn(&self) -> Self + me fmt(…) (use core::fmt::Debug) fn(&self, &mut Formatter<'_>) -> Result<(), Error> + me into_iter() (as IntoIterator) fn(self) -> ::IntoIter "#]], ); check_no_kw( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index a70a1138d2f42..1a4c97e70b4ae 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -10,6 +10,7 @@ mod snippet; #[cfg(test)] mod tests; +use base_db::salsa; use ide_db::{ FilePosition, FxHashSet, RootDatabase, imports::insert_use::{self, ImportScope}, @@ -228,7 +229,7 @@ pub fn completions( { let acc = &mut completions; - match analysis { + salsa::attach(db, || match analysis { CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx), CompletionAnalysis::NameRef(name_ref_ctx) => { completions::complete_name_ref(acc, ctx, name_ref_ctx) @@ -256,7 +257,7 @@ pub fn completions( ); } CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (), - } + }) } Some(completions.into()) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index fdc3d9a13bc92..4b3b271ca20ef 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -26,7 +26,7 @@ mod visibility; use base_db::SourceDatabase; use expect_test::Expect; -use hir::PrefixKind; +use hir::{PrefixKind, setup_tracing}; use ide_db::{ FilePosition, RootDatabase, SnippetCap, imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -120,6 +120,8 @@ fn completion_list_with_config_raw( include_keywords: bool, trigger_character: Option, ) -> Vec { + let _tracing = setup_tracing(); + // filter out all but one built-in type completion for smaller test outputs let items = get_all_items(config, ra_fixture, trigger_character); items diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 27c91bc7c4558..bb10086a08c64 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -1,3 +1,4 @@ +use base_db::salsa; use expect_test::{Expect, expect}; use crate::{ @@ -19,25 +20,29 @@ fn check_with_config( let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); let mut acc = crate::completions::Completions::default(); - if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) = - &analysis - { - crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx); - } - if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis { - match &name_ref_ctx.kind { - NameRefKind::Path(path) => { - crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path); - } - NameRefKind::DotAccess(dot_access) => { - crate::completions::flyimport::import_on_the_fly_dot(&mut acc, &ctx, dot_access); - } - NameRefKind::Pattern(pattern) => { - crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pattern); + salsa::attach(ctx.db, || { + if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) = + &analysis + { + crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx); + } + if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis { + match &name_ref_ctx.kind { + NameRefKind::Path(path) => { + crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path); + } + NameRefKind::DotAccess(dot_access) => { + crate::completions::flyimport::import_on_the_fly_dot( + &mut acc, &ctx, dot_access, + ); + } + NameRefKind::Pattern(pattern) => { + crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pattern); + } + _ => (), } - _ => (), } - } + }); expect.assert_eq(&super::render_completion_list(Vec::from(acc))); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 148203107c4cf..84ddff8f617ac 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -677,6 +677,7 @@ fn bar() -> Bar { expect![[r#" fn foo() (as Foo) fn() -> Self ex Bar + ex Bar::foo() ex bar() "#]], ); @@ -706,6 +707,7 @@ fn bar() -> Bar { fn bar() fn() fn foo() (as Foo) fn() -> Self ex Bar + ex Bar::foo() ex bar() "#]], ); @@ -734,6 +736,7 @@ fn bar() -> Bar { expect![[r#" fn foo() (as Foo) fn() -> Self ex Bar + ex Bar::foo() ex bar() "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 1e80d02926d1b..6331090d9c90a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -157,7 +157,7 @@ fn h(x: &Y) -> Y { fn no_false_positive_dyn_fn() { check_diagnostics( r#" -//- minicore: copy, fn +//- minicore: copy, fn, dispatch_from_dyn fn f(x: &mut &mut dyn Fn()) { x(); } @@ -166,7 +166,7 @@ struct X<'a> { field: &'a mut dyn Fn(), } -fn f(x: &mut X<'_>) { +fn g(x: &mut X<'_>) { (x.field)(); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index a1db92641f5ee..a4eb3d47d708b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -92,7 +92,7 @@ use hir::{ use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode}, - base_db::{ReleaseChannel, RootQueryDb as _}, + base_db::{ReleaseChannel, RootQueryDb as _, salsa}, generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup}, imports::insert_use::InsertUseConfig, label::Label, @@ -537,10 +537,12 @@ pub fn full_diagnostics( resolve: &AssistResolveStrategy, file_id: FileId, ) -> Vec { - let mut res = syntax_diagnostics(db, config, file_id); - let sema = semantic_diagnostics(db, config, resolve, file_id); - res.extend(sema); - res + salsa::attach(db, || { + let mut res = syntax_diagnostics(db, config, file_id); + let sema = semantic_diagnostics(db, config, resolve, file_id); + res.extend(sema); + res + }) } /// Returns whether to keep this diagnostic (or remove it). diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 181993154e59f..c3cc5a08b56b5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -2,6 +2,7 @@ mod overly_long_real_world_cases; +use hir::setup_tracing; use ide_db::{ LineIndexDatabase, RootDatabase, assists::{AssistResolveStrategy, ExprFillDefaultMode}, @@ -198,6 +199,8 @@ pub(crate) fn check_diagnostics_with_config( config: DiagnosticsConfig, #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { + let _tracing = setup_tracing(); + let (db, files) = RootDatabase::with_many_files(ra_fixture); let mut annotations = files .iter() diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index a4e2cfbaee27d..1d5f5adf2eefe 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -1,7 +1,7 @@ //! This module is responsible for resolving paths within rules. use hir::AsAssocItem; -use ide_db::FxHashMap; +use ide_db::{FxHashMap, base_db::salsa}; use parsing::Placeholder; use syntax::{ SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, @@ -48,16 +48,20 @@ impl<'db> ResolvedRule<'db> { resolution_scope: &ResolutionScope<'db>, index: usize, ) -> Result, SsrError> { - let resolver = - Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in }; - let resolved_template = match rule.template { - Some(template) => Some(resolver.resolve_pattern_tree(template)?), - None => None, - }; - Ok(ResolvedRule { - pattern: resolver.resolve_pattern_tree(rule.pattern)?, - template: resolved_template, - index, + salsa::attach(resolution_scope.scope.db, || { + let resolver = Resolver { + resolution_scope, + placeholders_by_stand_in: rule.placeholders_by_stand_in, + }; + let resolved_template = match rule.template { + Some(template) => Some(resolver.resolve_pattern_tree(template)?), + None => None, + }; + Ok(ResolvedRule { + pattern: resolver.resolve_pattern_tree(rule.pattern)?, + template: resolved_template, + index, + }) }) } diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index c2f08f8ca2e6b..b004c07576748 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -4,6 +4,7 @@ use expect_test::{Expect, expect}; use hir::Semantics; use ide_db::{ FilePosition, FileRange, RootDatabase, + base_db::salsa, defs::Definition, documentation::{DocsRangeMap, Documentation, HasDocs}, }; @@ -63,8 +64,10 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { .flat_map(|(text_range, link, ns)| { let attr = range.map(text_range); let is_inner_attr = attr.map(|(_file, attr)| attr.is_inner_attr()).unwrap_or(false); - let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr) - .unwrap_or_else(|| panic!("Failed to resolve {link}")); + let def = salsa::attach(sema.db, || { + resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr) + .unwrap_or_else(|| panic!("Failed to resolve {link}")) + }); def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link)) }) .map(|(nav_target, link)| { diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index f768d4b68f469..633feec622cd9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -10,7 +10,7 @@ use hir::{ }; use ide_db::{ RootDatabase, SymbolKind, - base_db::{AnchoredPath, SourceDatabase}, + base_db::{AnchoredPath, SourceDatabase, salsa}, defs::{Definition, IdentClass}, famous_defs::FamousDefs, helpers::pick_best_token, @@ -108,7 +108,7 @@ pub(crate) fn goto_definition( } Some( - IdentClass::classify_node(sema, &parent)? + salsa::attach(sema.db, || IdentClass::classify_node(sema, &parent))? .definitions() .into_iter() .flat_map(|(def, _)| { diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 02d96a6473281..4f172621908c5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -234,6 +234,7 @@ impl crate::T for crate::Foo {} ); } + // FIXME(next-solver): it would be nice to be able to also point to `&Foo` #[test] fn goto_implementation_all_impls() { check( @@ -246,7 +247,6 @@ impl Foo {} impl T for Foo {} //^^^ impl T for &Foo {} - //^^^^ "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 44c98a43f6944..a48fe43e80803 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -12,6 +12,7 @@ use hir::{ }; use ide_db::{ FileRange, FxIndexSet, Ranker, RootDatabase, + base_db::salsa, defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, @@ -290,7 +291,7 @@ fn hover_offset( .into_iter() .unique_by(|&((def, _), _, _, _)| def) .map(|((def, subst), macro_arm, hovered_definition, node)| { - hover_for_definition( + salsa::attach(sema.db, || hover_for_definition( sema, file_id, def, @@ -301,7 +302,7 @@ fn hover_offset( config, edition, display_target, - ) + )) }) .collect::>(), ) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 51b5900e8155a..1c0272cdfacd1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -10,6 +10,7 @@ use hir::{ }; use ide_db::{ RootDatabase, + base_db::salsa, defs::Definition, documentation::{DocsRangeMap, HasDocs}, famous_defs::FamousDefs, @@ -44,7 +45,7 @@ pub(super) fn type_info_of( Either::Left(expr) => sema.type_of_expr(expr)?, Either::Right(pat) => sema.type_of_pat(pat)?, }; - type_info(sema, _config, ty_info, edition, display_target) + salsa::attach(sema.db, || type_info(sema, _config, ty_info, edition, display_target)) } pub(super) fn closure_expr( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index c5480217a91e2..6f1bbad6ba169 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -6,6 +6,8 @@ use crate::{ HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, fixture, }; +use hir::setup_tracing; + const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { links_in_hover: false, memory_layout: Some(MemoryLayoutHoverConfig { @@ -38,6 +40,7 @@ fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + let _tracing = setup_tracing(); let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 8c2a2f6f72f5e..f6416fe51c307 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,7 +8,9 @@ use hir::{ ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; -use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder}; +use ide_db::{ + FileRange, RootDatabase, base_db::salsa, famous_defs::FamousDefs, text_edit::TextEditBuilder, +}; use ide_db::{FxHashSet, text_edit::TextEdit}; use itertools::Itertools; use smallvec::{SmallVec, smallvec}; @@ -734,7 +736,7 @@ fn label_of_ty( config: &InlayHintsConfig, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { - let iter_item_type = hint_iterator(sema, famous_defs, ty); + let iter_item_type = salsa::attach(sema.db, || hint_iterator(sema, famous_defs, ty)); match iter_item_type { Some((iter_trait, item, ty)) => { const LABEL_START: &str = "impl "; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 4d020bac3aad4..39554d777795c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -411,10 +411,9 @@ fn main() { (()) == {()}; // ^^& // ^^^^& - let closure: dyn Fn = || (); + let closure: &dyn Fn = &|| (); + //^^^^^^&* closure(); - //^^^^^^^(& - //^^^^^^^) Struct[0]; //^^^^^^(& //^^^^^^) @@ -507,9 +506,10 @@ fn main() { (()) == {()}; // ^^.& // ^^^^.& - let closure: dyn Fn = || (); + let closure: &dyn Fn = &|| (); + //^^^^^^( + //^^^^^^).*.&. closure(); - //^^^^^^^.& Struct[0]; //^^^^^^.& &mut Struct[0]; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 922e9598aa017..7a4af4f7549c6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -909,7 +909,7 @@ fn main() { foo(plus_one); let add_mul = bar(|x: u8| { x + 1 }); - // ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized + // ^^^^^^^ impl FnOnce(u8) -> u8 let closure = if let Some(6) = add_mul(2).checked_sub(1) { // ^^^^^^^ fn(i32) -> i32 diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 382573b680113..2cccb9639f3eb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -733,7 +733,7 @@ fn signature_help_for_tuple_pat_ish<'db>( mod tests { use expect_test::{Expect, expect}; - use ide_db::FilePosition; + use ide_db::{FilePosition, base_db::salsa}; use stdx::format_to; use test_fixture::ChangeFixture; @@ -762,7 +762,7 @@ mod tests { "# ); let (db, position) = position(&fixture); - let sig_help = crate::signature_help::signature_help(&db, position); + let sig_help = salsa::attach(&db, || crate::signature_help::signature_help(&db, position)); let actual = match sig_help { Some(sig_help) => { let mut rendered = String::new(); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 3ca172977cb9e..e3dc3ed3c742a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -16,7 +16,7 @@ use std::ops::ControlFlow; use either::Either; use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics}; -use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind}; +use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind, base_db::salsa}; use syntax::{ AstNode, AstToken, NodeOrToken, SyntaxKind::*, @@ -434,15 +434,17 @@ fn traverse( |node| unsafe_ops.contains(&InFile::new(descended_element.file_id, node)); let element = match descended_element.value { NodeOrToken::Node(name_like) => { - let hl = highlight::name_like( - sema, - krate, - bindings_shadow_count, - &is_unsafe_node, - config.syntactic_name_ref_highlighting, - name_like, - edition, - ); + let hl = salsa::attach(sema.db, || { + highlight::name_like( + sema, + krate, + bindings_shadow_count, + &is_unsafe_node, + config.syntactic_name_ref_highlighting, + name_like, + edition, + ) + }); if hl.is_some() && !in_macro { // skip highlighting the contained token of our name-like node // as that would potentially overwrite our result diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index 00925bd81ed8e..d99b29cfb8fa6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -127,9 +127,9 @@ let y = &mut x; let z = &y; - let Foo { x: z, y } = Foo { x: z, y }; + let Foo { x: z, y } = Foo { x: z, y }; - y; + y; let mut foo = Foo { x, y: x }; let foo2 = Foo { x, y: x }; @@ -142,7 +142,7 @@ copy.qux(); copy.baz(copy); - let a = |x| x; + let a = |x| x; let bar = Foo::baz; let baz = (-42,); @@ -172,13 +172,13 @@ } async fn learn_and_sing() { - let song = learn_song().await; - sing_song(song).await; + let song = learn_song().await; + sing_song(song).await; } async fn async_main() { let f1 = learn_and_sing(); - let f2 = dance(); + let f2 = dance(); futures::join!(f1, f2); } 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 4780743c4d92a..983ed3684a4f6 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -178,6 +178,8 @@ define_symbols! { core, coroutine_state, coroutine, + coroutine_return, + coroutine_yield, count, crate_type, CStr, @@ -226,6 +228,8 @@ define_symbols! { async_fn_once_output, async_fn_mut, async_fn, + call_ref_future, + call_once_future, fn_ptr_addr, fn_ptr_trait, format_alignment, @@ -416,6 +420,7 @@ define_symbols! { rustc_allow_incoherent_impl, rustc_builtin_macro, rustc_coherence_is_core, + rustc_coinductive, rustc_const_panic_str, rustc_deallocator, rustc_deprecated_safe_2024, diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs index 9f3e636ef816a..00c37c01d25e2 100644 --- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs +++ b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs @@ -37,10 +37,10 @@ impl StopWatch { .build() .map_err(|err| eprintln!("Failed to create perf counter: {err}")) .ok(); - if let Some(counter) = &mut counter { - if let Err(err) = counter.enable() { - eprintln!("Failed to start perf counter: {err}") - } + if let Some(counter) = &mut counter + && let Err(err) = counter.enable() + { + eprintln!("Failed to start perf counter: {err}") } counter } else { diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs index c151cca07272a..22a26c49fa530 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs @@ -48,7 +48,8 @@ impl ToTokens for TrackedQuery { quote!(#(#options),*) }) .into_iter() - .chain(self.lru.map(|lru| quote!(lru = #lru))); + .chain(self.lru.map(|lru| quote!(lru = #lru))) + .chain(Some(quote!(unsafe(non_update_return_type)))); let annotation = quote!(#[salsa_macros::tracked( #(#options),* )]); let pat_and_tys = &self.pat_and_tys; 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 7b719b5dec754..b735b323ce430 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -35,7 +35,7 @@ //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive //! fmt_before_1_89_0: fmt -//! fn: tuple +//! fn: sized, tuple //! from: sized, result //! future: pin //! coroutine: pin @@ -325,6 +325,18 @@ pub mod clone { *self } } + + impl Clone for [T; 0] { + fn clone(&self) -> Self { + [] + } + } + + impl Clone for [T; 1] { + fn clone(&self) -> Self { + [self[0].clone()] + } + } // endregion:builtin_impls // region:derive @@ -1035,6 +1047,7 @@ pub mod ops { #[lang = "coroutine"] pub trait Coroutine { + #[lang = "coroutine_yield"] type Yield; #[lang = "coroutine_return"] type Return; From 6b8a812aafaad6b0edd04d12569fe43ee1e69eed Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Sun, 10 Aug 2025 01:38:17 -0400 Subject: [PATCH 025/251] parser: fix parsing of trait bound polarity and for-binders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rustc AST allows both `for<>` binders and `?` polarity modifiers in trait bounds, but they are parsed in a specific order and validated for correctness: 1. `for<>` binder is parsed first. 2. Polarity modifiers (`?`, `!`) are parsed second. 3. The parser validates that binders and polarity modifiers do not conflict: ```rust if let Some(binder_span) = binder_span { match modifiers.polarity { BoundPolarity::Maybe(polarity_span) => { // Error: "for<...> binder not allowed with ? polarity" } } } ``` This implies: - `for<> ?Sized` → Valid syntax. Invalid semantics. - `?for<> Sized` → Invalid syntax. However, rust-analyzer incorrectly had special-case logic that allowed `?for<>` as valid syntax. This fix removes that incorrect special case, making rust-analyzer reject `?for<> Sized` as a syntax error, matching rustc behavior. This has caused confusion in other crates (such as syn) which rely on these files to implement correct syntax evaluation. --- .../parser/src/grammar/generic_params.rs | 11 ++--- .../parser/test_data/generated/runner.rs | 6 +++ ...invalid_question_for_type_trait_bound.rast | 49 +++++++++++++++++++ .../invalid_question_for_type_trait_bound.rs | 1 + .../ok/question_for_type_trait_bound.rast | 23 +++++---- .../ok/question_for_type_trait_bound.rs | 2 +- 6 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index cb1b59f649774..d419817e5cd70 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -182,12 +182,6 @@ fn type_bound(p: &mut Parser<'_>) -> bool { ); m.complete(p, USE_BOUND_GENERIC_ARGS); } - T![?] if p.nth_at(1, T![for]) => { - // test question_for_type_trait_bound - // fn f() where T: ?for<> Sized {} - p.bump_any(); - types::for_type(p, false) - } _ => { if path_type_bound(p).is_err() { m.abandon(p); @@ -219,8 +213,13 @@ fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> { // test async_trait_bound // fn async_foo(_: impl async Fn(&i32)) {} p.eat(T![async]); + // test question_for_type_trait_bound + // fn f() where T: for<> ?Sized {} p.eat(T![?]); + // test_err invalid_question_for_type_trait_bound + // fn f() where T: ?for<> Sized {} + if paths::is_use_path_start(p) { types::path_type_bounds(p, false); // test_err type_bounds_macro_call_recovery diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index c642e1a3354fc..a3cfe64e6e739 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -796,6 +796,12 @@ mod err { #[test] fn impl_type() { run_and_expect_errors("test_data/parser/inline/err/impl_type.rs"); } #[test] + fn invalid_question_for_type_trait_bound() { + run_and_expect_errors( + "test_data/parser/inline/err/invalid_question_for_type_trait_bound.rs", + ); + } + #[test] fn let_else_right_curly_brace() { run_and_expect_errors("test_data/parser/inline/err/let_else_right_curly_brace.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rast new file mode 100644 index 0000000000000..b060ee81d6178 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rast @@ -0,0 +1,49 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "f" + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME + IDENT "T" + R_ANGLE ">" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "where" + WHITESPACE " " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + QUESTION "?" + WHERE_PRED + FOR_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + R_ANGLE ">" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Sized" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 20: expected comma +error 31: expected colon diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rs new file mode 100644 index 0000000000000..f80dd90d446c5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/invalid_question_for_type_trait_bound.rs @@ -0,0 +1 @@ +fn f() where T: ?for<> Sized {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast index cb296153c8f1a..69db1aee2c5a5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rast @@ -27,19 +27,18 @@ SOURCE_FILE WHITESPACE " " TYPE_BOUND_LIST TYPE_BOUND + FOR_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + R_ANGLE ">" + WHITESPACE " " QUESTION "?" - FOR_TYPE - FOR_BINDER - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - R_ANGLE ">" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Sized" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Sized" WHITESPACE " " BLOCK_EXPR STMT_LIST diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs index f80dd90d446c5..96353df3b9b33 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs @@ -1 +1 @@ -fn f() where T: ?for<> Sized {} +fn f() where T: for<> ?Sized {} From 8c0f4b40803a6d0c6ed6525026217c8d2532d205 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 10 Aug 2025 14:37:35 +0800 Subject: [PATCH 026/251] Fix extract_expressions_from_format_string on write! **Input**: ```rust fn main() { write!(f, "{2+3}$0") } ``` **Old output**: ```rust fn main() { write!("{}"$0, 2+3) } ``` **This PR output**: ```rust fn main() { write!(f, "{}"$0, 2+3) } ``` --- .../extract_expressions_from_format_string.rs | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index cdc0e967101a4..e3c7ea1b09391 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -7,8 +7,8 @@ use itertools::Itertools; use syntax::{ AstNode, AstToken, NodeOrToken, SyntaxKind::WHITESPACE, - T, - ast::{self, make, syntax_factory::SyntaxFactory}, + SyntaxToken, T, + ast::{self, TokenTree, make, syntax_factory::SyntaxFactory}, }; // Assist: extract_expressions_from_format_string @@ -58,10 +58,11 @@ pub(crate) fn extract_expressions_from_format_string( tt.syntax().text_range(), |edit| { // Extract existing arguments in macro - let tokens = tt.token_trees_and_tokens().collect_vec(); + let mut raw_tokens = tt.token_trees_and_tokens().skip(1).collect_vec(); + let format_string_index = format_str_index(&raw_tokens, &fmt_string); + let tokens = raw_tokens.split_off(format_string_index); let existing_args = if let [ - _opening_bracket, NodeOrToken::Token(_format_string), _args_start_comma, tokens @ .., @@ -90,9 +91,11 @@ pub(crate) fn extract_expressions_from_format_string( // Start building the new args let mut existing_args = existing_args.into_iter(); - let mut new_tt_bits = vec![NodeOrToken::Token(make::tokens::literal(&new_fmt))]; + let mut new_tt_bits = raw_tokens; let mut placeholder_indexes = vec![]; + new_tt_bits.push(NodeOrToken::Token(make::tokens::literal(&new_fmt))); + for arg in extracted_args { if matches!(arg, Arg::Expr(_) | Arg::Placeholder) { // insert ", " before each arg @@ -150,7 +153,9 @@ pub(crate) fn extract_expressions_from_format_string( } // Add the final tabstop after the format literal - if let Some(NodeOrToken::Token(literal)) = new_tt.token_trees_and_tokens().nth(1) { + if let Some(NodeOrToken::Token(literal)) = + new_tt.token_trees_and_tokens().nth(1 + format_string_index) + { let annotation = edit.make_tabstop_after(cap); editor.add_annotation(literal, annotation); } @@ -163,6 +168,17 @@ pub(crate) fn extract_expressions_from_format_string( Some(()) } +fn format_str_index( + raw_tokens: &[NodeOrToken], + fmt_string: &ast::String, +) -> usize { + let fmt_string = fmt_string.syntax(); + raw_tokens + .iter() + .position(|tt| tt.as_token().is_some_and(|tt| tt == fmt_string)) + .unwrap_or_default() +} + #[cfg(test)] mod tests { use super::*; @@ -186,6 +202,24 @@ fn main() { ); } + #[test] + fn multiple_middle_arg_on_write() { + check_assist( + extract_expressions_from_format_string, + r#" +//- minicore: write +fn main() { + write!(writer(), "{} {x + 1:b} {}$0", y + 2, 2); +} +"#, + r#" +fn main() { + write!(writer(), "{} {:b} {}"$0, y + 2, x + 1, 2); +} +"#, + ); + } + #[test] fn single_arg() { check_assist( From b9f2bb7dd11f23c7922fdc024a270bf8a4675616 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 10 Aug 2025 16:43:36 +0900 Subject: [PATCH 027/251] internal: Make flycheck generational --- .../crates/rust-analyzer/src/diagnostics.rs | 47 ++++++-- .../crates/rust-analyzer/src/flycheck.rs | 112 ++++++++++++++---- .../crates/rust-analyzer/src/main_loop.rs | 24 +++- .../crates/rust-analyzer/src/reload.rs | 3 + 4 files changed, 148 insertions(+), 38 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 438a2a0ba1ea1..cd7c632d105e0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -26,6 +26,19 @@ pub struct DiagnosticsMapConfig { pub(crate) type DiagnosticsGeneration = usize; +#[derive(Debug, Clone)] +pub(crate) struct WorkspaceFlycheckDiagnostic { + pub(crate) generation: DiagnosticsGeneration, + pub(crate) per_package: + FxHashMap>, FxHashMap>>, +} + +impl WorkspaceFlycheckDiagnostic { + fn new(generation: DiagnosticsGeneration) -> Self { + WorkspaceFlycheckDiagnostic { generation, per_package: Default::default() } + } +} + #[derive(Debug, Default, Clone)] pub(crate) struct DiagnosticCollection { // FIXME: should be FxHashMap> @@ -33,9 +46,7 @@ pub(crate) struct DiagnosticCollection { FxHashMap)>, pub(crate) native_semantic: FxHashMap)>, - // FIXME: should be Vec - pub(crate) check: - Vec>, FxHashMap>>>, + pub(crate) check: Vec, pub(crate) check_fixes: CheckFixes, changes: FxHashSet, /// Counter for supplying a new generation number for diagnostics. @@ -57,7 +68,7 @@ impl DiagnosticCollection { let Some(check) = self.check.get_mut(flycheck_id) else { return; }; - self.changes.extend(check.drain().flat_map(|(_, v)| v.into_keys())); + self.changes.extend(check.per_package.drain().flat_map(|(_, v)| v.into_keys())); if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { fixes.clear(); } @@ -66,7 +77,9 @@ impl DiagnosticCollection { pub(crate) fn clear_check_all(&mut self) { Arc::make_mut(&mut self.check_fixes).clear(); self.changes.extend( - self.check.iter_mut().flat_map(|it| it.drain().flat_map(|(_, v)| v.into_keys())), + self.check + .iter_mut() + .flat_map(|it| it.per_package.drain().flat_map(|(_, v)| v.into_keys())), ) } @@ -79,7 +92,7 @@ impl DiagnosticCollection { return; }; let package_id = Some(package_id); - if let Some(checks) = check.remove(&package_id) { + if let Some(checks) = check.per_package.remove(&package_id) { self.changes.extend(checks.into_keys()); } if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { @@ -87,6 +100,16 @@ impl DiagnosticCollection { } } + pub(crate) fn clear_check_older_than( + &mut self, + flycheck_id: usize, + generation: DiagnosticsGeneration, + ) { + if self.check[flycheck_id].generation < generation { + self.clear_check(flycheck_id); + } + } + pub(crate) fn clear_native_for(&mut self, file_id: FileId) { self.native_syntax.remove(&file_id); self.native_semantic.remove(&file_id); @@ -96,15 +119,23 @@ impl DiagnosticCollection { pub(crate) fn add_check_diagnostic( &mut self, flycheck_id: usize, + generation: DiagnosticsGeneration, package_id: &Option>, file_id: FileId, diagnostic: lsp_types::Diagnostic, fix: Option>, ) { if self.check.len() <= flycheck_id { - self.check.resize_with(flycheck_id + 1, Default::default); + self.check + .resize_with(flycheck_id + 1, || WorkspaceFlycheckDiagnostic::new(generation)); + } + + // Getting message from old generation. Might happen in restarting checks. + if self.check[flycheck_id].generation > generation { + return; } let diagnostics = self.check[flycheck_id] + .per_package .entry(package_id.clone()) .or_default() .entry(file_id) @@ -177,7 +208,7 @@ impl DiagnosticCollection { let check = self .check .iter() - .flat_map(|it| it.values()) + .flat_map(|it| it.per_package.values()) .filter_map(move |it| it.get(&file_id)) .flatten(); native_syntax.chain(native_semantic).chain(check) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index e4e0bcdc1cd08..233bedec6900a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -1,7 +1,12 @@ //! Flycheck provides the functionality needed to run `cargo check` to provide //! LSP diagnostics based on the output of the command. -use std::{fmt, io, process::Command, time::Duration}; +use std::{ + fmt, io, + process::Command, + sync::atomic::{AtomicUsize, Ordering}, + time::Duration, +}; use cargo_metadata::PackageId; use crossbeam_channel::{Receiver, Sender, select_biased, unbounded}; @@ -18,7 +23,10 @@ pub(crate) use cargo_metadata::diagnostic::{ use toolchain::Tool; use triomphe::Arc; -use crate::command::{CargoParser, CommandHandle}; +use crate::{ + command::{CargoParser, CommandHandle}, + diagnostics::DiagnosticsGeneration, +}; #[derive(Clone, Debug, Default, PartialEq, Eq)] pub(crate) enum InvocationStrategy { @@ -138,36 +146,54 @@ pub(crate) struct FlycheckHandle { sender: Sender, _thread: stdx::thread::JoinHandle, id: usize, + generation: AtomicUsize, } impl FlycheckHandle { pub(crate) fn spawn( id: usize, + generation: DiagnosticsGeneration, sender: Sender, config: FlycheckConfig, sysroot_root: Option, workspace_root: AbsPathBuf, manifest_path: Option, ) -> FlycheckHandle { - let actor = - FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path); + let actor = FlycheckActor::new( + id, + generation, + sender, + config, + sysroot_root, + workspace_root, + manifest_path, + ); let (sender, receiver) = unbounded::(); let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, format!("Flycheck{id}")) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); - FlycheckHandle { id, sender, _thread: thread } + FlycheckHandle { id, generation: generation.into(), sender, _thread: thread } } /// Schedule a re-start of the cargo check worker to do a workspace wide check. pub(crate) fn restart_workspace(&self, saved_file: Option) { - self.sender.send(StateChange::Restart { package: None, saved_file, target: None }).unwrap(); + let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; + self.sender + .send(StateChange::Restart { generation, package: None, saved_file, target: None }) + .unwrap(); } /// Schedule a re-start of the cargo check worker to do a package wide check. pub(crate) fn restart_for_package(&self, package: String, target: Option) { + let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; self.sender - .send(StateChange::Restart { package: Some(package), saved_file: None, target }) + .send(StateChange::Restart { + generation, + package: Some(package), + saved_file: None, + target, + }) .unwrap(); } @@ -179,23 +205,31 @@ impl FlycheckHandle { pub(crate) fn id(&self) -> usize { self.id } + + pub(crate) fn generation(&self) -> DiagnosticsGeneration { + self.generation.load(Ordering::Relaxed) + } +} + +#[derive(Debug)] +pub(crate) enum ClearDiagnosticsKind { + All, + OlderThan(DiagnosticsGeneration), + Package(Arc), } pub(crate) enum FlycheckMessage { /// Request adding a diagnostic with fixes included to a file AddDiagnostic { id: usize, + generation: DiagnosticsGeneration, workspace_root: Arc, diagnostic: Diagnostic, package_id: Option>, }, /// Request clearing all outdated diagnostics. - ClearDiagnostics { - id: usize, - /// The package whose diagnostics to clear, or if unspecified, all diagnostics. - package_id: Option>, - }, + ClearDiagnostics { id: usize, kind: ClearDiagnosticsKind }, /// Request check progress notification to client Progress { @@ -208,18 +242,23 @@ pub(crate) enum FlycheckMessage { impl fmt::Debug for FlycheckMessage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => f + FlycheckMessage::AddDiagnostic { + id, + generation, + workspace_root, + diagnostic, + package_id, + } => f .debug_struct("AddDiagnostic") .field("id", id) + .field("generation", generation) .field("workspace_root", workspace_root) .field("package_id", package_id) .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) .finish(), - FlycheckMessage::ClearDiagnostics { id, package_id } => f - .debug_struct("ClearDiagnostics") - .field("id", id) - .field("package_id", package_id) - .finish(), + FlycheckMessage::ClearDiagnostics { id, kind } => { + f.debug_struct("ClearDiagnostics").field("id", id).field("kind", kind).finish() + } FlycheckMessage::Progress { id, progress } => { f.debug_struct("Progress").field("id", id).field("progress", progress).finish() } @@ -237,7 +276,12 @@ pub(crate) enum Progress { } enum StateChange { - Restart { package: Option, saved_file: Option, target: Option }, + Restart { + generation: DiagnosticsGeneration, + package: Option, + saved_file: Option, + target: Option, + }, Cancel, } @@ -246,6 +290,7 @@ struct FlycheckActor { /// The workspace id of this flycheck instance. id: usize, + generation: DiagnosticsGeneration, sender: Sender, config: FlycheckConfig, manifest_path: Option, @@ -283,6 +328,7 @@ pub(crate) const SAVED_FILE_PLACEHOLDER: &str = "$saved_file"; impl FlycheckActor { fn new( id: usize, + generation: DiagnosticsGeneration, sender: Sender, config: FlycheckConfig, sysroot_root: Option, @@ -292,6 +338,7 @@ impl FlycheckActor { tracing::info!(%id, ?workspace_root, "Spawning flycheck"); FlycheckActor { id, + generation, sender, config, sysroot_root, @@ -327,7 +374,12 @@ impl FlycheckActor { tracing::debug!(flycheck_id = self.id, "flycheck cancelled"); self.cancel_check_process(); } - Event::RequestStateChange(StateChange::Restart { package, saved_file, target }) => { + Event::RequestStateChange(StateChange::Restart { + generation, + package, + saved_file, + target, + }) => { // Cancel the previously spawned process self.cancel_check_process(); while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) { @@ -337,6 +389,8 @@ impl FlycheckActor { } } + self.generation = generation; + let Some(command) = self.check_command(package.as_deref(), saved_file.as_deref(), target) else { @@ -383,7 +437,16 @@ impl FlycheckActor { // Clear everything for good measure self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - package_id: None, + kind: ClearDiagnosticsKind::All, + }); + } else if res.is_ok() { + // We clear diagnostics for packages on + // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where + // cargo may not report an artifact to our runner at all. To handle such + // cases, clear stale diagnostics when flycheck completes successfully. + self.send(FlycheckMessage::ClearDiagnostics { + id: self.id, + kind: ClearDiagnosticsKind::OlderThan(self.generation), }); } self.clear_diagnostics_state(); @@ -412,7 +475,7 @@ impl FlycheckActor { ); self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - package_id: Some(package_id), + kind: ClearDiagnosticsKind::Package(package_id), }); } } @@ -435,7 +498,7 @@ impl FlycheckActor { ); self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - package_id: Some(package_id.clone()), + kind: ClearDiagnosticsKind::Package(package_id.clone()), }); } } else if self.diagnostics_received @@ -444,11 +507,12 @@ impl FlycheckActor { self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll; self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - package_id: None, + kind: ClearDiagnosticsKind::All, }); } self.send(FlycheckMessage::AddDiagnostic { id: self.id, + generation: self.generation, package_id, workspace_root: self.root.clone(), diagnostic, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index f5932d8cff026..c6762f318326a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -20,7 +20,7 @@ use crate::{ config::Config, diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics}, discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, - flycheck::{self, FlycheckMessage}, + flycheck::{self, ClearDiagnosticsKind, FlycheckMessage}, global_state::{ FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, file_id_to_url, url_to_file_id, @@ -1008,7 +1008,13 @@ impl GlobalState { fn handle_flycheck_msg(&mut self, message: FlycheckMessage) { match message { - FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic, package_id } => { + FlycheckMessage::AddDiagnostic { + id, + generation, + workspace_root, + diagnostic, + package_id, + } => { let snap = self.snapshot(); let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( &self.config.diagnostics_map(None), @@ -1020,6 +1026,7 @@ impl GlobalState { match url_to_file_id(&self.vfs.read().0, &diag.url) { Ok(Some(file_id)) => self.diagnostics.add_check_diagnostic( id, + generation, &package_id, file_id, diag.diagnostic, @@ -1035,12 +1042,17 @@ impl GlobalState { }; } } - FlycheckMessage::ClearDiagnostics { id, package_id: None } => { + FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => { self.diagnostics.clear_check(id) } - FlycheckMessage::ClearDiagnostics { id, package_id: Some(package_id) } => { - self.diagnostics.clear_check_for_package(id, package_id) - } + FlycheckMessage::ClearDiagnostics { + id, + kind: ClearDiagnosticsKind::OlderThan(generation), + } => self.diagnostics.clear_check_older_than(id, generation), + FlycheckMessage::ClearDiagnostics { + id, + kind: ClearDiagnosticsKind::Package(package_id), + } => self.diagnostics.clear_check_for_package(id, package_id), FlycheckMessage::Progress { id, progress } => { let (state, message) = match progress { flycheck::Progress::DidStart => (Progress::Begin, None), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index aa38aa72d44eb..f8f29eee126ed 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -855,11 +855,13 @@ impl GlobalState { invocation_strategy.clone() } }; + let next_gen = self.flycheck.iter().map(|f| f.generation() + 1).max().unwrap_or_default(); self.flycheck = match invocation_strategy { crate::flycheck::InvocationStrategy::Once => { vec![FlycheckHandle::spawn( 0, + next_gen, sender, config, None, @@ -898,6 +900,7 @@ impl GlobalState { .map(|(id, (root, manifest_path), sysroot_root)| { FlycheckHandle::spawn( id, + next_gen, sender.clone(), config.clone(), sysroot_root, From f2c0c3dd44471e46ebb3823cc751c9c42aabc1aa Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Sun, 10 Aug 2025 11:56:35 -0700 Subject: [PATCH 028/251] Add testing for Arm64EC Windows --- library/stdarch/.github/workflows/main.yml | 10 +- .../core_arch/src/aarch64/neon/generated.rs | 248 ++++++++++++++ .../src/arm_shared/neon/generated.rs | 308 ++++++++++++++++++ .../core_arch/src/arm_shared/neon/mod.rs | 8 +- .../spec/neon/aarch64.spec.yml | 144 ++++++++ .../spec/neon/arm_shared.spec.yml | 111 +++++++ .../crates/stdarch-test/src/disassembly.rs | 6 +- 7 files changed, 823 insertions(+), 12 deletions(-) diff --git a/library/stdarch/.github/workflows/main.yml b/library/stdarch/.github/workflows/main.yml index 048ce9864604e..b0d476f0e2ea5 100644 --- a/library/stdarch/.github/workflows/main.yml +++ b/library/stdarch/.github/workflows/main.yml @@ -117,6 +117,8 @@ jobs: os: windows-2025 - tuple: aarch64-pc-windows-msvc os: windows-11-arm + - tuple: arm64ec-pc-windows-msvc + os: windows-11-arm - tuple: x86_64-pc-windows-gnu os: windows-2025 # - tuple: i686-pc-windows-gnu @@ -207,14 +209,6 @@ jobs: rustup update nightly --no-self-update rustup default nightly shell: bash - if: matrix.target.os != 'windows-11-arm' - - name: Install Rust for `windows-11-arm` runners - # The arm runners don't have Rust pre-installed (https://github.com/actions/partner-runner-images/issues/77) - run: | - curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly - echo "$HOME/.cargo/bin" >> $GITHUB_PATH - shell: bash - if: matrix.target.os == 'windows-11-arm' - run: rustup target add ${{ matrix.target.tuple }} shell: bash diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs index bc4c438038dc5..554a809db8db2 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs @@ -188,6 +188,7 @@ pub fn vabds_f32(a: f32, b: f32) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fabd))] pub fn vabdh_f16(a: f16, b: f16) -> f16 { unsafe { simd_extract!(vabd_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } @@ -947,6 +948,7 @@ pub fn vbcaxq_u64(a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x2_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fcma"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcadd))] pub fn vcadd_rot270_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -964,6 +966,7 @@ pub fn vcadd_rot270_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fcma"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcadd))] pub fn vcaddq_rot270_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -1029,6 +1032,7 @@ pub fn vcaddq_rot270_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fcma"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcadd))] pub fn vcadd_rot90_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -1046,6 +1050,7 @@ pub fn vcadd_rot90_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fcma"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcadd))] pub fn vcaddq_rot90_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -1175,6 +1180,7 @@ pub fn vcages_f32(a: f32, b: f32) -> u32 { #[cfg_attr(test, assert_instr(facge))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcageh_f16(a: f16, b: f16) -> u16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -1255,6 +1261,7 @@ pub fn vcagts_f32(a: f32, b: f32) -> u32 { #[cfg_attr(test, assert_instr(facgt))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcagth_f16(a: f16, b: f16) -> u16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -1307,6 +1314,7 @@ pub fn vcales_f32(a: f32, b: f32) -> u32 { #[cfg_attr(test, assert_instr(facge))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcaleh_f16(a: f16, b: f16) -> u16 { vcageh_f16(b, a) } @@ -1352,6 +1360,7 @@ pub fn vcalts_f32(a: f32, b: f32) -> u32 { #[cfg_attr(test, assert_instr(facgt))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcalth_f16(a: f16, b: f16) -> u16 { vcagth_f16(b, a) } @@ -1469,6 +1478,7 @@ pub fn vceqd_u64(a: u64, b: u64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceqh_f16(a: f16, b: f16) -> u16 { unsafe { simd_extract!(vceq_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } } @@ -1478,6 +1488,7 @@ pub fn vceqh_f16(a: f16, b: f16) -> u16 { #[cfg_attr(test, assert_instr(fcmeq))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceqz_f16(a: float16x4_t) -> uint16x4_t { let b: f16x4 = f16x4::new(0.0, 0.0, 0.0, 0.0); unsafe { simd_eq(a, transmute(b)) } @@ -1488,6 +1499,7 @@ pub fn vceqz_f16(a: float16x4_t) -> uint16x4_t { #[cfg_attr(test, assert_instr(fcmeq))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceqzq_f16(a: float16x8_t) -> uint16x8_t { let b: f16x8 = f16x8::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); unsafe { simd_eq(a, transmute(b)) } @@ -1756,6 +1768,7 @@ pub fn vceqzd_u64(a: u64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceqzh_f16(a: f16) -> u16 { unsafe { simd_extract!(vceqz_f16(vdup_n_f16(a)), 0) } } @@ -1873,6 +1886,7 @@ pub fn vcged_u64(a: u64, b: u64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgeh_f16(a: f16, b: f16) -> u16 { unsafe { simd_extract!(vcge_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } } @@ -2029,6 +2043,7 @@ pub fn vcgezd_s64(a: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgezh_f16(a: f16) -> u16 { unsafe { simd_extract!(vcgez_f16(vdup_n_f16(a)), 0) } } @@ -2128,6 +2143,7 @@ pub fn vcgtd_u64(a: u64, b: u64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgth_f16(a: f16, b: f16) -> u16 { unsafe { simd_extract!(vcgt_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } } @@ -2284,6 +2300,7 @@ pub fn vcgtzd_s64(a: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgtzh_f16(a: f16) -> u16 { unsafe { simd_extract!(vcgtz_f16(vdup_n_f16(a)), 0) } } @@ -2383,6 +2400,7 @@ pub fn vcled_s64(a: i64, b: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcleh_f16(a: f16, b: f16) -> u16 { unsafe { simd_extract!(vcle_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } } @@ -2539,6 +2557,7 @@ pub fn vclezd_s64(a: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vclezh_f16(a: f16) -> u16 { unsafe { simd_extract!(vclez_f16(vdup_n_f16(a)), 0) } } @@ -2620,6 +2639,7 @@ pub fn vcltd_s64(a: i64, b: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vclth_f16(a: f16, b: f16) -> u16 { unsafe { simd_extract!(vclt_f16(vdup_n_f16(a), vdup_n_f16(b)), 0) } } @@ -2794,6 +2814,7 @@ pub fn vcltzd_s64(a: i64) -> u64 { #[cfg_attr(test, assert_instr(fcmp))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcltzh_f16(a: f16) -> u16 { unsafe { simd_extract!(vcltz_f16(vdup_n_f16(a)), 0) } } @@ -2803,6 +2824,7 @@ pub fn vcltzh_f16(a: f16) -> u16 { #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmla_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -2820,6 +2842,7 @@ pub fn vcmla_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmlaq_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -2887,6 +2910,7 @@ pub fn vcmlaq_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float64x2_t #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_lane_f16( a: float16x4_t, b: float16x4_t, @@ -2915,6 +2939,7 @@ pub fn vcmla_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_lane_f16( a: float16x8_t, b: float16x8_t, @@ -2992,6 +3017,7 @@ pub fn vcmlaq_lane_f32( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -3020,6 +3046,7 @@ pub fn vcmla_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -3095,6 +3122,7 @@ pub fn vcmlaq_laneq_f32( #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmla_rot180_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -3112,6 +3140,7 @@ pub fn vcmla_rot180_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmlaq_rot180_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -3179,6 +3208,7 @@ pub fn vcmlaq_rot180_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> floa #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot180_lane_f16( a: float16x4_t, b: float16x4_t, @@ -3207,6 +3237,7 @@ pub fn vcmla_rot180_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot180_lane_f16( a: float16x8_t, b: float16x8_t, @@ -3284,6 +3315,7 @@ pub fn vcmlaq_rot180_lane_f32( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot180_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -3312,6 +3344,7 @@ pub fn vcmla_rot180_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot180_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -3387,6 +3420,7 @@ pub fn vcmlaq_rot180_laneq_f32( #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmla_rot270_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -3404,6 +3438,7 @@ pub fn vcmla_rot270_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmlaq_rot270_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -3471,6 +3506,7 @@ pub fn vcmlaq_rot270_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> floa #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot270_lane_f16( a: float16x4_t, b: float16x4_t, @@ -3499,6 +3535,7 @@ pub fn vcmla_rot270_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot270_lane_f16( a: float16x8_t, b: float16x8_t, @@ -3576,6 +3613,7 @@ pub fn vcmlaq_rot270_lane_f32( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot270_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -3604,6 +3642,7 @@ pub fn vcmla_rot270_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot270_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -3679,6 +3718,7 @@ pub fn vcmlaq_rot270_laneq_f32( #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmla_rot90_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -3696,6 +3736,7 @@ pub fn vcmla_rot90_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float1 #[target_feature(enable = "neon,fcma")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fcmla))] pub fn vcmlaq_rot90_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -3763,6 +3804,7 @@ pub fn vcmlaq_rot90_f64(a: float64x2_t, b: float64x2_t, c: float64x2_t) -> float #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot90_lane_f16( a: float16x4_t, b: float16x4_t, @@ -3791,6 +3833,7 @@ pub fn vcmla_rot90_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot90_lane_f16( a: float16x8_t, b: float16x8_t, @@ -3868,6 +3911,7 @@ pub fn vcmlaq_rot90_lane_f32( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmla_rot90_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -3896,6 +3940,7 @@ pub fn vcmla_rot90_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcmlaq_rot90_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -7161,6 +7206,7 @@ pub fn vcvtq_f64_u64(a: uint64x2_t) -> float64x2_t { #[cfg_attr(test, assert_instr(fcvtn2))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_high_f16_f32(a: float16x4_t, b: float32x4_t) -> float16x8_t { vcombine_f16(a, vcvt_f16_f32(b)) } @@ -7170,6 +7216,7 @@ pub fn vcvt_high_f16_f32(a: float16x4_t, b: float32x4_t) -> float16x8_t { #[cfg_attr(test, assert_instr(fcvtl2))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_high_f32_f16(a: float16x8_t) -> float32x4_t { vcvt_f32_f16(vget_high_f16(a)) } @@ -7408,6 +7455,7 @@ pub fn vcvtq_u64_f64(a: float64x2_t) -> uint64x2_t { #[cfg_attr(test, assert_instr(fcvtas))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvta_s16_f16(a: float16x4_t) -> int16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -7424,6 +7472,7 @@ pub fn vcvta_s16_f16(a: float16x4_t) -> int16x4_t { #[cfg_attr(test, assert_instr(fcvtas))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtaq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -7504,6 +7553,7 @@ pub fn vcvtaq_s64_f64(a: float64x2_t) -> int64x2_t { #[cfg_attr(test, assert_instr(fcvtau))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvta_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -7520,6 +7570,7 @@ pub fn vcvta_u16_f16(a: float16x4_t) -> uint16x4_t { #[cfg_attr(test, assert_instr(fcvtau))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtaq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -7600,6 +7651,7 @@ pub fn vcvtaq_u64_f64(a: float64x2_t) -> uint64x2_t { #[cfg_attr(test, assert_instr(fcvtas))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_s16_f16(a: f16) -> i16 { vcvtah_s32_f16(a) as i16 } @@ -7609,6 +7661,7 @@ pub fn vcvtah_s16_f16(a: f16) -> i16 { #[cfg_attr(test, assert_instr(fcvtas))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_s32_f16(a: f16) -> i32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -7625,6 +7678,7 @@ pub fn vcvtah_s32_f16(a: f16) -> i32 { #[cfg_attr(test, assert_instr(fcvtas))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_s64_f16(a: f16) -> i64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -7641,6 +7695,7 @@ pub fn vcvtah_s64_f16(a: f16) -> i64 { #[cfg_attr(test, assert_instr(fcvtau))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_u16_f16(a: f16) -> u16 { vcvtah_u32_f16(a) as u16 } @@ -7650,6 +7705,7 @@ pub fn vcvtah_u16_f16(a: f16) -> u16 { #[cfg_attr(test, assert_instr(fcvtau))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_u32_f16(a: f16) -> u32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -7666,6 +7722,7 @@ pub fn vcvtah_u32_f16(a: f16) -> u32 { #[cfg_attr(test, assert_instr(fcvtau))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtah_u64_f16(a: f16) -> u64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -7764,6 +7821,7 @@ pub fn vcvts_f32_s32(a: i32) -> f32 { #[cfg_attr(test, assert_instr(scvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_s16(a: i16) -> f16 { a as f16 } @@ -7773,6 +7831,7 @@ pub fn vcvth_f16_s16(a: i16) -> f16 { #[cfg_attr(test, assert_instr(scvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_s32(a: i32) -> f16 { a as f16 } @@ -7782,6 +7841,7 @@ pub fn vcvth_f16_s32(a: i32) -> f16 { #[cfg_attr(test, assert_instr(scvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_s64(a: i64) -> f16 { a as f16 } @@ -7791,6 +7851,7 @@ pub fn vcvth_f16_s64(a: i64) -> f16 { #[cfg_attr(test, assert_instr(ucvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_u16(a: u16) -> f16 { a as f16 } @@ -7800,6 +7861,7 @@ pub fn vcvth_f16_u16(a: u16) -> f16 { #[cfg_attr(test, assert_instr(ucvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_u32(a: u32) -> f16 { a as f16 } @@ -7809,6 +7871,7 @@ pub fn vcvth_f16_u32(a: u32) -> f16 { #[cfg_attr(test, assert_instr(ucvtf))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_f16_u64(a: u64) -> f16 { a as f16 } @@ -7819,6 +7882,7 @@ pub fn vcvth_f16_u64(a: u64) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_s16(a: i16) -> f16 { static_assert!(N >= 1 && N <= 16); vcvth_n_f16_s32::(a as i32) @@ -7830,6 +7894,7 @@ pub fn vcvth_n_f16_s16(a: i16) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_s32(a: i32) -> f16 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7848,6 +7913,7 @@ pub fn vcvth_n_f16_s32(a: i32) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_s64(a: i64) -> f16 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7866,6 +7932,7 @@ pub fn vcvth_n_f16_s64(a: i64) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_u16(a: u16) -> f16 { static_assert!(N >= 1 && N <= 16); vcvth_n_f16_u32::(a as u32) @@ -7877,6 +7944,7 @@ pub fn vcvth_n_f16_u16(a: u16) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_u32(a: u32) -> f16 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7895,6 +7963,7 @@ pub fn vcvth_n_f16_u32(a: u32) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_f16_u64(a: u64) -> f16 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7913,6 +7982,7 @@ pub fn vcvth_n_f16_u64(a: u64) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_s16_f16(a: f16) -> i16 { static_assert!(N >= 1 && N <= 16); vcvth_n_s32_f16::(a) as i16 @@ -7924,6 +7994,7 @@ pub fn vcvth_n_s16_f16(a: f16) -> i16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_s32_f16(a: f16) -> i32 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7942,6 +8013,7 @@ pub fn vcvth_n_s32_f16(a: f16) -> i32 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_s64_f16(a: f16) -> i64 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7960,6 +8032,7 @@ pub fn vcvth_n_s64_f16(a: f16) -> i64 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_u16_f16(a: f16) -> u16 { static_assert!(N >= 1 && N <= 16); vcvth_n_u32_f16::(a) as u16 @@ -7971,6 +8044,7 @@ pub fn vcvth_n_u16_f16(a: f16) -> u16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_u32_f16(a: f16) -> u32 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -7989,6 +8063,7 @@ pub fn vcvth_n_u32_f16(a: f16) -> u32 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_n_u64_f16(a: f16) -> u64 { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8006,6 +8081,7 @@ pub fn vcvth_n_u64_f16(a: f16) -> u64 { #[cfg_attr(test, assert_instr(fcvtzs))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_s16_f16(a: f16) -> i16 { a as i16 } @@ -8015,6 +8091,7 @@ pub fn vcvth_s16_f16(a: f16) -> i16 { #[cfg_attr(test, assert_instr(fcvtzs))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_s32_f16(a: f16) -> i32 { a as i32 } @@ -8024,6 +8101,7 @@ pub fn vcvth_s32_f16(a: f16) -> i32 { #[cfg_attr(test, assert_instr(fcvtzs))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_s64_f16(a: f16) -> i64 { a as i64 } @@ -8033,6 +8111,7 @@ pub fn vcvth_s64_f16(a: f16) -> i64 { #[cfg_attr(test, assert_instr(fcvtzu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_u16_f16(a: f16) -> u16 { a as u16 } @@ -8042,6 +8121,7 @@ pub fn vcvth_u16_f16(a: f16) -> u16 { #[cfg_attr(test, assert_instr(fcvtzu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_u32_f16(a: f16) -> u32 { a as u32 } @@ -8051,6 +8131,7 @@ pub fn vcvth_u32_f16(a: f16) -> u32 { #[cfg_attr(test, assert_instr(fcvtzu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvth_u64_f16(a: f16) -> u64 { a as u64 } @@ -8060,6 +8141,7 @@ pub fn vcvth_u64_f16(a: f16) -> u64 { #[cfg_attr(test, assert_instr(fcvtms))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtm_s16_f16(a: float16x4_t) -> int16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8076,6 +8158,7 @@ pub fn vcvtm_s16_f16(a: float16x4_t) -> int16x4_t { #[cfg_attr(test, assert_instr(fcvtms))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8156,6 +8239,7 @@ pub fn vcvtmq_s64_f64(a: float64x2_t) -> int64x2_t { #[cfg_attr(test, assert_instr(fcvtmu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtm_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8172,6 +8256,7 @@ pub fn vcvtm_u16_f16(a: float16x4_t) -> uint16x4_t { #[cfg_attr(test, assert_instr(fcvtmu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8252,6 +8337,7 @@ pub fn vcvtmq_u64_f64(a: float64x2_t) -> uint64x2_t { #[cfg_attr(test, assert_instr(fcvtms))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_s16_f16(a: f16) -> i16 { vcvtmh_s32_f16(a) as i16 } @@ -8261,6 +8347,7 @@ pub fn vcvtmh_s16_f16(a: f16) -> i16 { #[cfg_attr(test, assert_instr(fcvtms))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_s32_f16(a: f16) -> i32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8277,6 +8364,7 @@ pub fn vcvtmh_s32_f16(a: f16) -> i32 { #[cfg_attr(test, assert_instr(fcvtms))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_s64_f16(a: f16) -> i64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8293,6 +8381,7 @@ pub fn vcvtmh_s64_f16(a: f16) -> i64 { #[cfg_attr(test, assert_instr(fcvtmu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_u16_f16(a: f16) -> u16 { vcvtmh_u32_f16(a) as u16 } @@ -8302,6 +8391,7 @@ pub fn vcvtmh_u16_f16(a: f16) -> u16 { #[cfg_attr(test, assert_instr(fcvtmu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_u32_f16(a: f16) -> u32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8318,6 +8408,7 @@ pub fn vcvtmh_u32_f16(a: f16) -> u32 { #[cfg_attr(test, assert_instr(fcvtmu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtmh_u64_f16(a: f16) -> u64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8398,6 +8489,7 @@ pub fn vcvtmd_u64_f64(a: f64) -> u64 { #[cfg_attr(test, assert_instr(fcvtns))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtn_s16_f16(a: float16x4_t) -> int16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8414,6 +8506,7 @@ pub fn vcvtn_s16_f16(a: float16x4_t) -> int16x4_t { #[cfg_attr(test, assert_instr(fcvtns))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8494,6 +8587,7 @@ pub fn vcvtnq_s64_f64(a: float64x2_t) -> int64x2_t { #[cfg_attr(test, assert_instr(fcvtnu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtn_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8510,6 +8604,7 @@ pub fn vcvtn_u16_f16(a: float16x4_t) -> uint16x4_t { #[cfg_attr(test, assert_instr(fcvtnu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8590,6 +8685,7 @@ pub fn vcvtnq_u64_f64(a: float64x2_t) -> uint64x2_t { #[cfg_attr(test, assert_instr(fcvtns))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_s16_f16(a: f16) -> i16 { vcvtnh_s32_f16(a) as i16 } @@ -8599,6 +8695,7 @@ pub fn vcvtnh_s16_f16(a: f16) -> i16 { #[cfg_attr(test, assert_instr(fcvtns))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_s32_f16(a: f16) -> i32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8615,6 +8712,7 @@ pub fn vcvtnh_s32_f16(a: f16) -> i32 { #[cfg_attr(test, assert_instr(fcvtns))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_s64_f16(a: f16) -> i64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8631,6 +8729,7 @@ pub fn vcvtnh_s64_f16(a: f16) -> i64 { #[cfg_attr(test, assert_instr(fcvtnu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_u16_f16(a: f16) -> u16 { vcvtnh_u32_f16(a) as u16 } @@ -8640,6 +8739,7 @@ pub fn vcvtnh_u16_f16(a: f16) -> u16 { #[cfg_attr(test, assert_instr(fcvtnu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_u32_f16(a: f16) -> u32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8656,6 +8756,7 @@ pub fn vcvtnh_u32_f16(a: f16) -> u32 { #[cfg_attr(test, assert_instr(fcvtnu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtnh_u64_f16(a: f16) -> u64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8736,6 +8837,7 @@ pub fn vcvtnd_u64_f64(a: f64) -> u64 { #[cfg_attr(test, assert_instr(fcvtps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtp_s16_f16(a: float16x4_t) -> int16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8752,6 +8854,7 @@ pub fn vcvtp_s16_f16(a: float16x4_t) -> int16x4_t { #[cfg_attr(test, assert_instr(fcvtps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtpq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8832,6 +8935,7 @@ pub fn vcvtpq_s64_f64(a: float64x2_t) -> int64x2_t { #[cfg_attr(test, assert_instr(fcvtpu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtp_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8848,6 +8952,7 @@ pub fn vcvtp_u16_f16(a: float16x4_t) -> uint16x4_t { #[cfg_attr(test, assert_instr(fcvtpu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtpq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -8928,6 +9033,7 @@ pub fn vcvtpq_u64_f64(a: float64x2_t) -> uint64x2_t { #[cfg_attr(test, assert_instr(fcvtps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_s16_f16(a: f16) -> i16 { vcvtph_s32_f16(a) as i16 } @@ -8937,6 +9043,7 @@ pub fn vcvtph_s16_f16(a: f16) -> i16 { #[cfg_attr(test, assert_instr(fcvtps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_s32_f16(a: f16) -> i32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8953,6 +9060,7 @@ pub fn vcvtph_s32_f16(a: f16) -> i32 { #[cfg_attr(test, assert_instr(fcvtps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_s64_f16(a: f16) -> i64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8969,6 +9077,7 @@ pub fn vcvtph_s64_f16(a: f16) -> i64 { #[cfg_attr(test, assert_instr(fcvtpu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_u16_f16(a: f16) -> u16 { vcvtph_u32_f16(a) as u16 } @@ -8978,6 +9087,7 @@ pub fn vcvtph_u16_f16(a: f16) -> u16 { #[cfg_attr(test, assert_instr(fcvtpu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_u32_f16(a: f16) -> u32 { unsafe extern "unadjusted" { #[cfg_attr( @@ -8994,6 +9104,7 @@ pub fn vcvtph_u32_f16(a: f16) -> u32 { #[cfg_attr(test, assert_instr(fcvtpu))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtph_u64_f16(a: f16) -> u64 { unsafe extern "unadjusted" { #[cfg_attr( @@ -9305,6 +9416,7 @@ pub fn vcvtxd_f32_f64(a: f64) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fdiv))] pub fn vdiv_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_div(a, b) } @@ -9314,6 +9426,7 @@ pub fn vdiv_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fdiv))] pub fn vdivq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_div(a, b) } @@ -9359,6 +9472,7 @@ pub fn vdivq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vdivh_f16(a: f16, b: f16) -> f16 { a / b @@ -9608,6 +9722,7 @@ pub fn vdupd_lane_u64(a: uint64x1_t) -> u64 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vduph_lane_f16(a: float16x4_t) -> f16 { static_assert_uimm_bits!(N, 2); unsafe { simd_extract!(a, N as u32) } @@ -9619,6 +9734,7 @@ pub fn vduph_lane_f16(a: float16x4_t) -> f16 { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vduph_laneq_f16(a: float16x8_t) -> f16 { static_assert_uimm_bits!(N, 4); unsafe { simd_extract!(a, N as u32) } @@ -9977,6 +10093,7 @@ pub fn vfma_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float64x1_t { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfma_lane_f16( a: float16x4_t, b: float16x4_t, @@ -9992,6 +10109,7 @@ pub fn vfma_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfma_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -10007,6 +10125,7 @@ pub fn vfma_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmaq_lane_f16( a: float16x8_t, b: float16x8_t, @@ -10022,6 +10141,7 @@ pub fn vfmaq_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmaq_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -10140,6 +10260,7 @@ pub fn vfma_laneq_f64( #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmla))] pub fn vfma_n_f16(a: float16x4_t, b: float16x4_t, c: f16) -> float16x4_t { vfma_f16(a, b, vdup_n_f16(c)) @@ -10149,6 +10270,7 @@ pub fn vfma_n_f16(a: float16x4_t, b: float16x4_t, c: f16) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmla))] pub fn vfmaq_n_f16(a: float16x8_t, b: float16x8_t, c: f16) -> float16x8_t { vfmaq_f16(a, b, vdupq_n_f16(c)) @@ -10182,6 +10304,7 @@ pub fn vfmad_lane_f64(a: f64, b: f64, c: float64x1_t) -> f64 { #[cfg_attr(test, assert_instr(fmadd))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmah_f16(a: f16, b: f16, c: f16) -> f16 { unsafe { fmaf16(b, c, a) } } @@ -10192,6 +10315,7 @@ pub fn vfmah_f16(a: f16, b: f16, c: f16) -> f16 { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmah_lane_f16(a: f16, b: f16, v: float16x4_t) -> f16 { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -10206,6 +10330,7 @@ pub fn vfmah_lane_f16(a: f16, b: f16, v: float16x4_t) -> f16 { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmah_laneq_f16(a: f16, b: f16, v: float16x8_t) -> f16 { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -10294,6 +10419,7 @@ pub fn vfmad_laneq_f64(a: f64, b: f64, c: float64x2_t) -> f64 { #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlal2))] pub fn vfmlal_high_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32x2_t { unsafe extern "unadjusted" { @@ -10311,6 +10437,7 @@ pub fn vfmlal_high_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float3 #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlal2))] pub fn vfmlalq_high_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float32x4_t { unsafe extern "unadjusted" { @@ -10330,6 +10457,7 @@ pub fn vfmlalq_high_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlal_lane_high_f16( r: float32x2_t, a: float16x4_t, @@ -10346,6 +10474,7 @@ pub fn vfmlal_lane_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlal_laneq_high_f16( r: float32x2_t, a: float16x4_t, @@ -10362,6 +10491,7 @@ pub fn vfmlal_laneq_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlalq_lane_high_f16( r: float32x4_t, a: float16x8_t, @@ -10378,6 +10508,7 @@ pub fn vfmlalq_lane_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlalq_laneq_high_f16( r: float32x4_t, a: float16x8_t, @@ -10394,6 +10525,7 @@ pub fn vfmlalq_laneq_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlal_lane_low_f16( r: float32x2_t, a: float16x4_t, @@ -10410,6 +10542,7 @@ pub fn vfmlal_lane_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlal_laneq_low_f16( r: float32x2_t, a: float16x4_t, @@ -10426,6 +10559,7 @@ pub fn vfmlal_laneq_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlalq_lane_low_f16( r: float32x4_t, a: float16x8_t, @@ -10442,6 +10576,7 @@ pub fn vfmlalq_lane_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlalq_laneq_low_f16( r: float32x4_t, a: float16x8_t, @@ -10456,6 +10591,7 @@ pub fn vfmlalq_laneq_low_f16( #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlal))] pub fn vfmlal_low_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32x2_t { unsafe extern "unadjusted" { @@ -10473,6 +10609,7 @@ pub fn vfmlal_low_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32 #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlal))] pub fn vfmlalq_low_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float32x4_t { unsafe extern "unadjusted" { @@ -10490,6 +10627,7 @@ pub fn vfmlalq_low_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float3 #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlsl2))] pub fn vfmlsl_high_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32x2_t { unsafe extern "unadjusted" { @@ -10507,6 +10645,7 @@ pub fn vfmlsl_high_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float3 #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlsl2))] pub fn vfmlslq_high_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float32x4_t { unsafe extern "unadjusted" { @@ -10526,6 +10665,7 @@ pub fn vfmlslq_high_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlsl_lane_high_f16( r: float32x2_t, a: float16x4_t, @@ -10542,6 +10682,7 @@ pub fn vfmlsl_lane_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlsl_laneq_high_f16( r: float32x2_t, a: float16x4_t, @@ -10558,6 +10699,7 @@ pub fn vfmlsl_laneq_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlslq_lane_high_f16( r: float32x4_t, a: float16x8_t, @@ -10574,6 +10716,7 @@ pub fn vfmlslq_lane_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlslq_laneq_high_f16( r: float32x4_t, a: float16x8_t, @@ -10590,6 +10733,7 @@ pub fn vfmlslq_laneq_high_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlsl_lane_low_f16( r: float32x2_t, a: float16x4_t, @@ -10606,6 +10750,7 @@ pub fn vfmlsl_lane_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlsl_laneq_low_f16( r: float32x2_t, a: float16x4_t, @@ -10622,6 +10767,7 @@ pub fn vfmlsl_laneq_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlslq_lane_low_f16( r: float32x4_t, a: float16x8_t, @@ -10638,6 +10784,7 @@ pub fn vfmlslq_lane_low_f16( #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[rustc_legacy_const_generics(3)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmlslq_laneq_low_f16( r: float32x4_t, a: float16x8_t, @@ -10652,6 +10799,7 @@ pub fn vfmlslq_laneq_low_f16( #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlsl))] pub fn vfmlsl_low_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32x2_t { unsafe extern "unadjusted" { @@ -10669,6 +10817,7 @@ pub fn vfmlsl_low_f16(r: float32x2_t, a: float16x4_t, b: float16x4_t) -> float32 #[target_feature(enable = "neon,fp16")] #[cfg_attr(not(target_arch = "arm"), target_feature(enable = "fhm"))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmlsl))] pub fn vfmlslq_low_f16(r: float32x4_t, a: float16x8_t, b: float16x8_t) -> float32x4_t { unsafe extern "unadjusted" { @@ -10699,6 +10848,7 @@ pub fn vfms_f64(a: float64x1_t, b: float64x1_t, c: float64x1_t) -> float64x1_t { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfms_lane_f16( a: float16x4_t, b: float16x4_t, @@ -10714,6 +10864,7 @@ pub fn vfms_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfms_laneq_f16( a: float16x4_t, b: float16x4_t, @@ -10729,6 +10880,7 @@ pub fn vfms_laneq_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsq_lane_f16( a: float16x8_t, b: float16x8_t, @@ -10744,6 +10896,7 @@ pub fn vfmsq_lane_f16( #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsq_laneq_f16( a: float16x8_t, b: float16x8_t, @@ -10862,6 +11015,7 @@ pub fn vfms_laneq_f64( #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmls))] pub fn vfms_n_f16(a: float16x4_t, b: float16x4_t, c: f16) -> float16x4_t { vfms_f16(a, b, vdup_n_f16(c)) @@ -10871,6 +11025,7 @@ pub fn vfms_n_f16(a: float16x4_t, b: float16x4_t, c: f16) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmls))] pub fn vfmsq_n_f16(a: float16x8_t, b: float16x8_t, c: f16) -> float16x8_t { vfmsq_f16(a, b, vdupq_n_f16(c)) @@ -10890,6 +11045,7 @@ pub fn vfms_n_f64(a: float64x1_t, b: float64x1_t, c: f64) -> float64x1_t { #[cfg_attr(test, assert_instr(fmsub))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsh_f16(a: f16, b: f16, c: f16) -> f16 { vfmah_f16(a, -b, c) } @@ -10900,6 +11056,7 @@ pub fn vfmsh_f16(a: f16, b: f16, c: f16) -> f16 { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsh_lane_f16(a: f16, b: f16, v: float16x4_t) -> f16 { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -10914,6 +11071,7 @@ pub fn vfmsh_lane_f16(a: f16, b: f16, v: float16x4_t) -> f16 { #[rustc_legacy_const_generics(3)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsh_laneq_f16(a: f16, b: f16, v: float16x8_t) -> f16 { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -11005,6 +11163,7 @@ pub fn vfmsd_laneq_f64(a: f64, b: f64, c: float64x2_t) -> f64 { #[target_feature(enable = "neon,fp16")] #[cfg_attr(test, assert_instr(ldr))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { crate::ptr::read_unaligned(ptr.cast()) } @@ -11016,6 +11175,7 @@ pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(test, assert_instr(ldr))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_f16(ptr: *const f16) -> float16x8_t { crate::ptr::read_unaligned(ptr.cast()) } @@ -13107,6 +13267,7 @@ pub fn vmaxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmax))] pub fn vmaxh_f16(a: f16, b: f16) -> f16 { unsafe extern "unadjusted" { @@ -13141,6 +13302,7 @@ pub fn vmaxnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxnm))] pub fn vmaxnmh_f16(a: f16, b: f16) -> f16 { f16::max(a, b) @@ -13150,6 +13312,7 @@ pub fn vmaxnmh_f16(a: f16, b: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxnmv))] pub fn vmaxnmv_f16(a: float16x4_t) -> f16 { unsafe { simd_reduce_max(a) } @@ -13159,6 +13322,7 @@ pub fn vmaxnmv_f16(a: float16x4_t) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxnmv))] pub fn vmaxnmvq_f16(a: float16x8_t) -> f16 { unsafe { simd_reduce_max(a) } @@ -13195,6 +13359,7 @@ pub fn vmaxnmvq_f32(a: float32x4_t) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxv))] pub fn vmaxv_f16(a: float16x4_t) -> f16 { unsafe extern "unadjusted" { @@ -13211,6 +13376,7 @@ pub fn vmaxv_f16(a: float16x4_t) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxv))] pub fn vmaxvq_f16(a: float16x8_t) -> f16 { unsafe extern "unadjusted" { @@ -13415,6 +13581,7 @@ pub fn vminq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmin))] pub fn vminh_f16(a: f16, b: f16) -> f16 { unsafe extern "unadjusted" { @@ -13449,6 +13616,7 @@ pub fn vminnmq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminnm))] pub fn vminnmh_f16(a: f16, b: f16) -> f16 { f16::min(a, b) @@ -13458,6 +13626,7 @@ pub fn vminnmh_f16(a: f16, b: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminnmv))] pub fn vminnmv_f16(a: float16x4_t) -> f16 { unsafe { simd_reduce_min(a) } @@ -13467,6 +13636,7 @@ pub fn vminnmv_f16(a: float16x4_t) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminnmv))] pub fn vminnmvq_f16(a: float16x8_t) -> f16 { unsafe { simd_reduce_min(a) } @@ -13503,6 +13673,7 @@ pub fn vminnmvq_f32(a: float32x4_t) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminv))] pub fn vminv_f16(a: float16x4_t) -> f16 { unsafe extern "unadjusted" { @@ -13519,6 +13690,7 @@ pub fn vminv_f16(a: float16x4_t) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminv))] pub fn vminvq_f16(a: float16x8_t) -> f16 { unsafe extern "unadjusted" { @@ -14554,6 +14726,7 @@ pub fn vmul_lane_f64(a: float64x1_t, b: float64x1_t) -> float64 #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmul_laneq_f16(a: float16x4_t, b: float16x8_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -14570,6 +14743,7 @@ pub fn vmul_laneq_f16(a: float16x4_t, b: float16x8_t) -> float1 #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulq_laneq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -14640,6 +14814,7 @@ pub fn vmuld_lane_f64(a: f64, b: float64x1_t) -> f64 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vmulh_f16(a: f16, b: f16) -> f16 { a * b @@ -14651,6 +14826,7 @@ pub fn vmulh_f16(a: f16, b: f16) -> f16 { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulh_lane_f16(a: f16, b: float16x4_t) -> f16 { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -14665,6 +14841,7 @@ pub fn vmulh_lane_f16(a: f16, b: float16x4_t) -> f16 { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulh_laneq_f16(a: f16, b: float16x8_t) -> f16 { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -15073,6 +15250,7 @@ pub fn vmuld_laneq_f64(a: f64, b: float64x2_t) -> f64 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmulx))] pub fn vmulx_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -15089,6 +15267,7 @@ pub fn vmulx_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmulx))] pub fn vmulxq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -15171,6 +15350,7 @@ pub fn vmulxq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulx_lane_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -15187,6 +15367,7 @@ pub fn vmulx_lane_f16(a: float16x4_t, b: float16x4_t) -> float1 #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulx_laneq_f16(a: float16x4_t, b: float16x8_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -15203,6 +15384,7 @@ pub fn vmulx_laneq_f16(a: float16x4_t, b: float16x8_t) -> float #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulxq_lane_f16(a: float16x8_t, b: float16x4_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -15232,6 +15414,7 @@ pub fn vmulxq_lane_f16(a: float16x8_t, b: float16x4_t) -> float #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulxq_laneq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 3); unsafe { @@ -15347,6 +15530,7 @@ pub fn vmulx_laneq_f64(a: float64x1_t, b: float64x2_t) -> float #[cfg_attr(test, assert_instr(fmulx))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulx_n_f16(a: float16x4_t, b: f16) -> float16x4_t { vmulx_f16(a, vdup_n_f16(b)) } @@ -15356,6 +15540,7 @@ pub fn vmulx_n_f16(a: float16x4_t, b: f16) -> float16x4_t { #[cfg_attr(test, assert_instr(fmulx))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulxq_n_f16(a: float16x8_t, b: f16) -> float16x8_t { vmulxq_f16(a, vdupq_n_f16(b)) } @@ -15440,6 +15625,7 @@ pub fn vmulxs_laneq_f32(a: f32, b: float32x4_t) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmulx))] pub fn vmulxh_f16(a: f16, b: f16) -> f16 { unsafe extern "unadjusted" { @@ -15458,6 +15644,7 @@ pub fn vmulxh_f16(a: f16, b: f16) -> f16 { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulxh_lane_f16(a: f16, b: float16x4_t) -> f16 { static_assert_uimm_bits!(LANE, 2); unsafe { vmulxh_f16(a, simd_extract!(b, LANE as u32)) } @@ -15469,6 +15656,7 @@ pub fn vmulxh_lane_f16(a: f16, b: float16x4_t) -> f16 { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulxh_laneq_f16(a: f16, b: float16x8_t) -> f16 { static_assert_uimm_bits!(LANE, 3); unsafe { vmulxh_f16(a, simd_extract!(b, LANE as u32)) } @@ -15534,6 +15722,7 @@ pub fn vnegd_s64(a: i64) -> i64 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fneg))] pub fn vnegh_f16(a: f16) -> f16 { -a @@ -15587,6 +15776,7 @@ pub fn vpaddd_u64(a: uint64x2_t) -> u64 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(faddp))] pub fn vpaddq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -15805,6 +15995,7 @@ pub fn vpaddq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxp))] pub fn vpmax_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -15821,6 +16012,7 @@ pub fn vpmax_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxp))] pub fn vpmaxq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -15837,6 +16029,7 @@ pub fn vpmaxq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxnmp))] pub fn vpmaxnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -15853,6 +16046,7 @@ pub fn vpmaxnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fmaxnmp))] pub fn vpmaxnmq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -16109,6 +16303,7 @@ pub fn vpmaxs_f32(a: float32x2_t) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminp))] pub fn vpmin_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -16125,6 +16320,7 @@ pub fn vpmin_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminp))] pub fn vpminq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -16141,6 +16337,7 @@ pub fn vpminq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminnmp))] pub fn vpminnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -16157,6 +16354,7 @@ pub fn vpminnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fminnmp))] pub fn vpminnmq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -21135,6 +21333,7 @@ pub fn vrecpes_f32(a: f32) -> f32 { #[cfg_attr(test, assert_instr(frecpe))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpeh_f16(a: f16) -> f16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -21215,6 +21414,7 @@ pub fn vrecpss_f32(a: f32, b: f32) -> f32 { #[cfg_attr(test, assert_instr(frecps))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpsh_f16(a: f16, b: f16) -> f16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -21263,6 +21463,7 @@ pub fn vrecpxs_f32(a: f32) -> f32 { #[cfg_attr(test, assert_instr(frecpx))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpxh_f16(a: f16) -> f16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -21279,6 +21480,7 @@ pub fn vrecpxh_f16(a: f16) -> f16 { #[cfg(target_endian = "little")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { unsafe { transmute(a) } @@ -21289,6 +21491,7 @@ pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; @@ -21300,6 +21503,7 @@ pub fn vreinterpret_f64_f16(a: float16x4_t) -> float64x1_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { unsafe { transmute(a) } @@ -21310,6 +21514,7 @@ pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; @@ -21324,6 +21529,7 @@ pub fn vreinterpretq_f64_f16(a: float16x8_t) -> float64x2_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { unsafe { transmute(a) } @@ -21334,6 +21540,7 @@ pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { unsafe { @@ -21347,6 +21554,7 @@ pub fn vreinterpret_f16_f64(a: float64x1_t) -> float16x4_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f16_f64(a: float64x2_t) -> float16x8_t { unsafe { transmute(a) } @@ -21357,6 +21565,7 @@ pub fn vreinterpretq_f16_f64(a: float64x2_t) -> float16x8_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vreinterpretq_f16_f64(a: float64x2_t) -> float16x8_t { let a: float64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; @@ -22935,6 +23144,7 @@ pub fn vrnd64z_f64(a: float64x1_t) -> float64x1_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintz))] pub fn vrnd_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_trunc(a) } @@ -22944,6 +23154,7 @@ pub fn vrnd_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintz))] pub fn vrndq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_trunc(a) } @@ -22989,6 +23200,7 @@ pub fn vrndq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinta))] pub fn vrnda_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_round(a) } @@ -22998,6 +23210,7 @@ pub fn vrnda_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinta))] pub fn vrndaq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_round(a) } @@ -23043,6 +23256,7 @@ pub fn vrndaq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinta))] pub fn vrndah_f16(a: f16) -> f16 { unsafe { roundf16(a) } @@ -23052,6 +23266,7 @@ pub fn vrndah_f16(a: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintz))] pub fn vrndh_f16(a: f16) -> f16 { unsafe { truncf16(a) } @@ -23061,6 +23276,7 @@ pub fn vrndh_f16(a: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinti))] pub fn vrndi_f16(a: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { @@ -23077,6 +23293,7 @@ pub fn vrndi_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinti))] pub fn vrndiq_f16(a: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { @@ -23157,6 +23374,7 @@ pub fn vrndiq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frinti))] pub fn vrndih_f16(a: f16) -> f16 { unsafe extern "unadjusted" { @@ -23173,6 +23391,7 @@ pub fn vrndih_f16(a: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintm))] pub fn vrndm_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_floor(a) } @@ -23182,6 +23401,7 @@ pub fn vrndm_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintm))] pub fn vrndmq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_floor(a) } @@ -23227,6 +23447,7 @@ pub fn vrndmq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintm))] pub fn vrndmh_f16(a: f16) -> f16 { unsafe { floorf16(a) } @@ -23268,6 +23489,7 @@ pub fn vrndnq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintn))] pub fn vrndnh_f16(a: f16) -> f16 { unsafe extern "unadjusted" { @@ -23300,6 +23522,7 @@ pub fn vrndns_f32(a: f32) -> f32 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintp))] pub fn vrndp_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_ceil(a) } @@ -23309,6 +23532,7 @@ pub fn vrndp_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintp))] pub fn vrndpq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_ceil(a) } @@ -23354,6 +23578,7 @@ pub fn vrndpq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintp))] pub fn vrndph_f16(a: f16) -> f16 { unsafe { ceilf16(a) } @@ -23363,6 +23588,7 @@ pub fn vrndph_f16(a: f16) -> f16 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintx))] pub fn vrndx_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_round_ties_even(a) } @@ -23372,6 +23598,7 @@ pub fn vrndx_f16(a: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintx))] pub fn vrndxq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_round_ties_even(a) } @@ -23417,6 +23644,7 @@ pub fn vrndxq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(frintx))] pub fn vrndxh_f16(a: f16) -> f16 { round_ties_even_f16(a) @@ -23623,6 +23851,7 @@ pub fn vrsqrtes_f32(a: f32) -> f32 { #[cfg_attr(test, assert_instr(frsqrte))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrteh_f16(a: f16) -> f16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -23703,6 +23932,7 @@ pub fn vrsqrtss_f32(a: f32, b: f32) -> f32 { #[target_feature(enable = "neon,fp16")] #[cfg_attr(test, assert_instr(frsqrts))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrtsh_f16(a: f16, b: f16) -> f16 { unsafe extern "unadjusted" { #[cfg_attr( @@ -24791,6 +25021,7 @@ pub fn vsqadds_u32(a: u32, b: i32) -> u32 { #[cfg_attr(test, assert_instr(fsqrt))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vsqrt_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_fsqrt(a) } } @@ -24800,6 +25031,7 @@ pub fn vsqrt_f16(a: float16x4_t) -> float16x4_t { #[cfg_attr(test, assert_instr(fsqrt))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vsqrtq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_fsqrt(a) } } @@ -24844,6 +25076,7 @@ pub fn vsqrtq_f64(a: float64x2_t) -> float64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(fsqrt))] pub fn vsqrth_f16(a: f16) -> f16 { unsafe { sqrtf16(a) } @@ -25177,6 +25410,7 @@ pub fn vsrid_n_u64(a: u64, b: u64) -> u64 { #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16(ptr: *mut f16, a: float16x4_t) { crate::ptr::write_unaligned(ptr.cast(), a) } @@ -25189,6 +25423,7 @@ pub unsafe fn vst1_f16(ptr: *mut f16, a: float16x4_t) { #[cfg_attr(test, assert_instr(str))] #[allow(clippy::cast_ptr_alignment)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16(ptr: *mut f16, a: float16x8_t) { crate::ptr::write_unaligned(ptr.cast(), a) } @@ -26488,6 +26723,7 @@ pub fn vsubd_u64(a: u64, b: u64) -> u64 { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vsubh_f16(a: f16, b: f16) -> f16 { a - b @@ -27283,6 +27519,7 @@ pub fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(trn1))] pub fn vtrn1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [0, 4, 2, 6]) } @@ -27292,6 +27529,7 @@ pub fn vtrn1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(trn1))] pub fn vtrn1q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [0, 8, 2, 10, 4, 12, 6, 14]) } @@ -27517,6 +27755,7 @@ pub fn vtrn1q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(trn2))] pub fn vtrn2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [1, 5, 3, 7]) } @@ -27526,6 +27765,7 @@ pub fn vtrn2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(trn2))] pub fn vtrn2q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [1, 9, 3, 11, 5, 13, 7, 15]) } @@ -28056,6 +28296,7 @@ pub fn vusdotq_laneq_s32(a: int32x4_t, b: uint8x16_t, c: int8x1 #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(uzp1))] pub fn vuzp1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [0, 2, 4, 6]) } @@ -28065,6 +28306,7 @@ pub fn vuzp1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(uzp1))] pub fn vuzp1q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [0, 2, 4, 6, 8, 10, 12, 14]) } @@ -28290,6 +28532,7 @@ pub fn vuzp1q_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(uzp2))] pub fn vuzp2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [1, 3, 5, 7]) } @@ -28299,6 +28542,7 @@ pub fn vuzp2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(uzp2))] pub fn vuzp2q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [1, 3, 5, 7, 9, 11, 13, 15]) } @@ -28542,6 +28786,7 @@ pub fn vxarq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(zip1))] pub fn vzip1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [0, 4, 1, 5]) } @@ -28551,6 +28796,7 @@ pub fn vzip1_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(zip1))] pub fn vzip1q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [0, 8, 1, 9, 2, 10, 3, 11]) } @@ -28776,6 +29022,7 @@ pub fn vzip1q_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(zip2))] pub fn vzip2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, b, [2, 6, 3, 7]) } @@ -28785,6 +29032,7 @@ pub fn vzip2_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { #[inline] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(zip2))] pub fn vzip2q_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [4, 12, 5, 13, 6, 14, 7, 15]) } diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index 32531c7da1356..fd150bcaf2b7f 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -820,6 +820,7 @@ pub fn vabaq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vabd_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v4f16")] @@ -842,6 +843,7 @@ pub fn vabd_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vabdq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vabds.v8f16")] @@ -1405,6 +1407,7 @@ pub fn vabdl_u32(a: uint32x2_t, b: uint32x2_t) -> uint64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vabs_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_fabs(a) } } @@ -1419,6 +1422,7 @@ pub fn vabs_f16(a: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vabsq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_fabs(a) } } @@ -1625,6 +1629,7 @@ pub fn vabsq_s32(a: int32x4_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vabsh_f16(a: f16) -> f16 { unsafe { simd_extract!(vabs_f16(vdup_n_f16(a)), 0) } } @@ -1639,6 +1644,7 @@ pub fn vabsh_f16(a: f16) -> f16 { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vadd_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_add(a, b) } } @@ -1653,6 +1659,7 @@ pub fn vadd_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vaddq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_add(a, b) } } @@ -2129,6 +2136,7 @@ pub fn vaddq_p64(a: poly64x2_t, b: poly64x2_t) -> poly64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vaddh_f16(a: f16, b: f16) -> f16 { a + b } @@ -3828,6 +3836,7 @@ pub fn vbicq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { assert_instr(bsl) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vbsl_f16(a: uint16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { let not = int16x4_t::splat(-1); unsafe { @@ -3848,6 +3857,7 @@ pub fn vbsl_f16(a: uint16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { assert_instr(bsl) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vbslq_f16(a: uint16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { let not = int16x8_t::splat(-1); unsafe { @@ -4462,6 +4472,7 @@ pub fn vbslq_u8(a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcage_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacge.v4i16.v4f16")] @@ -4484,6 +4495,7 @@ pub fn vcage_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcageq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacge.v8i16.v8f16")] @@ -4564,6 +4576,7 @@ pub fn vcageq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcagt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacgt.v4i16.v4f16")] @@ -4586,6 +4599,7 @@ pub fn vcagt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcagtq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vacgt.v8i16.v8f16")] @@ -4666,6 +4680,7 @@ pub fn vcagtq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcale_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { vcage_f16(b, a) } @@ -4680,6 +4695,7 @@ pub fn vcale_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcaleq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { vcageq_f16(b, a) } @@ -4736,6 +4752,7 @@ pub fn vcaleq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcalt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { vcagt_f16(b, a) } @@ -4750,6 +4767,7 @@ pub fn vcalt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcaltq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { vcagtq_f16(b, a) } @@ -4806,6 +4824,7 @@ pub fn vcaltq_f32(a: float32x4_t, b: float32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceq_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe { simd_eq(a, b) } } @@ -4820,6 +4839,7 @@ pub fn vceq_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vceqq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe { simd_eq(a, b) } } @@ -5170,6 +5190,7 @@ pub fn vceqq_p8(a: poly8x16_t, b: poly8x16_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcge_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe { simd_ge(a, b) } } @@ -5184,6 +5205,7 @@ pub fn vcge_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgeq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe { simd_ge(a, b) } } @@ -5492,6 +5514,7 @@ pub fn vcgeq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgez_f16(a: float16x4_t) -> uint16x4_t { let b: f16x4 = f16x4::new(0.0, 0.0, 0.0, 0.0); unsafe { simd_ge(a, transmute(b)) } @@ -5507,6 +5530,7 @@ pub fn vcgez_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgezq_f16(a: float16x8_t) -> uint16x8_t { let b: f16x8 = f16x8::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); unsafe { simd_ge(a, transmute(b)) } @@ -5522,6 +5546,7 @@ pub fn vcgezq_f16(a: float16x8_t) -> uint16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe { simd_gt(a, b) } } @@ -5536,6 +5561,7 @@ pub fn vcgt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgtq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe { simd_gt(a, b) } } @@ -5844,6 +5870,7 @@ pub fn vcgtq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgtz_f16(a: float16x4_t) -> uint16x4_t { let b: f16x4 = f16x4::new(0.0, 0.0, 0.0, 0.0); unsafe { simd_gt(a, transmute(b)) } @@ -5859,6 +5886,7 @@ pub fn vcgtz_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcgtzq_f16(a: float16x8_t) -> uint16x8_t { let b: f16x8 = f16x8::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); unsafe { simd_gt(a, transmute(b)) } @@ -5874,6 +5902,7 @@ pub fn vcgtzq_f16(a: float16x8_t) -> uint16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcle_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe { simd_le(a, b) } } @@ -5888,6 +5917,7 @@ pub fn vcle_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcleq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe { simd_le(a, b) } } @@ -6196,6 +6226,7 @@ pub fn vcleq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vclez_f16(a: float16x4_t) -> uint16x4_t { let b: f16x4 = f16x4::new(0.0, 0.0, 0.0, 0.0); unsafe { simd_le(a, transmute(b)) } @@ -6211,6 +6242,7 @@ pub fn vclez_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vclezq_f16(a: float16x8_t) -> uint16x8_t { let b: f16x8 = f16x8::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); unsafe { simd_le(a, transmute(b)) } @@ -6526,6 +6558,7 @@ pub fn vclsq_u32(a: uint32x4_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vclt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { unsafe { simd_lt(a, b) } } @@ -6540,6 +6573,7 @@ pub fn vclt_f16(a: float16x4_t, b: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcltq_f16(a: float16x8_t, b: float16x8_t) -> uint16x8_t { unsafe { simd_lt(a, b) } } @@ -6848,6 +6882,7 @@ pub fn vcltq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcltz_f16(a: float16x4_t) -> uint16x4_t { let b: f16x4 = f16x4::new(0.0, 0.0, 0.0, 0.0); unsafe { simd_lt(a, transmute(b)) } @@ -6863,6 +6898,7 @@ pub fn vcltz_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcltzq_f16(a: float16x8_t) -> uint16x8_t { let b: f16x8 = f16x8::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); unsafe { simd_lt(a, transmute(b)) } @@ -7536,6 +7572,7 @@ pub fn vcntq_p8(a: poly8x16_t) -> poly8x16_t { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vcombine_f16(a: float16x4_t, b: float16x4_t) -> float16x8_t { unsafe { simd_shuffle!(a, b, [0, 1, 2, 3, 4, 5, 6, 7]) } @@ -7756,6 +7793,7 @@ pub fn vcombine_p64(a: poly64x1_t, b: poly64x1_t) -> poly64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcreate_f16(a: u64) -> float16x4_t { unsafe { transmute(a) } } @@ -7771,6 +7809,7 @@ pub fn vcreate_f16(a: u64) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcreate_f16(a: u64) -> float16x4_t { unsafe { let ret_val: float16x4_t = transmute(a); @@ -8274,6 +8313,7 @@ pub fn vcreate_p64(a: u64) -> poly64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_f16_f32(a: float32x4_t) -> float16x4_t { unsafe { simd_cast(a) } } @@ -8288,6 +8328,7 @@ pub fn vcvt_f16_f32(a: float32x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_f16_s16(a: int16x4_t) -> float16x4_t { unsafe { simd_cast(a) } } @@ -8302,6 +8343,7 @@ pub fn vcvt_f16_s16(a: int16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_f16_s16(a: int16x8_t) -> float16x8_t { unsafe { simd_cast(a) } } @@ -8316,6 +8358,7 @@ pub fn vcvtq_f16_s16(a: int16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_f16_u16(a: uint16x4_t) -> float16x4_t { unsafe { simd_cast(a) } } @@ -8330,6 +8373,7 @@ pub fn vcvt_f16_u16(a: uint16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_f16_u16(a: uint16x8_t) -> float16x8_t { unsafe { simd_cast(a) } } @@ -8344,6 +8388,7 @@ pub fn vcvtq_f16_u16(a: uint16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_f32_f16(a: float16x4_t) -> float32x4_t { unsafe { simd_cast(a) } } @@ -8443,6 +8488,7 @@ pub fn vcvtq_f32_u32(a: uint32x4_t) -> float32x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_n_f16_s16(a: int16x4_t) -> float16x4_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8470,6 +8516,7 @@ pub fn vcvt_n_f16_s16(a: int16x4_t) -> float16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_n_f16_s16(a: int16x8_t) -> float16x8_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8497,6 +8544,7 @@ pub fn vcvtq_n_f16_s16(a: int16x8_t) -> float16x8_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_n_f16_u16(a: uint16x4_t) -> float16x4_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8524,6 +8572,7 @@ pub fn vcvt_n_f16_u16(a: uint16x4_t) -> float16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_n_f16_u16(a: uint16x8_t) -> float16x8_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8703,6 +8752,7 @@ pub fn vcvtq_n_f32_u32(a: uint32x4_t) -> float32x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_n_s16_f16(a: float16x4_t) -> int16x4_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8730,6 +8780,7 @@ pub fn vcvt_n_s16_f16(a: float16x4_t) -> int16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_n_s16_f16(a: float16x8_t) -> int16x8_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8833,6 +8884,7 @@ pub fn vcvtq_n_s32_f32(a: float32x4_t) -> int32x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_n_u16_f16(a: float16x4_t) -> uint16x4_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8860,6 +8912,7 @@ pub fn vcvt_n_u16_f16(a: float16x4_t) -> uint16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_n_u16_f16(a: float16x8_t) -> uint16x8_t { static_assert!(N >= 1 && N <= 16); unsafe extern "unadjusted" { @@ -8962,6 +9015,7 @@ pub fn vcvtq_n_u32_f32(a: float32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_s16_f16(a: float16x4_t) -> int16x4_t { unsafe { simd_cast(a) } } @@ -8976,6 +9030,7 @@ pub fn vcvt_s16_f16(a: float16x4_t) -> int16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe { simd_cast(a) } } @@ -9048,6 +9103,7 @@ pub fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvt_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe { simd_cast(a) } } @@ -9062,6 +9118,7 @@ pub fn vcvt_u16_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vcvtq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe { simd_cast(a) } } @@ -9361,6 +9418,7 @@ pub fn vdotq_u32(a: uint32x4_t, b: uint8x16_t, c: uint8x16_t) -> uint32x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdup_lane_f16(a: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(N, 2); unsafe { simd_shuffle!(a, a, [N as u32, N as u32, N as u32, N as u32]) } @@ -9377,6 +9435,7 @@ pub fn vdup_lane_f16(a: float16x4_t) -> float16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdupq_lane_f16(a: float16x4_t) -> float16x8_t { static_assert_uimm_bits!(N, 2); unsafe { @@ -9922,6 +9981,7 @@ pub fn vdup_lane_u64(a: uint64x1_t) -> uint64x1_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdup_laneq_f16(a: float16x8_t) -> float16x4_t { static_assert_uimm_bits!(N, 3); unsafe { simd_shuffle!(a, a, [N as u32, N as u32, N as u32, N as u32]) } @@ -9938,6 +9998,7 @@ pub fn vdup_laneq_f16(a: float16x8_t) -> float16x4_t { #[rustc_legacy_const_generics(1)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdupq_laneq_f16(a: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(N, 3); unsafe { @@ -10482,6 +10543,7 @@ pub fn vdup_laneq_u64(a: uint64x2_t) -> uint64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdup_n_f16(a: f16) -> float16x4_t { float16x4_t::splat(a) } @@ -10496,6 +10558,7 @@ pub fn vdup_n_f16(a: f16) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vdupq_n_f16(a: f16) -> float16x8_t { float16x8_t::splat(a) } @@ -11443,6 +11506,7 @@ pub fn veorq_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vext_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(N, 2); unsafe { @@ -11814,6 +11878,7 @@ pub fn vextq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vextq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(N, 3); unsafe { @@ -12394,6 +12459,7 @@ pub fn vextq_p8(a: poly8x16_t, b: poly8x16_t) -> poly8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfma_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe { simd_fma(b, c, a) } } @@ -12408,6 +12474,7 @@ pub fn vfma_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmaq_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe { simd_fma(b, c, a) } } @@ -12507,6 +12574,7 @@ pub fn vfmaq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfms_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { unsafe { let b: float16x4_t = simd_neg(b); @@ -12525,6 +12593,7 @@ pub fn vfms_f16(a: float16x4_t, b: float16x4_t, c: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vfmsq_f16(a: float16x8_t, b: float16x8_t, c: float16x8_t) -> float16x8_t { unsafe { let b: float16x8_t = simd_neg(b); @@ -12627,6 +12696,7 @@ pub fn vfmsq_n_f32(a: float32x4_t, b: float32x4_t, c: f32) -> float32x4_t { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vget_high_f16(a: float16x8_t) -> float16x4_t { unsafe { simd_shuffle!(a, a, [4, 5, 6, 7]) } @@ -12637,6 +12707,7 @@ pub fn vget_high_f16(a: float16x8_t) -> float16x4_t { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(nop))] pub fn vget_low_f16(a: float16x8_t) -> float16x4_t { unsafe { simd_shuffle!(a, a, [0, 1, 2, 3]) } @@ -12884,6 +12955,7 @@ pub fn vget_high_u64(a: uint64x2_t) -> uint64x1_t { )] #[rustc_legacy_const_generics(1)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vget_lane_f16(a: float16x4_t) -> f16 { static_assert_uimm_bits!(LANE, 2); unsafe { simd_extract!(a, LANE as u32) } @@ -12900,6 +12972,7 @@ pub fn vget_lane_f16(a: float16x4_t) -> f16 { )] #[rustc_legacy_const_generics(1)] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vgetq_lane_f16(a: float16x8_t) -> f16 { static_assert_uimm_bits!(LANE, 3); unsafe { simd_extract!(a, LANE as u32) } @@ -14256,6 +14329,7 @@ pub fn vhsubq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_dup_f16(ptr: *const f16) -> float16x4_t { let x: float16x4_t = vld1_lane_f16::<0>(ptr, transmute(f16x4::splat(0.0))); simd_shuffle!(x, x, [0, 0, 0, 0]) @@ -14273,6 +14347,7 @@ pub unsafe fn vld1_dup_f16(ptr: *const f16) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_dup_f16(ptr: *const f16) -> float16x8_t { let x: float16x8_t = vld1q_lane_f16::<0>(ptr, transmute(f16x8::splat(0.0))); simd_shuffle!(x, x, [0, 0, 0, 0, 0, 0, 0, 0]) @@ -14843,6 +14918,7 @@ pub unsafe fn vld1_dup_u64(ptr: *const u64) -> uint64x1_t { #[target_feature(enable = "neon,v7")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { transmute(vld1_v4f16( @@ -14860,6 +14936,7 @@ pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { #[target_feature(enable = "neon,v7")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { let ret_val: float16x4_t = transmute(vld1_v4f16( @@ -14878,6 +14955,7 @@ pub unsafe fn vld1_f16(ptr: *const f16) -> float16x4_t { #[target_feature(enable = "neon,v7")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] pub unsafe fn vld1q_f16(ptr: *const f16) -> float16x8_t { transmute(vld1q_v8f16( @@ -14895,6 +14973,7 @@ pub unsafe fn vld1q_f16(ptr: *const f16) -> float16x8_t { #[target_feature(enable = "neon,v7")] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vld1.16"))] pub unsafe fn vld1q_f16(ptr: *const f16) -> float16x8_t { let ret_val: float16x8_t = transmute(vld1q_v8f16( @@ -14916,6 +14995,7 @@ pub unsafe fn vld1q_f16(ptr: *const f16) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_f16_x2(a: *const f16) -> float16x4x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -14940,6 +15020,7 @@ pub unsafe fn vld1_f16_x2(a: *const f16) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_f16_x3(a: *const f16) -> float16x4x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -14964,6 +15045,7 @@ pub unsafe fn vld1_f16_x3(a: *const f16) -> float16x4x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_f16_x4(a: *const f16) -> float16x4x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -14988,6 +15070,7 @@ pub unsafe fn vld1_f16_x4(a: *const f16) -> float16x4x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_f16_x2(a: *const f16) -> float16x8x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -15012,6 +15095,7 @@ pub unsafe fn vld1q_f16_x2(a: *const f16) -> float16x8x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_f16_x3(a: *const f16) -> float16x8x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -15036,6 +15120,7 @@ pub unsafe fn vld1q_f16_x3(a: *const f16) -> float16x8x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_f16_x4(a: *const f16) -> float16x8x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -15732,6 +15817,7 @@ pub unsafe fn vld1q_f32_x4(a: *const f32) -> float32x4x4_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1_lane_f16(ptr: *const f16, src: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 2); simd_insert!(src, LANE as u32, *ptr) @@ -15750,6 +15836,7 @@ pub unsafe fn vld1_lane_f16(ptr: *const f16, src: float16x4_t) #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld1q_lane_f16(ptr: *const f16, src: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 3); simd_insert!(src, LANE as u32, *ptr) @@ -19490,6 +19577,7 @@ unsafe fn vld1q_v8i16(a: *const i8, b: i32) -> int16x8_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] unsafe fn vld1_v4f16(a: *const i8, b: i32) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4f16")] @@ -19507,6 +19595,7 @@ unsafe fn vld1_v4f16(a: *const i8, b: i32) -> float16x4_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(nop))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] unsafe fn vld1q_v8f16(a: *const i8, b: i32) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v8f16")] @@ -19548,6 +19637,7 @@ pub unsafe fn vld1q_dup_p64(ptr: *const p64) -> poly64x2_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld2))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_dup_f16(a: *const f16) -> float16x4x2_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld2dup.v4f16.p0")] @@ -19565,6 +19655,7 @@ pub unsafe fn vld2_dup_f16(a: *const f16) -> float16x4x2_t { #[target_feature(enable = "neon,fp16")] #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld2))] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_dup_f16(a: *const f16) -> float16x8x2_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld2dup.v8f16.p0")] @@ -19584,6 +19675,7 @@ pub unsafe fn vld2q_dup_f16(a: *const f16) -> float16x8x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_dup_f16(a: *const f16) -> float16x4x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -19606,6 +19698,7 @@ pub unsafe fn vld2_dup_f16(a: *const f16) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_dup_f16(a: *const f16) -> float16x8x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -20521,6 +20614,7 @@ pub unsafe fn vld2q_dup_p16(a: *const p16) -> poly16x8x2_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld2))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_f16(a: *const f16) -> float16x4x2_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld2.v4f16.p0")] @@ -20538,6 +20632,7 @@ pub unsafe fn vld2_f16(a: *const f16) -> float16x4x2_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld2))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_f16(a: *const f16) -> float16x8x2_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld2.v8f16.p0")] @@ -20557,6 +20652,7 @@ pub unsafe fn vld2q_f16(a: *const f16) -> float16x8x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_f16(a: *const f16) -> float16x4x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -20579,6 +20675,7 @@ pub unsafe fn vld2_f16(a: *const f16) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_f16(a: *const f16) -> float16x8x2_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -20880,6 +20977,7 @@ pub unsafe fn vld2q_s32(a: *const i32) -> int32x4x2_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_lane_f16(a: *const f16, b: float16x4x2_t) -> float16x4x2_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -20905,6 +21003,7 @@ pub unsafe fn vld2_lane_f16(a: *const f16, b: float16x4x2_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_lane_f16(a: *const f16, b: float16x8x2_t) -> float16x8x2_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -20932,6 +21031,7 @@ pub unsafe fn vld2q_lane_f16(a: *const f16, b: float16x8x2_t) - #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2_lane_f16(a: *const f16, b: float16x4x2_t) -> float16x4x2_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -20957,6 +21057,7 @@ pub unsafe fn vld2_lane_f16(a: *const f16, b: float16x4x2_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld2q_lane_f16(a: *const f16, b: float16x8x2_t) -> float16x8x2_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -22109,6 +22210,7 @@ pub unsafe fn vld2q_p16(a: *const p16) -> poly16x8x2_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld3))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_dup_f16(a: *const f16) -> float16x4x3_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld3dup.v4f16.p0")] @@ -22126,6 +22228,7 @@ pub unsafe fn vld3_dup_f16(a: *const f16) -> float16x4x3_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld3))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_dup_f16(a: *const f16) -> float16x8x3_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld3dup.v8f16.p0")] @@ -22145,6 +22248,7 @@ pub unsafe fn vld3q_dup_f16(a: *const f16) -> float16x8x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_dup_f16(a: *const f16) -> float16x4x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -22167,6 +22271,7 @@ pub unsafe fn vld3_dup_f16(a: *const f16) -> float16x4x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_dup_f16(a: *const f16) -> float16x8x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -23104,6 +23209,7 @@ pub unsafe fn vld3q_dup_p16(a: *const p16) -> poly16x8x3_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld3))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_f16(a: *const f16) -> float16x4x3_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld3.v4f16.p0")] @@ -23121,6 +23227,7 @@ pub unsafe fn vld3_f16(a: *const f16) -> float16x4x3_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld3))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_f16(a: *const f16) -> float16x8x3_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld3.v8f16.p0")] @@ -23140,6 +23247,7 @@ pub unsafe fn vld3q_f16(a: *const f16) -> float16x8x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_f16(a: *const f16) -> float16x4x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -23162,6 +23270,7 @@ pub unsafe fn vld3_f16(a: *const f16) -> float16x4x3_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_f16(a: *const f16) -> float16x8x3_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -23463,6 +23572,7 @@ pub unsafe fn vld3q_s32(a: *const i32) -> int32x4x3_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_lane_f16(a: *const f16, b: float16x4x3_t) -> float16x4x3_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -23489,6 +23599,7 @@ pub unsafe fn vld3_lane_f16(a: *const f16, b: float16x4x3_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_lane_f16(a: *const f16, b: float16x8x3_t) -> float16x8x3_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -23517,6 +23628,7 @@ pub unsafe fn vld3q_lane_f16(a: *const f16, b: float16x8x3_t) - #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3_lane_f16(a: *const f16, b: float16x4x3_t) -> float16x4x3_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -23547,6 +23659,7 @@ pub unsafe fn vld3_lane_f16(a: *const f16, b: float16x4x3_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld3q_lane_f16(a: *const f16, b: float16x8x3_t) -> float16x8x3_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -24775,6 +24888,7 @@ pub unsafe fn vld3q_lane_f32(a: *const f32, b: float32x4x3_t) - #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld4))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_dup_f16(a: *const f16) -> float16x4x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld4dup.v4f16.p0")] @@ -24792,6 +24906,7 @@ pub unsafe fn vld4_dup_f16(a: *const f16) -> float16x4x4_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld4))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_dup_f16(a: *const f16) -> float16x8x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld4dup.v8f16.p0")] @@ -24811,6 +24926,7 @@ pub unsafe fn vld4q_dup_f16(a: *const f16) -> float16x8x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_dup_f16(a: *const f16) -> float16x4x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -24833,6 +24949,7 @@ pub unsafe fn vld4_dup_f16(a: *const f16) -> float16x4x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_dup_f16(a: *const f16) -> float16x8x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -25792,6 +25909,7 @@ pub unsafe fn vld4q_dup_p16(a: *const p16) -> poly16x8x4_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld4))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_f16(a: *const f16) -> float16x4x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld4.v4f16.p0")] @@ -25809,6 +25927,7 @@ pub unsafe fn vld4_f16(a: *const f16) -> float16x4x4_t { #[cfg_attr(all(test, target_arch = "arm"), assert_instr(vld4))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_f16(a: *const f16) -> float16x8x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld4.v8f16.p0")] @@ -25828,6 +25947,7 @@ pub unsafe fn vld4q_f16(a: *const f16) -> float16x8x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_f16(a: *const f16) -> float16x4x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -25850,6 +25970,7 @@ pub unsafe fn vld4_f16(a: *const f16) -> float16x4x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_f16(a: *const f16) -> float16x8x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -26151,6 +26272,7 @@ pub unsafe fn vld4q_s32(a: *const i32) -> int32x4x4_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_lane_f16(a: *const f16, b: float16x4x4_t) -> float16x4x4_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -26178,6 +26300,7 @@ pub unsafe fn vld4_lane_f16(a: *const f16, b: float16x4x4_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_lane_f16(a: *const f16, b: float16x8x4_t) -> float16x8x4_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -26207,6 +26330,7 @@ pub unsafe fn vld4q_lane_f16(a: *const f16, b: float16x8x4_t) - #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4_lane_f16(a: *const f16, b: float16x4x4_t) -> float16x4x4_t { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -26238,6 +26362,7 @@ pub unsafe fn vld4_lane_f16(a: *const f16, b: float16x4x4_t) -> #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vld4q_lane_f16(a: *const f16, b: float16x8x4_t) -> float16x8x4_t { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -27527,6 +27652,7 @@ pub unsafe fn vldrq_p128(a: *const p128) -> p128 { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmax_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v4f16")] @@ -27549,6 +27675,7 @@ pub fn vmax_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmaxq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmaxs.v8f16")] @@ -27917,6 +28044,7 @@ pub fn vmaxq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmaxnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_fmax(a, b) } } @@ -27931,6 +28059,7 @@ pub fn vmaxnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmaxnmq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_fmax(a, b) } } @@ -27987,6 +28116,7 @@ pub fn vmaxnmq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmin_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v4f16")] @@ -28009,6 +28139,7 @@ pub fn vmin_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vminq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vmins.v8f16")] @@ -28377,6 +28508,7 @@ pub fn vminq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vminnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_fmin(a, b) } } @@ -28391,6 +28523,7 @@ pub fn vminnm_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vminnmq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_fmin(a, b) } } @@ -31573,6 +31706,7 @@ pub fn vmmlaq_u32(a: uint32x4_t, b: uint8x16_t, c: uint8x16_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmov_n_f16(a: f16) -> float16x4_t { vdup_n_f16(a) } @@ -31587,6 +31721,7 @@ pub fn vmov_n_f16(a: f16) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmovq_n_f16(a: f16) -> float16x8_t { vdupq_n_f16(a) } @@ -32315,6 +32450,7 @@ pub fn vmovn_u64(a: uint64x2_t) -> uint32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmul_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_mul(a, b) } } @@ -32329,6 +32465,7 @@ pub fn vmul_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_mul(a, b) } } @@ -32386,6 +32523,7 @@ pub fn vmulq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmul_lane_f16(a: float16x4_t, v: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -32407,6 +32545,7 @@ pub fn vmul_lane_f16(a: float16x4_t, v: float16x4_t) -> float16 #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulq_lane_f16(a: float16x8_t, v: float16x4_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 2); unsafe { @@ -33022,6 +33161,7 @@ pub fn vmulq_laneq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmul_n_f16(a: float16x4_t, b: f16) -> float16x4_t { unsafe { simd_mul(a, vdup_n_f16(b)) } } @@ -33036,6 +33176,7 @@ pub fn vmul_n_f16(a: float16x4_t, b: f16) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vmulq_n_f16(a: float16x8_t, b: f16) -> float16x8_t { unsafe { simd_mul(a, vdupq_n_f16(b)) } } @@ -34369,6 +34510,7 @@ pub fn vmvnq_u8(a: uint8x16_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vneg_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_neg(a) } } @@ -34383,6 +34525,7 @@ pub fn vneg_f16(a: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vnegq_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_neg(a) } } @@ -35613,6 +35756,7 @@ pub fn vpadalq_u32(a: uint64x2_t, b: uint32x4_t) -> uint64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vpadd_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v4f16")] @@ -41943,6 +42087,7 @@ pub fn vraddhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpe_f16(a: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v4f16")] @@ -41965,6 +42110,7 @@ pub fn vrecpe_f16(a: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpeq_f16(a: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecpe.v8f16")] @@ -42103,6 +42249,7 @@ pub fn vrecpeq_u32(a: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecps_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecps.v4f16")] @@ -42125,6 +42272,7 @@ pub fn vrecps_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrecpsq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrecps.v8f16")] @@ -42206,6 +42354,7 @@ pub fn vrecpsq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { unsafe { transmute(a) } } @@ -42221,6 +42370,7 @@ pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42240,6 +42390,7 @@ pub fn vreinterpret_f32_f16(a: float16x4_t) -> float32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { unsafe { transmute(a) } } @@ -42255,6 +42406,7 @@ pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42274,6 +42426,7 @@ pub fn vreinterpret_s8_f16(a: float16x4_t) -> int8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { unsafe { transmute(a) } } @@ -42289,6 +42442,7 @@ pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42308,6 +42462,7 @@ pub fn vreinterpret_s16_f16(a: float16x4_t) -> int16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { unsafe { transmute(a) } } @@ -42323,6 +42478,7 @@ pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42342,6 +42498,7 @@ pub fn vreinterpret_s32_f16(a: float16x4_t) -> int32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { unsafe { transmute(a) } } @@ -42357,6 +42514,7 @@ pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { transmute(a) } @@ -42373,6 +42531,7 @@ pub fn vreinterpret_s64_f16(a: float16x4_t) -> int64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { unsafe { transmute(a) } } @@ -42388,6 +42547,7 @@ pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42407,6 +42567,7 @@ pub fn vreinterpret_u8_f16(a: float16x4_t) -> uint8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { unsafe { transmute(a) } } @@ -42422,6 +42583,7 @@ pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42441,6 +42603,7 @@ pub fn vreinterpret_u16_f16(a: float16x4_t) -> uint16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { unsafe { transmute(a) } } @@ -42456,6 +42619,7 @@ pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42475,6 +42639,7 @@ pub fn vreinterpret_u32_f16(a: float16x4_t) -> uint32x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { unsafe { transmute(a) } } @@ -42490,6 +42655,7 @@ pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { transmute(a) } @@ -42506,6 +42672,7 @@ pub fn vreinterpret_u64_f16(a: float16x4_t) -> uint64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { unsafe { transmute(a) } } @@ -42521,6 +42688,7 @@ pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42540,6 +42708,7 @@ pub fn vreinterpret_p8_f16(a: float16x4_t) -> poly8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { unsafe { transmute(a) } } @@ -42555,6 +42724,7 @@ pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -42574,6 +42744,7 @@ pub fn vreinterpret_p16_f16(a: float16x4_t) -> poly16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { unsafe { transmute(a) } } @@ -42589,6 +42760,7 @@ pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42608,6 +42780,7 @@ pub fn vreinterpretq_f32_f16(a: float16x8_t) -> float32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { unsafe { transmute(a) } } @@ -42623,6 +42796,7 @@ pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42646,6 +42820,7 @@ pub fn vreinterpretq_s8_f16(a: float16x8_t) -> int8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { unsafe { transmute(a) } } @@ -42661,6 +42836,7 @@ pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42680,6 +42856,7 @@ pub fn vreinterpretq_s16_f16(a: float16x8_t) -> int16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { unsafe { transmute(a) } } @@ -42695,6 +42872,7 @@ pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42714,6 +42892,7 @@ pub fn vreinterpretq_s32_f16(a: float16x8_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { unsafe { transmute(a) } } @@ -42729,6 +42908,7 @@ pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42748,6 +42928,7 @@ pub fn vreinterpretq_s64_f16(a: float16x8_t) -> int64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { unsafe { transmute(a) } } @@ -42763,6 +42944,7 @@ pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42786,6 +42968,7 @@ pub fn vreinterpretq_u8_f16(a: float16x8_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { unsafe { transmute(a) } } @@ -42801,6 +42984,7 @@ pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42820,6 +43004,7 @@ pub fn vreinterpretq_u16_f16(a: float16x8_t) -> uint16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { unsafe { transmute(a) } } @@ -42835,6 +43020,7 @@ pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42854,6 +43040,7 @@ pub fn vreinterpretq_u32_f16(a: float16x8_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { unsafe { transmute(a) } } @@ -42869,6 +43056,7 @@ pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42888,6 +43076,7 @@ pub fn vreinterpretq_u64_f16(a: float16x8_t) -> uint64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { unsafe { transmute(a) } } @@ -42903,6 +43092,7 @@ pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42926,6 +43116,7 @@ pub fn vreinterpretq_p8_f16(a: float16x8_t) -> poly8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { unsafe { transmute(a) } } @@ -42941,6 +43132,7 @@ pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -42960,6 +43152,7 @@ pub fn vreinterpretq_p16_f16(a: float16x8_t) -> poly16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { unsafe { transmute(a) } } @@ -42975,6 +43168,7 @@ pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { let a: float32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -42994,6 +43188,7 @@ pub fn vreinterpret_f16_f32(a: float32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43009,6 +43204,7 @@ pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { let a: float32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43028,6 +43224,7 @@ pub fn vreinterpretq_f16_f32(a: float32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43043,6 +43240,7 @@ pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { let a: int8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43062,6 +43260,7 @@ pub fn vreinterpret_f16_s8(a: int8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43077,6 +43276,7 @@ pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { let a: int8x16_t = unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; @@ -43097,6 +43297,7 @@ pub fn vreinterpretq_f16_s8(a: int8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43112,6 +43313,7 @@ pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { let a: int16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43131,6 +43333,7 @@ pub fn vreinterpret_f16_s16(a: int16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43146,6 +43349,7 @@ pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { let a: int16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43165,6 +43369,7 @@ pub fn vreinterpretq_f16_s16(a: int16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43180,6 +43385,7 @@ pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { let a: int32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -43199,6 +43405,7 @@ pub fn vreinterpret_f16_s32(a: int32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43214,6 +43421,7 @@ pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { let a: int32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43233,6 +43441,7 @@ pub fn vreinterpretq_f16_s32(a: int32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43248,6 +43457,7 @@ pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { unsafe { let ret_val: float16x4_t = transmute(a); @@ -43266,6 +43476,7 @@ pub fn vreinterpret_f16_s64(a: int64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43281,6 +43492,7 @@ pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { let a: int64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -43300,6 +43512,7 @@ pub fn vreinterpretq_f16_s64(a: int64x2_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43315,6 +43528,7 @@ pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { let a: uint8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43334,6 +43548,7 @@ pub fn vreinterpret_f16_u8(a: uint8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43349,6 +43564,7 @@ pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { let a: uint8x16_t = unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; @@ -43369,6 +43585,7 @@ pub fn vreinterpretq_f16_u8(a: uint8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43384,6 +43601,7 @@ pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { let a: uint16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43403,6 +43621,7 @@ pub fn vreinterpret_f16_u16(a: uint16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43418,6 +43637,7 @@ pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { let a: uint16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43437,6 +43657,7 @@ pub fn vreinterpretq_f16_u16(a: uint16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43452,6 +43673,7 @@ pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { let a: uint32x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -43471,6 +43693,7 @@ pub fn vreinterpret_f16_u32(a: uint32x2_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43486,6 +43709,7 @@ pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { let a: uint32x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43505,6 +43729,7 @@ pub fn vreinterpretq_f16_u32(a: uint32x4_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43520,6 +43745,7 @@ pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { unsafe { let ret_val: float16x4_t = transmute(a); @@ -43538,6 +43764,7 @@ pub fn vreinterpret_f16_u64(a: uint64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43553,6 +43780,7 @@ pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { let a: uint64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -43572,6 +43800,7 @@ pub fn vreinterpretq_f16_u64(a: uint64x2_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43587,6 +43816,7 @@ pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { let a: poly8x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43606,6 +43836,7 @@ pub fn vreinterpret_f16_p8(a: poly8x8_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43621,6 +43852,7 @@ pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { let a: poly8x16_t = unsafe { simd_shuffle!(a, a, [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) }; @@ -43641,6 +43873,7 @@ pub fn vreinterpretq_f16_p8(a: poly8x16_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43656,6 +43889,7 @@ pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { let a: poly16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { @@ -43675,6 +43909,7 @@ pub fn vreinterpret_f16_p16(a: poly16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43690,6 +43925,7 @@ pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { let a: poly16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43709,6 +43945,7 @@ pub fn vreinterpretq_f16_p16(a: poly16x8_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { unsafe { transmute(a) } } @@ -43724,6 +43961,7 @@ pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { unsafe { let ret_val: float16x8_t = transmute(a); @@ -43742,6 +43980,7 @@ pub fn vreinterpretq_f16_p128(a: p128) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { unsafe { transmute(a) } } @@ -43757,6 +43996,7 @@ pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { let a: float16x4_t = unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) }; unsafe { transmute(a) } @@ -43773,6 +44013,7 @@ pub fn vreinterpret_p64_f16(a: float16x4_t) -> poly64x1_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { unsafe { transmute(a) } } @@ -43788,6 +44029,7 @@ pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { transmute(a) } @@ -43804,6 +44046,7 @@ pub fn vreinterpretq_p128_f16(a: float16x8_t) -> p128 { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { unsafe { transmute(a) } } @@ -43819,6 +44062,7 @@ pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { let a: float16x8_t = unsafe { simd_shuffle!(a, a, [7, 6, 5, 4, 3, 2, 1, 0]) }; unsafe { @@ -43838,6 +44082,7 @@ pub fn vreinterpretq_p64_f16(a: float16x8_t) -> poly64x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { unsafe { transmute(a) } } @@ -43853,6 +44098,7 @@ pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { unsafe { let ret_val: float16x4_t = transmute(a); @@ -43871,6 +44117,7 @@ pub fn vreinterpret_f16_p64(a: poly64x1_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { unsafe { transmute(a) } } @@ -43886,6 +44133,7 @@ pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vreinterpretq_f16_p64(a: poly64x2_t) -> float16x8_t { let a: poly64x2_t = unsafe { simd_shuffle!(a, a, [1, 0]) }; unsafe { @@ -57882,6 +58130,7 @@ pub fn vrev64q_u8(a: uint8x16_t) -> uint8x16_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrev64_f16(a: float16x4_t) -> float16x4_t { unsafe { simd_shuffle!(a, a, [3, 2, 1, 0]) } } @@ -57896,6 +58145,7 @@ pub fn vrev64_f16(a: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrev64q_f16(a: float16x8_t) -> float16x8_t { unsafe { simd_shuffle!(a, a, [3, 2, 1, 0, 7, 6, 5, 4]) } } @@ -58258,6 +58508,7 @@ pub fn vrhaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrndn_f16(a: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -58280,6 +58531,7 @@ pub fn vrndn_f16(a: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrndnq_f16(a: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr( @@ -59366,6 +59618,7 @@ pub fn vrshrn_n_u64(a: uint64x2_t) -> uint32x2_t { assert_instr(frsqrte) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrte_f16(a: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v4f16")] @@ -59388,6 +59641,7 @@ pub fn vrsqrte_f16(a: float16x4_t) -> float16x4_t { assert_instr(frsqrte) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrteq_f16(a: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrte.v8f16")] @@ -59526,6 +59780,7 @@ pub fn vrsqrteq_u32(a: uint32x4_t) -> uint32x4_t { assert_instr(frsqrts) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrts_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrts.v4f16")] @@ -59548,6 +59803,7 @@ pub fn vrsqrts_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { assert_instr(frsqrts) )] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vrsqrtsq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vrsqrts.v8f16")] @@ -60231,6 +60487,7 @@ pub fn vrsubhn_u64(a: uint64x2_t, b: uint64x2_t) -> uint32x2_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vset_lane_f16(a: f16, b: float16x4_t) -> float16x4_t { static_assert_uimm_bits!(LANE, 2); unsafe { simd_insert!(b, LANE as u32, a) } @@ -60247,6 +60504,7 @@ pub fn vset_lane_f16(a: f16, b: float16x4_t) -> float16x4_t { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vsetq_lane_f16(a: f16, b: float16x8_t) -> float16x8_t { static_assert_uimm_bits!(LANE, 3); unsafe { simd_insert!(b, LANE as u32, a) } @@ -63699,6 +63957,7 @@ pub fn vsriq_n_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8_t { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vst1.16"))] pub unsafe fn vst1_f16(ptr: *mut f16, a: float16x4_t) { vst1_v4f16( @@ -63716,6 +63975,7 @@ pub unsafe fn vst1_f16(ptr: *mut f16, a: float16x4_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vst1.16"))] pub unsafe fn vst1q_f16(ptr: *mut f16, a: float16x8_t) { vst1q_v8f16( @@ -63734,6 +63994,7 @@ pub unsafe fn vst1q_f16(ptr: *mut f16, a: float16x8_t) { #[cfg_attr(test, assert_instr(vst1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16_x2(a: *mut f16, b: float16x4x2_t) { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0.v4f16")] @@ -63751,6 +64012,7 @@ pub unsafe fn vst1_f16_x2(a: *mut f16, b: float16x4x2_t) { #[cfg_attr(test, assert_instr(vst1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16_x2(a: *mut f16, b: float16x8x2_t) { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x2.p0.v8f16")] @@ -63767,6 +64029,7 @@ pub unsafe fn vst1q_f16_x2(a: *mut f16, b: float16x8x2_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16_x2(a: *mut f16, b: float16x4x2_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -63786,6 +64049,7 @@ pub unsafe fn vst1_f16_x2(a: *mut f16, b: float16x4x2_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16_x2(a: *mut f16, b: float16x8x2_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -63806,6 +64070,7 @@ pub unsafe fn vst1q_f16_x2(a: *mut f16, b: float16x8x2_t) { #[cfg_attr(test, assert_instr(vst1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16_x3(a: *mut f16, b: float16x4x3_t) { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0.v4f16")] @@ -63823,6 +64088,7 @@ pub unsafe fn vst1_f16_x3(a: *mut f16, b: float16x4x3_t) { #[cfg_attr(test, assert_instr(vst1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16_x3(a: *mut f16, b: float16x8x3_t) { unsafe extern "unadjusted" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vst1x3.p0.v8f16")] @@ -63839,6 +64105,7 @@ pub unsafe fn vst1q_f16_x3(a: *mut f16, b: float16x8x3_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16_x3(a: *mut f16, b: float16x4x3_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -63858,6 +64125,7 @@ pub unsafe fn vst1_f16_x3(a: *mut f16, b: float16x4x3_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16_x3(a: *mut f16, b: float16x8x3_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -63877,6 +64145,7 @@ pub unsafe fn vst1q_f16_x3(a: *mut f16, b: float16x8x3_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst1))] pub unsafe fn vst1_f16_x4(a: *mut f16, b: float16x4x4_t) { unsafe extern "unadjusted" { @@ -63900,6 +64169,7 @@ pub unsafe fn vst1_f16_x4(a: *mut f16, b: float16x4x4_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst1))] pub unsafe fn vst1q_f16_x4(a: *mut f16, b: float16x8x4_t) { unsafe extern "unadjusted" { @@ -63923,6 +64193,7 @@ pub unsafe fn vst1q_f16_x4(a: *mut f16, b: float16x8x4_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_f16_x4(a: *mut f16, b: float16x4x4_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -63948,6 +64219,7 @@ pub unsafe fn vst1_f16_x4(a: *mut f16, b: float16x4x4_t) { #[cfg_attr(test, assert_instr(st1))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_f16_x4(a: *mut f16, b: float16x8x4_t) { unsafe extern "unadjusted" { #[cfg_attr( @@ -64556,6 +64828,7 @@ pub unsafe fn vst1q_f32_x4(a: *mut f32, b: float32x4x4_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1_lane_f16(a: *mut f16, b: float16x4_t) { static_assert_uimm_bits!(LANE, 2); *a = simd_extract!(b, LANE as u32); @@ -64574,6 +64847,7 @@ pub unsafe fn vst1_lane_f16(a: *mut f16, b: float16x4_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst1q_lane_f16(a: *mut f16, b: float16x8_t) { static_assert_uimm_bits!(LANE, 3); *a = simd_extract!(b, LANE as u32); @@ -67138,6 +67412,7 @@ unsafe fn vst1q_v8i16(addr: *const i8, val: int16x8_t, align: i32) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vst1.16"))] unsafe fn vst1_v4f16(addr: *const i8, val: float16x4_t, align: i32) { unsafe extern "unadjusted" { @@ -67155,6 +67430,7 @@ unsafe fn vst1_v4f16(addr: *const i8, val: float16x4_t, align: i32) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(all(test, target_arch = "arm"), assert_instr("vst1.16"))] unsafe fn vst1q_v8f16(addr: *const i8, val: float16x8_t, align: i32) { unsafe extern "unadjusted" { @@ -67196,6 +67472,7 @@ pub unsafe fn vst1q_lane_p64(a: *mut p64, b: poly64x2_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st2))] pub unsafe fn vst2_f16(a: *mut f16, b: float16x4x2_t) { unsafe extern "unadjusted" { @@ -67215,6 +67492,7 @@ pub unsafe fn vst2_f16(a: *mut f16, b: float16x4x2_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st2))] pub unsafe fn vst2q_f16(a: *mut f16, b: float16x8x2_t) { unsafe extern "unadjusted" { @@ -67235,6 +67513,7 @@ pub unsafe fn vst2q_f16(a: *mut f16, b: float16x8x2_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst2))] pub unsafe fn vst2_f16(a: *mut f16, b: float16x4x2_t) { unsafe extern "unadjusted" { @@ -67252,6 +67531,7 @@ pub unsafe fn vst2_f16(a: *mut f16, b: float16x4x2_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst2))] pub unsafe fn vst2q_f16(a: *mut f16, b: float16x8x2_t) { unsafe extern "unadjusted" { @@ -67550,6 +67830,7 @@ pub unsafe fn vst2q_s32(a: *mut i32, b: int32x4x2_t) { #[cfg_attr(test, assert_instr(st2, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst2_lane_f16(a: *mut f16, b: float16x4x2_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -67571,6 +67852,7 @@ pub unsafe fn vst2_lane_f16(a: *mut f16, b: float16x4x2_t) { #[cfg_attr(test, assert_instr(st2, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst2q_lane_f16(a: *mut f16, b: float16x8x2_t) { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -67593,6 +67875,7 @@ pub unsafe fn vst2q_lane_f16(a: *mut f16, b: float16x8x2_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst2_lane_f16(a: *mut f16, b: float16x4x2_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -67612,6 +67895,7 @@ pub unsafe fn vst2_lane_f16(a: *mut f16, b: float16x4x2_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst2q_lane_f16(a: *mut f16, b: float16x8x2_t) { static_assert_uimm_bits!(LANE, 1); unsafe extern "unadjusted" { @@ -68413,6 +68697,7 @@ pub unsafe fn vst2q_p16(a: *mut p16, b: poly16x8x2_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst3))] pub unsafe fn vst3_f16(a: *mut f16, b: float16x4x3_t) { unsafe extern "unadjusted" { @@ -68430,6 +68715,7 @@ pub unsafe fn vst3_f16(a: *mut f16, b: float16x4x3_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst3))] pub unsafe fn vst3q_f16(a: *mut f16, b: float16x8x3_t) { unsafe extern "unadjusted" { @@ -68446,6 +68732,7 @@ pub unsafe fn vst3q_f16(a: *mut f16, b: float16x8x3_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st3))] pub unsafe fn vst3_f16(a: *mut f16, b: float16x4x3_t) { unsafe extern "unadjusted" { @@ -68465,6 +68752,7 @@ pub unsafe fn vst3_f16(a: *mut f16, b: float16x4x3_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st3))] pub unsafe fn vst3q_f16(a: *mut f16, b: float16x8x3_t) { unsafe extern "unadjusted" { @@ -68767,6 +69055,7 @@ pub unsafe fn vst3q_s32(a: *mut i32, b: int32x4x3_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst3_lane_f16(a: *mut f16, b: float16x4x3_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -68793,6 +69082,7 @@ pub unsafe fn vst3_lane_f16(a: *mut f16, b: float16x4x3_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst3q_lane_f16(a: *mut f16, b: float16x8x3_t) { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -68818,6 +69108,7 @@ pub unsafe fn vst3q_lane_f16(a: *mut f16, b: float16x8x3_t) { #[cfg_attr(test, assert_instr(st3, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst3_lane_f16(a: *mut f16, b: float16x4x3_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -68839,6 +69130,7 @@ pub unsafe fn vst3_lane_f16(a: *mut f16, b: float16x4x3_t) { #[cfg_attr(test, assert_instr(st3, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst3q_lane_f16(a: *mut f16, b: float16x8x3_t) { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -69685,6 +69977,7 @@ pub unsafe fn vst3q_p16(a: *mut p16, b: poly16x8x3_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst4))] pub unsafe fn vst4_f16(a: *mut f16, b: float16x4x4_t) { unsafe extern "unadjusted" { @@ -69709,6 +70002,7 @@ pub unsafe fn vst4_f16(a: *mut f16, b: float16x4x4_t) { #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(vst4))] pub unsafe fn vst4q_f16(a: *mut f16, b: float16x8x4_t) { unsafe extern "unadjusted" { @@ -69732,6 +70026,7 @@ pub unsafe fn vst4q_f16(a: *mut f16, b: float16x8x4_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st4))] pub unsafe fn vst4_f16(a: *mut f16, b: float16x4x4_t) { unsafe extern "unadjusted" { @@ -69751,6 +70046,7 @@ pub unsafe fn vst4_f16(a: *mut f16, b: float16x4x4_t) { #[cfg(not(target_arch = "arm"))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] #[cfg_attr(test, assert_instr(st4))] pub unsafe fn vst4q_f16(a: *mut f16, b: float16x8x4_t) { unsafe extern "unadjusted" { @@ -70102,6 +70398,7 @@ pub unsafe fn vst4q_s32(a: *mut i32, b: int32x4x4_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst4_lane_f16(a: *mut f16, b: float16x4x4_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -70129,6 +70426,7 @@ pub unsafe fn vst4_lane_f16(a: *mut f16, b: float16x4x4_t) { #[rustc_legacy_const_generics(2)] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst4q_lane_f16(a: *mut f16, b: float16x8x4_t) { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -70155,6 +70453,7 @@ pub unsafe fn vst4q_lane_f16(a: *mut f16, b: float16x8x4_t) { #[cfg_attr(test, assert_instr(st4, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst4_lane_f16(a: *mut f16, b: float16x4x4_t) { static_assert_uimm_bits!(LANE, 2); unsafe extern "unadjusted" { @@ -70183,6 +70482,7 @@ pub unsafe fn vst4_lane_f16(a: *mut f16, b: float16x4x4_t) { #[cfg_attr(test, assert_instr(st4, LANE = 0))] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub unsafe fn vst4q_lane_f16(a: *mut f16, b: float16x8x4_t) { static_assert_uimm_bits!(LANE, 3); unsafe extern "unadjusted" { @@ -71124,6 +71424,7 @@ pub unsafe fn vstrq_p128(a: *mut p128, b: p128) { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vsub_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { unsafe { simd_sub(a, b) } } @@ -71138,6 +71439,7 @@ pub fn vsub_f16(a: float16x4_t, b: float16x4_t) -> float16x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vsubq_f16(a: float16x8_t, b: float16x8_t) -> float16x8_t { unsafe { simd_sub(a, b) } } @@ -73002,6 +73304,7 @@ pub fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vtrn_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { unsafe { let a1: float16x4_t = simd_shuffle!(a, b, [0, 4, 2, 6]); @@ -73024,6 +73327,7 @@ pub fn vtrn_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vtrnq_f16(a: float16x8_t, b: float16x8_t) -> float16x8x2_t { unsafe { let a1: float16x8_t = simd_shuffle!(a, b, [0, 8, 2, 10, 4, 12, 6, 14]); @@ -74134,6 +74438,7 @@ pub fn vusmmlaq_s32(a: int32x4_t, b: uint8x16_t, c: int8x16_t) -> int32x4_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vuzp_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { unsafe { let a0: float16x4_t = simd_shuffle!(a, b, [0, 2, 4, 6]); @@ -74156,6 +74461,7 @@ pub fn vuzp_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vuzpq_f16(a: float16x8_t, b: float16x8_t) -> float16x8x2_t { unsafe { let a0: float16x8_t = simd_shuffle!(a, b, [0, 2, 4, 6, 8, 10, 12, 14]); @@ -74724,6 +75030,7 @@ pub fn vuzpq_p16(a: poly16x8_t, b: poly16x8_t) -> poly16x8x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vzip_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { unsafe { let a0: float16x4_t = simd_shuffle!(a, b, [0, 4, 1, 5]); @@ -74746,6 +75053,7 @@ pub fn vzip_f16(a: float16x4_t, b: float16x4_t) -> float16x4x2_t { )] #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] +#[cfg(not(target_arch = "arm64ec"))] pub fn vzipq_f16(a: float16x8_t, b: float16x8_t) -> float16x8x2_t { unsafe { let a0: float16x8_t = simd_shuffle!(a, b, [0, 8, 1, 9, 2, 10, 3, 11]); diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs index 60c9daef68c42..fbd1967c544ad 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs @@ -5503,8 +5503,12 @@ mod tests { test_vcombine!(test_vcombine_s16 => vcombine_s16([3_i16, -4, 5, -6], [13_i16, -14, 15, -16])); test_vcombine!(test_vcombine_u16 => vcombine_u16([3_u16, 4, 5, 6], [13_u16, 14, 15, 16])); test_vcombine!(test_vcombine_p16 => vcombine_p16([3_u16, 4, 5, 6], [13_u16, 14, 15, 16])); - test_vcombine!(test_vcombine_f16 => vcombine_f16([3_f16, 4., 5., 6.], - [13_f16, 14., 15., 16.])); + #[cfg(not(target_arch = "arm64ec"))] + mod fp16 { + use super::*; + test_vcombine!(test_vcombine_f16 => vcombine_f16([3_f16, 4., 5., 6.], + [13_f16, 14., 15., 16.])); + } test_vcombine!(test_vcombine_s32 => vcombine_s32([3_i32, -4], [13_i32, -14])); test_vcombine!(test_vcombine_u32 => vcombine_u32([3_u32, 4], [13_u32, 14])); diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml index a31613e6b1aef..a1a837bc61064 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml @@ -17,6 +17,10 @@ neon-stable: &neon-stable target-not-arm: &target-not-arm FnCall: [cfg, [{ FnCall: [not, ['target_arch = "arm"']]}]] +# #[cfg(not(target_arch = "arm64ec"))] +target-not-arm64ec: &target-not-arm64ec + FnCall: [cfg, [{ FnCall: [not, ['target_arch = "arm64ec"']]}]] + # #[cfg_attr(all(test, not(target_env = "msvc"))] msvc-disabled: &msvc-disabled FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]] @@ -169,6 +173,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fabd] safety: safe types: @@ -368,6 +373,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -559,6 +565,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -642,6 +649,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -777,6 +785,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -859,6 +868,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -931,6 +941,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [facgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16", i32] @@ -988,6 +999,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [facge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16", i32] @@ -1036,6 +1048,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [facgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -1078,6 +1091,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [facge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -1175,6 +1189,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1202,6 +1217,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1219,6 +1235,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1246,6 +1263,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1264,6 +1282,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1386,6 +1405,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [scvtf]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["s16", "f16", "h_f16_s16", i16] @@ -1402,6 +1422,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtzs]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "s16", "h", i16, 'a as i16'] @@ -1418,6 +1439,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtzu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", "h", 'a as u16'] @@ -1435,6 +1457,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [ucvtf]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["u16", "f16", "h_f16_u16"] @@ -1486,6 +1509,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtn2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x8_t, float16x4_t, float32x4_t] @@ -1503,6 +1527,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtl2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float32x4_t, float16x8_t] @@ -1650,6 +1675,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1675,6 +1701,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1693,6 +1720,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1783,6 +1811,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtas]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, int16x4_t] @@ -1821,6 +1850,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtau]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u32", 'h_u32_f16'] @@ -1842,6 +1872,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtas]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i32", 'h_s32_f16'] @@ -1863,6 +1894,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtas]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i16", 'h_s16_f16', 's32'] @@ -1877,6 +1909,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtau]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", 'h_u16_f16', 'u32'] @@ -1948,6 +1981,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtns]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, int16x4_t] @@ -1968,6 +2002,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtnu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -1987,6 +2022,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtns]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i32", 'h'] @@ -2007,6 +2043,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtns]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i16", 'h', 'i32'] @@ -2022,6 +2059,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtnu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u32", 'h'] @@ -2042,6 +2080,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtnu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", 'h', 'u32'] @@ -2077,6 +2116,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtms]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, int16x4_t] @@ -2097,6 +2137,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtmu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -2291,6 +2332,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtps]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, int16x4_t] @@ -2311,6 +2353,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtpu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -2331,6 +2374,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtps]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i32", 'h'] @@ -2351,6 +2395,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtps]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i16", 'h', 'i32'] @@ -2365,6 +2410,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtpu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u32", 'h'] @@ -2385,6 +2431,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtpu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", 'h', 'u32'] @@ -2531,6 +2578,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -2549,6 +2597,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -2770,6 +2819,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fneg] safety: safe types: @@ -2986,6 +3036,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintx] safety: safe types: @@ -3002,6 +3053,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintx] safety: safe types: @@ -3033,6 +3085,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frinta] safety: safe types: @@ -3049,6 +3102,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frinta] safety: safe types: @@ -3096,6 +3150,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintn] safety: safe types: @@ -3130,6 +3185,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintm] safety: safe types: @@ -3146,6 +3202,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintm] safety: safe types: @@ -3178,6 +3235,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintp] safety: safe types: @@ -3193,6 +3251,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintp] safety: safe types: @@ -3222,6 +3281,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintz] safety: safe types: @@ -3238,6 +3298,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frintz] safety: safe types: @@ -3273,6 +3334,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [frinti] safety: safe types: @@ -3293,6 +3355,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec # TODO: double check me assert_instr: [frinti] safety: safe @@ -5205,6 +5268,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmulx] safety: safe types: @@ -5243,6 +5307,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmulx] safety: safe types: @@ -5385,6 +5450,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -5438,6 +5504,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -5462,6 +5529,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fmulx]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, "f16"] @@ -5546,6 +5614,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmla] safety: safe types: @@ -5582,6 +5651,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fdiv] safety: safe types: @@ -5597,6 +5667,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -5637,6 +5708,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -5928,6 +6000,7 @@ intrinsics: - *neon-fp16 - *enable-fcma - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcadd] safety: safe types: @@ -5948,6 +6021,7 @@ intrinsics: - *neon-fp16 - *enable-fcma - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcadd] safety: safe types: @@ -5988,6 +6062,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "neon,fcma"']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcmla] safety: safe types: @@ -6028,6 +6103,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "neon,fcma"']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcmla] safety: safe types: @@ -6069,6 +6145,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "neon,fcma"']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcmla] safety: safe types: @@ -6113,6 +6190,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6158,6 +6236,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6203,6 +6282,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6245,6 +6325,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "neon,fcma"']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fcmla] safety: safe types: @@ -6290,6 +6371,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6337,6 +6419,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6384,6 +6467,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6430,6 +6514,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6473,6 +6558,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6568,6 +6654,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmax] safety: safe types: @@ -6601,6 +6688,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmaxnm] safety: safe types: @@ -6616,6 +6704,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fminnm] safety: safe types: @@ -6657,6 +6746,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmaxnmv] safety: safe types: @@ -6673,6 +6763,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fminnmv] safety: safe types: @@ -6689,6 +6780,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmaxv] safety: safe types: @@ -6708,6 +6800,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fminv] safety: safe types: @@ -6762,6 +6855,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmin] safety: safe types: @@ -6875,6 +6969,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [faddp] safety: safe types: @@ -6894,6 +6989,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmaxp] safety: safe types: @@ -6914,6 +7010,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmaxnmp] safety: safe types: @@ -6934,6 +7031,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fminp] safety: safe types: @@ -6954,6 +7052,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fminnmp] safety: safe types: @@ -8379,6 +8478,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fsqrt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -8393,6 +8493,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fsqrt] safety: safe types: @@ -8445,6 +8546,7 @@ intrinsics: - *neon-fp16 - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [frsqrts]]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [h_f16, "f16"] @@ -8501,6 +8603,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [frecpe]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [h_f16, "f16"] @@ -8557,6 +8660,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [frecps]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [h_f16, "f16"] @@ -8595,6 +8699,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [frecpx]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [h_f16, "f16"] @@ -8687,6 +8792,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -9586,6 +9692,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [trn1]]}]] safety: safe types: @@ -9647,6 +9754,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [trn2]]}]] safety: safe types: @@ -9715,6 +9823,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [zip2]]}]] safety: safe types: @@ -9765,6 +9874,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [zip1]]}]] safety: safe types: @@ -9826,6 +9936,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [uzp1]]}]] safety: safe types: @@ -9891,6 +10002,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [{FnCall: [all, [test, {FnCall: [not, ['target_env = "msvc"']]}]]}, {FnCall: [assert_instr, [uzp2]]}]] safety: safe types: @@ -10180,6 +10292,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -10206,6 +10319,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -10230,6 +10344,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fmsub]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "h_f16"] @@ -10342,6 +10457,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fmadd]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "h_f16"] @@ -10358,6 +10474,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -10377,6 +10494,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -10541,6 +10659,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmeq]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t, 'f16x4', 'f16x4::new(0.0, 0.0, 0.0, 0.0)'] @@ -10576,6 +10695,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", "h_f16"] @@ -10700,6 +10820,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -10842,6 +10963,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -10972,6 +11094,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16", "u16"] @@ -11126,6 +11249,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -11146,6 +11270,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -11183,6 +11308,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -11328,6 +11454,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcmp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", 'h_f16'] @@ -11399,6 +11526,7 @@ intrinsics: attr: - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmls] safety: safe types: @@ -11651,6 +11779,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [frsqrte]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["h_f16", "f16"] @@ -11734,6 +11863,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtau]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -11772,6 +11902,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtms]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i32", 'h'] @@ -11792,6 +11923,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtms]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "i16", 'h', 'i32'] @@ -11807,6 +11939,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtmu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u32", 'h'] @@ -11827,6 +11960,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [fcvtmu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["f16", "u16", 'h', 'u32'] @@ -12857,6 +12991,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "{type[2]}"']] - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [ldr]]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -12924,6 +13059,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [str]]}]] - FnCall: [allow, ['clippy::cast_ptr_alignment']] - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -13637,6 +13773,7 @@ intrinsics: - *neon-fp16 - *enable-fhm - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmlal2] safety: safe types: @@ -13660,6 +13797,7 @@ intrinsics: - *enable-fhm - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -13684,6 +13822,7 @@ intrinsics: - *neon-fp16 - *enable-fhm - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmlal] safety: safe types: @@ -13707,6 +13846,7 @@ intrinsics: - *enable-fhm - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -13731,6 +13871,7 @@ intrinsics: - *neon-fp16 - *enable-fhm - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmlsl2] safety: safe types: @@ -13753,6 +13894,7 @@ intrinsics: - *enable-fhm - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -13777,6 +13919,7 @@ intrinsics: - *neon-fp16 - *enable-fhm - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [fmlsl] safety: safe types: @@ -13799,6 +13942,7 @@ intrinsics: - *enable-fhm - FnCall: [rustc_legacy_const_generics, ['3']] - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml index c96c6e2a0c0b5..f16a257399bc8 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml @@ -37,6 +37,10 @@ target-is-arm: &target-is-arm target-not-arm: &target-not-arm FnCall: [cfg, [{ FnCall: [not, ['target_arch = "arm"']]}]] +# #[cfg(not(target_arch = "arm64ec"))] +target-not-arm64ec: &target-not-arm64ec + FnCall: [cfg, [{ FnCall: [not, ['target_arch = "arm64ec"']]}]] + not-arm: ¬-arm FnCall: [not, ['target_arch = "arm"']] @@ -278,6 +282,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fabd]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -396,6 +401,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmeq]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -457,6 +463,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fabs]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -474,6 +481,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fabs]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ['h_f16', 'f16'] @@ -555,6 +563,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -573,6 +582,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t, f16x4, 'f16x4::new(0.0, 0.0, 0.0, 0.0)'] @@ -651,6 +661,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -668,6 +679,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmle]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t, f16x4, 'f16x4::new(0.0, 0.0, 0.0, 0.0)'] @@ -849,6 +861,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [facgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -895,6 +908,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [facge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -935,6 +949,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [facgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -970,6 +985,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [facge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -1004,6 +1020,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [scvtf]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [int16x4_t, float16x4_t] @@ -1038,6 +1055,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ucvtf]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [uint16x4_t, float16x4_t] @@ -1109,6 +1127,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1140,6 +1159,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1171,6 +1191,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1229,6 +1250,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1482,6 +1504,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1501,6 +1524,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [dup]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, f16, 'float16x4', '_n_'] @@ -1519,6 +1543,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['1']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1740,6 +1765,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -1758,6 +1784,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const N: i32'] safety: safe types: @@ -2207,6 +2234,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fneg]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, 'f16'] @@ -2478,6 +2506,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [frintn]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -2743,6 +2772,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -2773,6 +2803,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -2793,6 +2824,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld1r]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3385,6 +3417,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3413,6 +3446,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3440,6 +3474,7 @@ intrinsics: - *neon-fp16 - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld2]]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3469,6 +3504,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld2r]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3498,6 +3534,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -3540,6 +3577,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -3580,6 +3618,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld3]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3608,6 +3647,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld3]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3635,6 +3675,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld3]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3664,6 +3705,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld3r]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -3693,6 +3735,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -3737,6 +3780,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -4718,6 +4762,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec types: - ['*mut f16', float16x4_t, '2'] - ['*mut f16', float16x8_t, '3'] @@ -4955,6 +5000,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [vst1] types: - [f16, float16x4x4_t, float16x4_t] @@ -5098,6 +5144,7 @@ intrinsics: - *target-not-arm - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [st2] safety: unsafe: [neon] @@ -5188,6 +5235,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st2, 'LANE = 0']]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -5279,6 +5327,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [vst2] safety: unsafe: [neon] @@ -5345,6 +5394,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -5555,6 +5605,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [vst3] safety: unsafe: [neon] @@ -5623,6 +5674,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -5683,6 +5735,7 @@ intrinsics: - *target-not-arm - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [st3] safety: unsafe: [neon] @@ -5747,6 +5800,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st3, 'LANE = 0']]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -5960,6 +6014,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [vst4] safety: unsafe: [neon] @@ -6029,6 +6084,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -6091,6 +6147,7 @@ intrinsics: - *target-not-arm - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [st4] safety: unsafe: [neon] @@ -6157,6 +6214,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st4, 'LANE = 0']]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: unsafe: [neon] @@ -6317,6 +6375,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmul]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [f16, float16x4_t] @@ -6366,6 +6425,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ["const LANE: i32"] safety: safe types: @@ -6569,6 +6629,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmla]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -6678,6 +6739,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fsub]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ['f16', float16x4_t] @@ -6696,6 +6758,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fadd]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -6716,6 +6779,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fadd]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ['h_f16', 'f16'] @@ -7194,6 +7258,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmax]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -7236,6 +7301,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmaxnm]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -7254,6 +7320,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fminnm]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -7340,6 +7407,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmin]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -7404,6 +7472,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [faddp]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -8247,6 +8316,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vrsqrts]]}]] - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [frsqrts]]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -8295,6 +8365,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [frecpe]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -8343,6 +8414,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [frecps]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -8675,6 +8747,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [nop]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: # non-q @@ -8737,6 +8810,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [nop]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [poly64x1_t, float16x4_t] @@ -8759,6 +8833,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [rev64]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, "[3, 2, 1, 0]"] @@ -9074,6 +9149,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [nop]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ["u64", float16x4_t] @@ -9147,6 +9223,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ['2']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -9578,6 +9655,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [trn2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, float16x4x2_t, '[0, 4, 2, 6]', '[1, 5, 3, 7]'] @@ -9733,6 +9811,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [zip2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, float16x4x2_t, '[0, 4, 1, 5]', '[2, 6, 3, 7]'] @@ -9803,6 +9882,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [uzp2]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, float16x4x2_t, '[0, 2, 4, 6]', '[1, 3, 5, 7]'] @@ -10050,6 +10130,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [vst1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -10077,6 +10158,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -10103,6 +10185,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [vst1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -10179,6 +10262,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -10233,6 +10317,7 @@ intrinsics: - FnCall: [cfg_attr, [test, {FnCall: [assert_instr, [st1]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -10376,6 +10461,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -10394,6 +10480,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmge]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t, f16x4, 'f16x4::new(0.0, 0.0, 0.0, 0.0)'] @@ -10633,6 +10720,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcvtzu]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -10652,6 +10740,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcvtn]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float32x4_t, float16x4_t] @@ -10668,6 +10757,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcvtl]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, float32x4_t] @@ -11029,6 +11119,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmul]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, "f16"] @@ -11141,6 +11232,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmgt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t] @@ -11159,6 +11251,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcmlt]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, uint16x4_t, f16x4, 'f16x4::new(0.0, 0.0, 0.0, 0.0)'] @@ -11271,6 +11364,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fmls]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -11386,6 +11480,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vrsqrte]]}]] - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [frsqrte]]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - float16x4_t @@ -11499,6 +11594,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [fcvtzs]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, int16x4_t] @@ -11748,6 +11844,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [nop]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -11834,6 +11931,7 @@ intrinsics: - FnCall: [target_feature, ['enable = "{type[3]}"']] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, ['{type[2]}']]}]] types: - ['*const f16', float16x4_t, '"vld1.16"', 'neon,v7', 'crate::mem::align_of::() as i32', '_v4f16'] @@ -12117,6 +12215,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld4]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -12145,6 +12244,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld4]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -12172,6 +12272,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, [vld4]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -12201,6 +12302,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [ld4r]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: unsafe: [neon] types: @@ -12230,6 +12332,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -12276,6 +12379,7 @@ intrinsics: - FnCall: [rustc_legacy_const_generics, ["2"]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec static_defs: - "const LANE: i32" safety: @@ -13674,6 +13778,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, ['"vst1.{type[4]}"']]}]] types: - ['_v4f16', '* const i8', float16x4_t, i32, '16'] @@ -13738,6 +13843,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec - FnCall: [cfg_attr, [*test-is-arm, {FnCall: [assert_instr, ['"vst1.{type[2]}"']]}]] types: - ['*mut f16', float16x4_t, '16', 'transmute(a)', 'crate::mem::align_of::() as i32', '_v4f16'] @@ -13918,6 +14024,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -13933,6 +14040,7 @@ intrinsics: - *neon-v7 - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec assert_instr: [nop] safety: safe types: @@ -13952,6 +14060,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [nop, 'LANE = 0']]}]] - FnCall: [rustc_legacy_const_generics, ["1"]] - *neon-unstable-f16 + - *target-not-arm64ec static_defs: ['const LANE: i32'] safety: safe types: @@ -13971,6 +14080,7 @@ intrinsics: - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, [dup]]}]] - *neon-fp16 - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - [float16x4_t, f16] @@ -14585,6 +14695,7 @@ intrinsics: - FnCall: [cfg_attr, [*test-is-arm, { FnCall: [assert_instr, ['vbsl']]}]] - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, ['bsl']]}]] - *neon-unstable-f16 + - *target-not-arm64ec safety: safe types: - ['vbslq_f16', 'uint16x8_t', 'float16x8_t', 'int16x8_t::splat(-1)'] diff --git a/library/stdarch/crates/stdarch-test/src/disassembly.rs b/library/stdarch/crates/stdarch-test/src/disassembly.rs index f5167ea8d8ef3..4c136cff02ae6 100644 --- a/library/stdarch/crates/stdarch-test/src/disassembly.rs +++ b/library/stdarch/crates/stdarch-test/src/disassembly.rs @@ -27,9 +27,9 @@ fn normalize(mut symbol: &str) -> String { symbol = symbol[last_colon + 1..].to_string(); } - // Normalize to no leading underscore to handle platforms that may + // Normalize to no leading mangling chars to handle platforms that may // inject extra ones in symbol names. - while symbol.starts_with('_') || symbol.starts_with('.') { + while symbol.starts_with('_') || symbol.starts_with('.') || symbol.starts_with('#') { symbol.remove(0); } // Windows/x86 has a suffix such as @@4. @@ -49,6 +49,8 @@ pub(crate) fn disassemble_myself() -> HashSet { "i686-pc-windows-msvc" } else if cfg!(target_arch = "aarch64") { "aarch64-pc-windows-msvc" + } else if cfg!(target_arch = "arm64ec") { + "arm64ec-pc-windows-msvc" } else { panic!("disassembly unimplemented") }; From 802fa9255b59c8787d679f5da1f5534f9c0580b0 Mon Sep 17 00:00:00 2001 From: Ifeanyi Orizu Date: Sun, 10 Aug 2025 10:02:03 -0500 Subject: [PATCH 029/251] Add config option to exclude locals from doc search --- .../crates/ide/src/file_structure.rs | 307 +++++++++++++++++- src/tools/rust-analyzer/crates/ide/src/lib.rs | 12 +- .../crates/rust-analyzer/src/cli/symbols.rs | 9 +- .../crates/rust-analyzer/src/config.rs | 16 + .../rust-analyzer/src/handlers/request.rs | 17 +- .../docs/book/src/configuration_generated.md | 7 + .../rust-analyzer/editors/code/package.json | 10 + 7 files changed, 350 insertions(+), 28 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index 6820f99facf2c..e0cd32baa97e3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -23,6 +23,11 @@ pub enum StructureNodeKind { Region, } +#[derive(Debug, Clone)] +pub struct FileStructureConfig { + pub exclude_locals: bool, +} + // Feature: File Structure // // Provides a tree of the symbols defined in the file. Can be used to @@ -36,21 +41,24 @@ pub enum StructureNodeKind { // | VS Code | Ctrl+Shift+O | // // ![File Structure](https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif) -pub(crate) fn file_structure(file: &SourceFile) -> Vec { +pub(crate) fn file_structure( + file: &SourceFile, + config: &FileStructureConfig, +) -> Vec { let mut res = Vec::new(); let mut stack = Vec::new(); for event in file.syntax().preorder_with_tokens() { match event { WalkEvent::Enter(NodeOrToken::Node(node)) => { - if let Some(mut symbol) = structure_node(&node) { + if let Some(mut symbol) = structure_node(&node, config) { symbol.parent = stack.last().copied(); stack.push(res.len()); res.push(symbol); } } WalkEvent::Leave(NodeOrToken::Node(node)) => { - if structure_node(&node).is_some() { + if structure_node(&node, config).is_some() { stack.pop().unwrap(); } } @@ -71,7 +79,7 @@ pub(crate) fn file_structure(file: &SourceFile) -> Vec { res } -fn structure_node(node: &SyntaxNode) -> Option { +fn structure_node(node: &SyntaxNode, config: &FileStructureConfig) -> Option { fn decl(node: N, kind: StructureNodeKind) -> Option { decl_with_detail(&node, None, kind) } @@ -187,6 +195,10 @@ fn structure_node(node: &SyntaxNode) -> Option { Some(node) }, ast::LetStmt(it) => { + if config.exclude_locals { + return None; + } + let pat = it.pat()?; let mut label = String::new(); @@ -254,9 +266,19 @@ mod tests { use super::*; + const DEFAULT_CONFIG: FileStructureConfig = FileStructureConfig { exclude_locals: true }; + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + check_with_config(ra_fixture, &DEFAULT_CONFIG, expect); + } + + fn check_with_config( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + config: &FileStructureConfig, + expect: Expect, + ) { let file = SourceFile::parse(ra_fixture, span::Edition::CURRENT).ok().unwrap(); - let structure = file_structure(&file); + let structure = file_structure(&file, config); expect.assert_debug_eq(&structure) } @@ -701,13 +723,264 @@ fn let_statements() { ), deprecated: false, }, + ] + "#]], + ); + } + + #[test] + fn test_file_structure_include_locals() { + check_with_config( + r#" +struct Foo { + x: i32 +} + +mod m { + fn bar1() {} + fn bar2(t: T) -> T {} + fn bar3(a: A, + b: B) -> Vec< + u32 + > {} +} + +enum E { X, Y(i32) } +type T = (); +static S: i32 = 42; +const C: i32 = 42; +trait Tr {} +trait Alias = Tr; + +macro_rules! mc { + () => {} +} + +fn let_statements() { + let x = 42; + let mut y = x; + let Foo { + .. + } = Foo { x }; + _ = (); + let _ = g(); +} +"#, + &FileStructureConfig { exclude_locals: false }, + expect![[r#" + [ + StructureNode { + parent: None, + label: "Foo", + navigation_range: 8..11, + node_range: 1..26, + kind: SymbolKind( + Struct, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 0, + ), + label: "x", + navigation_range: 18..19, + node_range: 18..24, + kind: SymbolKind( + Field, + ), + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "m", + navigation_range: 32..33, + node_range: 28..158, + kind: SymbolKind( + Module, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar1", + navigation_range: 43..47, + node_range: 40..52, + kind: SymbolKind( + Function, + ), + detail: Some( + "fn()", + ), + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar2", + navigation_range: 60..64, + node_range: 57..81, + kind: SymbolKind( + Function, + ), + detail: Some( + "fn(t: T) -> T", + ), + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar3", + navigation_range: 89..93, + node_range: 86..156, + kind: SymbolKind( + Function, + ), + detail: Some( + "fn(a: A, b: B) -> Vec< u32 >", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "E", + navigation_range: 165..166, + node_range: 160..180, + kind: SymbolKind( + Enum, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 6, + ), + label: "X", + navigation_range: 169..170, + node_range: 169..170, + kind: SymbolKind( + Variant, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 6, + ), + label: "Y", + navigation_range: 172..173, + node_range: 172..178, + kind: SymbolKind( + Variant, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "T", + navigation_range: 186..187, + node_range: 181..193, + kind: SymbolKind( + TypeAlias, + ), + detail: Some( + "()", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "S", + navigation_range: 201..202, + node_range: 194..213, + kind: SymbolKind( + Static, + ), + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "C", + navigation_range: 220..221, + node_range: 214..232, + kind: SymbolKind( + Const, + ), + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "Tr", + navigation_range: 239..241, + node_range: 233..244, + kind: SymbolKind( + Trait, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "Alias", + navigation_range: 251..256, + node_range: 245..262, + kind: SymbolKind( + TraitAlias, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "mc", + navigation_range: 277..279, + node_range: 264..296, + kind: SymbolKind( + Macro, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "let_statements", + navigation_range: 301..315, + node_range: 298..429, + kind: SymbolKind( + Function, + ), + detail: Some( + "fn()", + ), + deprecated: false, + }, StructureNode { parent: Some( - 27, + 15, ), label: "x", - navigation_range: 684..685, - node_range: 680..691, + navigation_range: 328..329, + node_range: 324..335, kind: SymbolKind( Local, ), @@ -716,11 +989,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 27, + 15, ), label: "mut y", - navigation_range: 700..705, - node_range: 696..710, + navigation_range: 344..349, + node_range: 340..354, kind: SymbolKind( Local, ), @@ -729,11 +1002,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 27, + 15, ), label: "Foo { .. }", - navigation_range: 719..741, - node_range: 715..754, + navigation_range: 363..385, + node_range: 359..398, kind: SymbolKind( Local, ), @@ -742,11 +1015,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 27, + 15, ), label: "_", - navigation_range: 804..805, - node_range: 800..812, + navigation_range: 419..420, + node_range: 415..427, kind: SymbolKind( Local, ), diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 98877482ed863..5349ebb7c82a5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -81,7 +81,7 @@ pub use crate::{ annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation}, call_hierarchy::{CallHierarchyConfig, CallItem}, expand_macro::ExpandedMacro, - file_structure::{StructureNode, StructureNodeKind}, + file_structure::{FileStructureConfig, StructureNode, StructureNodeKind}, folding_ranges::{Fold, FoldKind}, highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{ @@ -430,12 +430,16 @@ impl Analysis { /// Returns a tree representation of symbols in the file. Useful to draw a /// file outline. - pub fn file_structure(&self, file_id: FileId) -> Cancellable> { + pub fn file_structure( + &self, + config: &FileStructureConfig, + file_id: FileId, + ) -> Cancellable> { // FIXME: Edition self.with_db(|db| { let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id); - - file_structure::file_structure(&db.parse(editioned_file_id_wrapper).tree()) + let source_file = db.parse(editioned_file_id_wrapper).tree(); + file_structure::file_structure(&source_file, config) }) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs index 9fad6723afcd9..d7af56d3e15be 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/symbols.rs @@ -1,5 +1,5 @@ //! Read Rust code on stdin, print syntax tree on stdout. -use ide::Analysis; +use ide::{Analysis, FileStructureConfig}; use crate::cli::{flags, read_stdin}; @@ -7,7 +7,12 @@ impl flags::Symbols { pub fn run(self) -> anyhow::Result<()> { let text = read_stdin()?; let (analysis, file_id) = Analysis::from_single_file(text); - let structure = analysis.file_structure(file_id).unwrap(); + let structure = analysis + // The default setting in config.rs (document_symbol_search_excludeLocals) is to exclude + // locals because it is unlikely that users want document search to return the names of + // local variables, but here we include them deliberately. + .file_structure(&FileStructureConfig { exclude_locals: false }, file_id) + .unwrap(); for s in structure { println!("{s:?}"); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 1a00295b9ac18..77e5a8e079f84 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -858,6 +858,9 @@ config_data! { /// check will be performed. check_workspace: bool = true, + /// Exclude all locals from document symbol search. + document_symbol_search_excludeLocals: bool = true, + /// These proc-macros will be ignored when trying to expand them. /// /// This config takes a map of crate names with the exported proc-macro names to ignore as values. @@ -1481,6 +1484,13 @@ pub enum FilesWatcher { Server, } +/// Configuration for document symbol search requests. +#[derive(Debug, Clone)] +pub struct DocumentSymbolConfig { + /// Should locals be excluded. + pub search_exclude_locals: bool, +} + #[derive(Debug, Clone)] pub struct NotificationsConfig { pub cargo_toml_not_found: bool, @@ -2438,6 +2448,12 @@ impl Config { } } + pub fn document_symbol(&self, source_root: Option) -> DocumentSymbolConfig { + DocumentSymbolConfig { + search_exclude_locals: *self.document_symbol_search_excludeLocals(source_root), + } + } + pub fn workspace_symbol(&self, source_root: Option) -> WorkspaceSymbolConfig { WorkspaceSymbolConfig { search_exclude_imports: *self.workspace_symbol_search_excludeImports(source_root), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 25c0aac405e79..74ed5e344af6d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -8,8 +8,9 @@ use anyhow::Context; use base64::{Engine, prelude::BASE64_STANDARD}; use ide::{ AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, - FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, - RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, + FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData, + InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, + SingleResolve, SourceChange, TextEdit, }; use ide_db::{FxHashMap, SymbolKind}; use itertools::Itertools; @@ -568,7 +569,14 @@ pub(crate) fn handle_document_symbol( let mut parents: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); - for symbol in snap.analysis.file_structure(file_id)? { + let config = snap.config.document_symbol(None); + + let structure_nodes = snap.analysis.file_structure( + &FileStructureConfig { exclude_locals: config.search_exclude_locals }, + file_id, + )?; + + for symbol in structure_nodes { let mut tags = Vec::new(); if symbol.deprecated { tags.push(SymbolTag::DEPRECATED) @@ -588,8 +596,7 @@ pub(crate) fn handle_document_symbol( parents.push((doc_symbol, symbol.parent)); } - // Builds hierarchy from a flat list, in reverse order (so that indices - // makes sense) + // Builds hierarchy from a flat list, in reverse order (so that indices make sense) let document_symbols = { let mut acc = Vec::new(); while let Some((mut node, parent_idx)) = parents.pop() { diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 99a30d8f62138..6ee956fe0dbf4 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -610,6 +610,13 @@ The warnings will be indicated by a blue squiggly underline in code and a blue i the `Problems Panel`. +## rust-analyzer.document.symbol.search.excludeLocals {#document.symbol.search.excludeLocals} + +Default: `true` + +Exclude all locals from document symbol search. + + ## rust-analyzer.files.exclude {#files.exclude} Default: `[]` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 470db244f14bd..328eb509b4eea 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1585,6 +1585,16 @@ } } }, + { + "title": "Document", + "properties": { + "rust-analyzer.document.symbol.search.excludeLocals": { + "markdownDescription": "Exclude all locals from document symbol search.", + "default": true, + "type": "boolean" + } + } + }, { "title": "Files", "properties": { From 00d000ce74f8e3bed8abc4cff382f62dcca0d8d5 Mon Sep 17 00:00:00 2001 From: Ifeanyi Orizu Date: Sun, 10 Aug 2025 10:02:34 -0500 Subject: [PATCH 030/251] Fix minor things --- .../crates/ide/src/file_structure.rs | 1 - .../crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/src/handlers/request.rs | 38 +++++++++---------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index e0cd32baa97e3..ac15af0334fc8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -213,7 +213,6 @@ fn structure_node(node: &SyntaxNode, config: &FileStructureConfig) -> Option { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 77e5a8e079f84..d4cd56dc55bf6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -3083,7 +3083,7 @@ macro_rules! _config_data { }) => { /// Default config values for this grouping. #[allow(non_snake_case)] - #[derive(Debug, Clone )] + #[derive(Debug, Clone)] struct $name { $($field: $ty,)* } impl_for_config_data!{ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 74ed5e344af6d..6cb28aecf748f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -567,7 +567,7 @@ pub(crate) fn handle_document_symbol( let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; - let mut parents: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); + let mut symbols: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); let config = snap.config.document_symbol(None); @@ -576,38 +576,38 @@ pub(crate) fn handle_document_symbol( file_id, )?; - for symbol in structure_nodes { + for node in structure_nodes { let mut tags = Vec::new(); - if symbol.deprecated { + if node.deprecated { tags.push(SymbolTag::DEPRECATED) }; #[allow(deprecated)] - let doc_symbol = lsp_types::DocumentSymbol { - name: symbol.label, - detail: symbol.detail, - kind: to_proto::structure_node_kind(symbol.kind), + let symbol = lsp_types::DocumentSymbol { + name: node.label, + detail: node.detail, + kind: to_proto::structure_node_kind(node.kind), tags: Some(tags), - deprecated: Some(symbol.deprecated), - range: to_proto::range(&line_index, symbol.node_range), - selection_range: to_proto::range(&line_index, symbol.navigation_range), + deprecated: Some(node.deprecated), + range: to_proto::range(&line_index, node.node_range), + selection_range: to_proto::range(&line_index, node.navigation_range), children: None, }; - parents.push((doc_symbol, symbol.parent)); + symbols.push((symbol, node.parent)); } - // Builds hierarchy from a flat list, in reverse order (so that indices make sense) + // Builds hierarchy from a flat list, in reverse order (so that the indices make sense) let document_symbols = { let mut acc = Vec::new(); - while let Some((mut node, parent_idx)) = parents.pop() { - if let Some(children) = &mut node.children { + while let Some((mut symbol, parent_idx)) = symbols.pop() { + if let Some(children) = &mut symbol.children { children.reverse(); } let parent = match parent_idx { None => &mut acc, - Some(i) => parents[i].0.children.get_or_insert_with(Vec::new), + Some(i) => symbols[i].0.children.get_or_insert_with(Vec::new), }; - parent.push(node); + parent.push(symbol); } acc.reverse(); acc @@ -617,7 +617,7 @@ pub(crate) fn handle_document_symbol( document_symbols.into() } else { let url = to_proto::url(&snap, file_id); - let mut symbol_information = Vec::::new(); + let mut symbol_information = Vec::new(); for symbol in document_symbols { flatten_document_symbol(&symbol, None, &url, &mut symbol_information); } @@ -654,7 +654,7 @@ pub(crate) fn handle_workspace_symbol( let _p = tracing::info_span!("handle_workspace_symbol").entered(); let config = snap.config.workspace_symbol(None); - let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &config); + let (all_symbols, libs) = decide_search_kind_and_scope(¶ms, &config); let query = { let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect(); @@ -677,7 +677,7 @@ pub(crate) fn handle_workspace_symbol( return Ok(Some(lsp_types::WorkspaceSymbolResponse::Nested(res))); - fn decide_search_scope_and_kind( + fn decide_search_kind_and_scope( params: &WorkspaceSymbolParams, config: &WorkspaceSymbolConfig, ) -> (bool, bool) { From af10cb727fd55ce8638653f18d2edd4b8005add7 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 11 Aug 2025 04:25:52 +0000 Subject: [PATCH 031/251] Prepare for merging from rust-lang/rust This updates the rust-version file to 21a19c297d4f5a03501d92ca251bd7a17073c08a. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 2178caf63968a..02b217f7d80dc 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -733dab558992d902d6d17576de1da768094e2cf3 +21a19c297d4f5a03501d92ca251bd7a17073c08a From 7daaa4ee01f4c4d026293a6e3a90e4c8b4f5aa12 Mon Sep 17 00:00:00 2001 From: "Shoyu Vanilla (Flint)" Date: Mon, 11 Aug 2025 18:18:55 +0900 Subject: [PATCH 032/251] hotfix: Update flycheck diagnostics generation --- src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index cd7c632d105e0..2711bdba693bf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -134,6 +134,7 @@ impl DiagnosticCollection { if self.check[flycheck_id].generation > generation { return; } + self.check[flycheck_id].generation = generation; let diagnostics = self.check[flycheck_id] .per_package .entry(package_id.clone()) From 380d89d82f514d7e998f7b3b0e6bdb2065b711bc Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 11 Aug 2025 01:57:27 +0900 Subject: [PATCH 033/251] Make import sorting order follow 2024 edition style --- .../ide-assists/src/handlers/merge_imports.rs | 2 +- .../src/handlers/normalize_import.rs | 22 +- .../ide-completion/src/tests/flyimport.rs | 2 +- .../ide-db/src/imports/insert_use/tests.rs | 26 +-- .../ide-db/src/imports/merge_imports.rs | 217 ++++++++++++++++-- 5 files changed, 219 insertions(+), 50 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 6bf7f5849148f..9ba73d23dd243 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -605,7 +605,7 @@ use foo::$0{ ", r" use foo::{ - bar::baz, FooBar + FooBar, bar::baz, }; ", ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs index bba28b5fc8af5..36da1d1788247 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs @@ -109,8 +109,8 @@ mod tests { #[test] fn test_order() { check_assist_variations!( - "foo::{*, Qux, bar::{Quux, Bar}, baz, FOO_BAZ, self, Baz}", - "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}" + "foo::{*, Qux, bar::{Quux, Bar}, baz, FOO_BAZ, self, Baz, v10, v9, r#aaa}", + "foo::{self, Baz, FOO_BAZ, Qux, r#aaa, bar::{Bar, Quux}, baz, v9, v10, *}" ); } @@ -145,17 +145,17 @@ fn main() { #[test] fn test_redundant_braces() { - check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}"); + check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{Qux, baz}"); check_assist_variations!("foo::{bar::{self}}", "foo::bar::{self}"); check_assist_variations!("foo::{bar::{*}}", "foo::bar::*"); check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux"); check_assist_variations!( "foo::bar::{{FOO_BAZ, Qux, self}, {*, baz}}", - "foo::bar::{self, baz, Qux, FOO_BAZ, *}" + "foo::bar::{self, FOO_BAZ, Qux, baz, *}" ); check_assist_variations!( "foo::bar::{{{FOO_BAZ}, {{Qux}, {self}}}, {{*}, {baz}}}", - "foo::bar::{self, baz, Qux, FOO_BAZ, *}" + "foo::bar::{self, FOO_BAZ, Qux, baz, *}" ); } @@ -163,11 +163,11 @@ fn main() { fn test_merge() { check_assist_variations!( "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux}}", - "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}" + "foo::{FOO_BAZ, Quux, bar::{self, baz, *}, qux, *}" ); check_assist_variations!( "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux, bar::{baz::Foo}}}", - "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}" + "foo::{FOO_BAZ, Quux, bar::{self, baz::{self, Foo}, *}, qux, *}" ); } @@ -229,15 +229,15 @@ use { check_assist_not_applicable_variations!("foo::bar"); check_assist_not_applicable_variations!("foo::bar::*"); check_assist_not_applicable_variations!("foo::bar::Qux as Quux"); - check_assist_not_applicable_variations!("foo::bar::{self, baz, Qux, FOO_BAZ, *}"); + check_assist_not_applicable_variations!("foo::bar::{self, FOO_BAZ, Qux, baz, *}"); check_assist_not_applicable_variations!( - "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}" + "foo::{self, Baz, FOO_BAZ, Qux, bar::{Bar, Quux}, baz, *}" ); check_assist_not_applicable_variations!( - "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}" + "foo::{FOO_BAZ, Quux, bar::{self, baz, *}, qux, *}" ); check_assist_not_applicable_variations!( - "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}" + "foo::{bar::{self, FOO_BAZ, Quux, baz::{self, Foo}, *}, qux, *}" ); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 27c91bc7c4558..04bed418eec79 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -114,7 +114,7 @@ fn main() { } "#, r#" -use dep::{some_module::{SecondStruct, ThirdStruct}, FirstStruct}; +use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; fn main() { ThirdStruct diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 4a00854f01a5f..3350e1c3d207f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -782,18 +782,18 @@ fn merge_groups_long_last_list() { fn merge_groups_long_full_nested() { check_crate( "std::foo::bar::Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux};", + r"use std::foo::bar::{quux::{Fez, Fizz}, Qux};", + r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};", ); check_crate( "std::foo::bar::r#Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{quux::{Fez, Fizz}, r#Baz, Qux};", + r"use std::foo::bar::{quux::{Fez, Fizz}, Qux};", + r"use std::foo::bar::{r#Baz, Qux, quux::{Fez, Fizz}};", ); check_one( "std::foo::bar::Baz", - r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", - r"use {std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux}};", + r"use {std::foo::bar::{quux::{Fez, Fizz}}, Qux};", + r"use {Qux, std::foo::bar::{Baz, quux::{Fez, Fizz}}};", ); } @@ -811,13 +811,13 @@ use std::foo::bar::{Qux, quux::{Fez, Fizz}};", fn merge_groups_full_nested_deep() { check_crate( "std::foo::bar::quux::Baz", - r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", - r"use std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux};", + r"use std::foo::bar::{quux::{Fez, Fizz}, Qux};", + r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};", ); check_one( "std::foo::bar::quux::Baz", - r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", - r"use {std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux}};", + r"use {std::foo::bar::{quux::{Fez, Fizz}}, Qux};", + r"use {Qux, std::foo::bar::quux::{Baz, Fez, Fizz}};", ); } @@ -988,8 +988,8 @@ use syntax::SyntaxKind::{self, *};", fn merge_glob_nested() { check_crate( "foo::bar::quux::Fez", - r"use foo::bar::{Baz, quux::*};", - r"use foo::bar::{quux::{Fez, *}, Baz};", + r"use foo::bar::{quux::*, Baz};", + r"use foo::bar::{Baz, quux::{Fez, *}};", ) } @@ -998,7 +998,7 @@ fn merge_nested_considers_first_segments() { check_crate( "hir_ty::display::write_bounds_like_dyn_trait", r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", - r"use hir_ty::{autoderef, display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, method_resolution};", + r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};", ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 61962e593476c..4e779a7d858e5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -3,7 +3,6 @@ use std::cmp::Ordering; use itertools::{EitherOrBoth, Itertools}; use parser::T; -use stdx::is_upper_snake_case; use syntax::{ Direction, SyntaxElement, algo, ast::{ @@ -543,12 +542,13 @@ fn use_tree_cmp_bin_search(lhs: &ast::UseTree, rhs: &ast::UseTree) -> Ordering { } } -/// Orders use trees following `rustfmt`'s algorithm for ordering imports, which is `self`, `super` -/// and `crate` first, then identifier imports with lowercase ones first and upper snake case -/// (e.g. UPPER_SNAKE_CASE) ones last, then glob imports, and at last list imports. +/// Orders use trees following `rustfmt`'s version sorting algorithm for ordering imports. /// -/// Example: `foo::{self, baz, foo, Baz, Qux, FOO_BAZ, *, {Bar}}` -/// Ref: . +/// Example: `foo::{self, Baz, FOO_BAZ, Qux, baz, foo, *, {Bar}}` +/// +/// Ref: +/// - +/// - pub(super) fn use_tree_cmp(a: &ast::UseTree, b: &ast::UseTree) -> Ordering { let a_is_simple_path = a.is_simple_path() && a.rename().is_none(); let b_is_simple_path = b.is_simple_path() && b.rename().is_none(); @@ -613,26 +613,9 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering { (Some(_), None) => Ordering::Greater, (None, Some(_)) => Ordering::Less, (Some(a_name), Some(b_name)) => { - // snake_case < UpperCamelCase < UPPER_SNAKE_CASE let a_text = a_name.as_str().trim_start_matches("r#"); let b_text = b_name.as_str().trim_start_matches("r#"); - if a_text.starts_with(char::is_lowercase) - && b_text.starts_with(char::is_uppercase) - { - return Ordering::Less; - } - if a_text.starts_with(char::is_uppercase) - && b_text.starts_with(char::is_lowercase) - { - return Ordering::Greater; - } - if !is_upper_snake_case(a_text) && is_upper_snake_case(b_text) { - return Ordering::Less; - } - if is_upper_snake_case(a_text) && !is_upper_snake_case(b_text) { - return Ordering::Greater; - } - a_text.cmp(b_text) + version_sort::version_sort(a_text, b_text) } } } @@ -740,3 +723,189 @@ fn remove_subtree_if_only_self(use_tree: &ast::UseTree) { _ => (), } } + +// Taken from rustfmt +// https://github.com/rust-lang/rustfmt/blob/0332da01486508710f2a542111e40513bfb215aa/src/sort.rs +mod version_sort { + // Original rustfmt code contains some clippy lints. + // Suppress them to minimize changes from upstream. + #![allow(clippy::all)] + + use std::cmp::Ordering; + + use itertools::{EitherOrBoth, Itertools}; + + struct VersionChunkIter<'a> { + ident: &'a str, + start: usize, + } + + impl<'a> VersionChunkIter<'a> { + pub(crate) fn new(ident: &'a str) -> Self { + Self { ident, start: 0 } + } + + fn parse_numeric_chunk( + &mut self, + mut chars: std::str::CharIndices<'a>, + ) -> Option> { + let mut end = self.start; + let mut is_end_of_chunk = false; + + while let Some((idx, c)) = chars.next() { + end = self.start + idx; + + if c.is_ascii_digit() { + continue; + } + + is_end_of_chunk = true; + break; + } + + let source = if is_end_of_chunk { + let value = &self.ident[self.start..end]; + self.start = end; + value + } else { + let value = &self.ident[self.start..]; + self.start = self.ident.len(); + value + }; + + let zeros = source.chars().take_while(|c| *c == '0').count(); + let value = source.parse::().ok()?; + + Some(VersionChunk::Number { value, zeros, source }) + } + + fn parse_str_chunk( + &mut self, + mut chars: std::str::CharIndices<'a>, + ) -> Option> { + let mut end = self.start; + let mut is_end_of_chunk = false; + + while let Some((idx, c)) = chars.next() { + end = self.start + idx; + + if c == '_' { + is_end_of_chunk = true; + break; + } + + if !c.is_ascii_digit() { + continue; + } + + is_end_of_chunk = true; + break; + } + + let source = if is_end_of_chunk { + let value = &self.ident[self.start..end]; + self.start = end; + value + } else { + let value = &self.ident[self.start..]; + self.start = self.ident.len(); + value + }; + + Some(VersionChunk::Str(source)) + } + } + + impl<'a> Iterator for VersionChunkIter<'a> { + type Item = VersionChunk<'a>; + + fn next(&mut self) -> Option { + let mut chars = self.ident[self.start..].char_indices(); + let (_, next) = chars.next()?; + + if next == '_' { + self.start = self.start + next.len_utf8(); + return Some(VersionChunk::Underscore); + } + + if next.is_ascii_digit() { + return self.parse_numeric_chunk(chars); + } + + self.parse_str_chunk(chars) + } + } + + /// Represents a chunk in the version-sort algorithm + #[derive(Debug, PartialEq, Eq)] + enum VersionChunk<'a> { + /// A single `_` in an identifier. Underscores are sorted before all other characters. + Underscore, + /// A &str chunk in the version sort. + Str(&'a str), + /// A numeric chunk in the version sort. Keeps track of the numeric value and leading zeros. + Number { value: usize, zeros: usize, source: &'a str }, + } + + /// Determine which side of the version-sort comparison had more leading zeros. + #[derive(Debug, PartialEq, Eq)] + enum MoreLeadingZeros { + Left, + Right, + Equal, + } + + pub(super) fn version_sort(a: &str, b: &str) -> Ordering { + let iter_a = VersionChunkIter::new(a); + let iter_b = VersionChunkIter::new(b); + let mut more_leading_zeros = MoreLeadingZeros::Equal; + + for either_or_both in iter_a.zip_longest(iter_b) { + match either_or_both { + EitherOrBoth::Left(_) => return std::cmp::Ordering::Greater, + EitherOrBoth::Right(_) => return std::cmp::Ordering::Less, + EitherOrBoth::Both(a, b) => match (a, b) { + (VersionChunk::Underscore, VersionChunk::Underscore) => { + continue; + } + (VersionChunk::Underscore, _) => return std::cmp::Ordering::Less, + (_, VersionChunk::Underscore) => return std::cmp::Ordering::Greater, + (VersionChunk::Str(ca), VersionChunk::Str(cb)) + | (VersionChunk::Str(ca), VersionChunk::Number { source: cb, .. }) + | (VersionChunk::Number { source: ca, .. }, VersionChunk::Str(cb)) => { + match ca.cmp(&cb) { + std::cmp::Ordering::Equal => { + continue; + } + order @ _ => return order, + } + } + ( + VersionChunk::Number { value: va, zeros: lza, .. }, + VersionChunk::Number { value: vb, zeros: lzb, .. }, + ) => match va.cmp(&vb) { + std::cmp::Ordering::Equal => { + if lza == lzb { + continue; + } + + if more_leading_zeros == MoreLeadingZeros::Equal && lza > lzb { + more_leading_zeros = MoreLeadingZeros::Left; + } else if more_leading_zeros == MoreLeadingZeros::Equal && lza < lzb { + more_leading_zeros = MoreLeadingZeros::Right; + } + continue; + } + order @ _ => return order, + }, + }, + } + } + + match more_leading_zeros { + MoreLeadingZeros::Equal => std::cmp::Ordering::Equal, + MoreLeadingZeros::Left => std::cmp::Ordering::Less, + MoreLeadingZeros::Right => std::cmp::Ordering::Greater, + } + } +} From 6c3c620e6b65a130a6996cca14cb9e19cc8ea65c Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 12 Aug 2025 00:24:44 +0900 Subject: [PATCH 034/251] fix: Panic while trying to clear old diagnostics while there's nothing --- src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 2711bdba693bf..30f530100f9df 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -105,7 +105,7 @@ impl DiagnosticCollection { flycheck_id: usize, generation: DiagnosticsGeneration, ) { - if self.check[flycheck_id].generation < generation { + if self.check.get(flycheck_id).is_some_and(|it| it.generation < generation) { self.clear_check(flycheck_id); } } From 875c158686fc47e083c83d1ccee4359ba4cc64f9 Mon Sep 17 00:00:00 2001 From: sgasho Date: Mon, 11 Aug 2025 22:19:50 +0900 Subject: [PATCH 035/251] fix: Implement default member to resolve IdentPat --- .../src/handlers/add_missing_impl_members.rs | 49 +++++++++++++++ .../crates/ide-db/src/path_transform.rs | 61 ++++++++++++++++--- 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 11201afb8a7f2..7e03eb30304bf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2418,6 +2418,55 @@ pub struct MyStruct; impl other_file_2::Trait for MyStruct { $0type Iter; +}"#, + ); + } + + #[test] + fn test_qualify_ident_pat_in_default_members() { + check_assist( + add_missing_default_members, + r#" +//- /lib.rs crate:b new_source_root:library +pub enum State { + Active, + Inactive, +} + +use State::*; + +pub trait Checker { + fn check(&self) -> State; + + fn is_active(&self) -> bool { + match self.check() { + Active => true, + Inactive => false, + } + } +} +//- /main.rs crate:a deps:b +struct MyChecker; + +impl b::Checker for MyChecker { + fn check(&self) -> b::State { + todo!(); + }$0 +}"#, + r#" +struct MyChecker; + +impl b::Checker for MyChecker { + fn check(&self) -> b::State { + todo!(); + } + + $0fn is_active(&self) -> bool { + match self.check() { + b::State::Active => true, + b::State::Inactive => false, + } + } }"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 5d88afec50951..a76a0551dd8db 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -11,7 +11,7 @@ use rustc_hash::FxHashMap; use span::Edition; use syntax::{ NodeOrToken, SyntaxNode, - ast::{self, AstNode, HasGenericArgs, make}, + ast::{self, AstNode, HasGenericArgs, HasName, make}, syntax_editor::{self, SyntaxEditor}, }; @@ -315,32 +315,49 @@ impl Ctx<'_> { } fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode { - fn find_child_paths(root_path: &SyntaxNode) -> Vec { - let mut result = Vec::new(); + fn find_child_paths_and_ident_pats( + root_path: &SyntaxNode, + ) -> Vec> { + let mut result: Vec> = Vec::new(); for child in root_path.children() { if let Some(child_path) = ast::Path::cast(child.clone()) { - result.push(child_path); + result.push(either::Left(child_path)); + } else if let Some(child_ident_pat) = ast::IdentPat::cast(child.clone()) { + result.push(either::Right(child_ident_pat)); } else { - result.extend(find_child_paths(&child)); + result.extend(find_child_paths_and_ident_pats(&child)); } } result } + let root_path = path.clone_subtree(); - let result = find_child_paths(&root_path); + + let result = find_child_paths_and_ident_pats(&root_path); let mut editor = SyntaxEditor::new(root_path.clone()); for sub_path in result { let new = self.transform_path(sub_path.syntax()); editor.replace(sub_path.syntax(), new); } + let update_sub_item = editor.finish().new_root().clone().clone_subtree(); - let item = find_child_paths(&update_sub_item); + let item = find_child_paths_and_ident_pats(&update_sub_item); let mut editor = SyntaxEditor::new(update_sub_item); for sub_path in item { - self.transform_path_(&mut editor, &sub_path); + self.transform_path_or_ident_pat(&mut editor, &sub_path); } editor.finish().new_root().clone() } + fn transform_path_or_ident_pat( + &self, + editor: &mut SyntaxEditor, + item: &Either, + ) -> Option<()> { + match item { + Either::Left(path) => self.transform_path_(editor, path), + Either::Right(ident_pat) => self.transform_ident_pat(editor, ident_pat), + } + } fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> { if path.qualifier().is_some() { @@ -515,6 +532,34 @@ impl Ctx<'_> { } Some(()) } + + fn transform_ident_pat( + &self, + editor: &mut SyntaxEditor, + ident_pat: &ast::IdentPat, + ) -> Option<()> { + let name = ident_pat.name()?; + + let temp_path = make::path_from_text(&name.text()); + + let resolution = self.source_scope.speculative_resolve(&temp_path)?; + + match resolution { + hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => { + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + allow_unstable: true, + }; + let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?; + let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update(); + editor.replace(ident_pat.syntax(), res.syntax()); + Some(()) + } + _ => None, + } + } } // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the From 49ebe9f849202561ac02ece6e8683a6602bf1f38 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 13 Aug 2025 05:23:58 +0300 Subject: [PATCH 036/251] Only import the item in "Unqualify method call" if needed --- .../rust-analyzer/crates/hir/src/semantics.rs | 5 + .../src/handlers/unqualify_method_call.rs | 118 +++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 05f06f97fdc26..6be44532d033f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2247,6 +2247,11 @@ impl<'db> SemanticsScope<'db> { } } + /// Checks if a trait is in scope, either because of an import or because we're in an impl of it. + pub fn can_use_trait_methods(&self, t: Trait) -> bool { + self.resolver.traits_in_scope(self.db).contains(&t.id) + } + /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs index 1f89a3d5f17c9..a58b1da621c7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -1,3 +1,4 @@ +use hir::AsAssocItem; use syntax::{ TextRange, ast::{self, AstNode, HasArgList, prec::ExprPrecedence}, @@ -43,6 +44,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) let qualifier = path.qualifier()?; let method_name = path.segment()?.name_ref()?; + let scope = ctx.sema.scope(path.syntax())?; let res = ctx.sema.resolve_path(&path)?; let hir::PathResolution::Def(hir::ModuleDef::Function(fun)) = res else { return None }; if !fun.has_self_param(ctx.sema.db) { @@ -78,7 +80,14 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) edit.insert(close, ")"); } edit.replace(replace_comma, format!(".{method_name}(")); - add_import(qualifier, ctx, edit); + + if let Some(fun) = fun.as_assoc_item(ctx.db()) + && let Some(trait_) = fun.container_or_implemented_trait(ctx.db()) + && !scope.can_use_trait_methods(trait_) + { + // Only add an import for trait methods that are not already imported. + add_import(qualifier, ctx, edit); + } }, ) } @@ -235,4 +244,111 @@ impl S { fn assoc(S: S, S: S) {} } fn f() { S::assoc$0(S, S); }"#, ); } + + #[test] + fn inherent_method() { + check_assist( + unqualify_method_call, + r#" +mod foo { + pub struct Bar; + impl Bar { + pub fn bar(self) {} + } +} + +fn baz() { + foo::Bar::b$0ar(foo::Bar); +} + "#, + r#" +mod foo { + pub struct Bar; + impl Bar { + pub fn bar(self) {} + } +} + +fn baz() { + foo::Bar.bar(); +} + "#, + ); + } + + #[test] + fn trait_method_in_impl() { + check_assist( + unqualify_method_call, + r#" +mod foo { + pub trait Bar { + pub fn bar(self) {} + } +} + +struct Baz; +impl foo::Bar for Baz { + fn bar(self) { + foo::Bar::b$0ar(Baz); + } +} + "#, + r#" +mod foo { + pub trait Bar { + pub fn bar(self) {} + } +} + +struct Baz; +impl foo::Bar for Baz { + fn bar(self) { + Baz.bar(); + } +} + "#, + ); + } + + #[test] + fn trait_method_already_imported() { + check_assist( + unqualify_method_call, + r#" +mod foo { + pub struct Foo; + pub trait Bar { + pub fn bar(self) {} + } + impl Bar for Foo { + pub fn bar(self) {} + } +} + +use foo::Bar; + +fn baz() { + foo::Bar::b$0ar(foo::Foo); +} + "#, + r#" +mod foo { + pub struct Foo; + pub trait Bar { + pub fn bar(self) {} + } + impl Bar for Foo { + pub fn bar(self) {} + } +} + +use foo::Bar; + +fn baz() { + foo::Foo.bar(); +} + "#, + ); + } } From 8d247472e5f9612b4bf9668de937ad9c373b891c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 4 Aug 2025 16:11:51 +0800 Subject: [PATCH 037/251] Merge Trait and TraitAlias handling --- .../rust-analyzer/crates/hir-def/src/attr.rs | 2 - .../rust-analyzer/crates/hir-def/src/db.rs | 20 +--- .../crates/hir-def/src/dyn_map.rs | 5 +- .../crates/hir-def/src/expr_store/lower.rs | 24 +---- .../crates/hir-def/src/expr_store/pretty.rs | 1 - .../src/expr_store/tests/signatures.rs | 2 - .../crates/hir-def/src/hir/generics.rs | 11 --- .../crates/hir-def/src/item_scope.rs | 1 - .../crates/hir-def/src/item_tree.rs | 8 -- .../crates/hir-def/src/item_tree/lower.rs | 16 +-- .../crates/hir-def/src/item_tree/pretty.rs | 8 +- .../rust-analyzer/crates/hir-def/src/lib.rs | 14 --- .../crates/hir-def/src/nameres/assoc.rs | 10 +- .../crates/hir-def/src/nameres/collector.rs | 16 +-- .../crates/hir-def/src/resolver.rs | 13 +-- .../crates/hir-def/src/signatures.rs | 31 +----- .../rust-analyzer/crates/hir-def/src/src.rs | 9 +- .../crates/hir-ty/src/generics.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 1 - .../crates/hir-ty/src/lower/path.rs | 7 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 1 + .../crates/hir-ty/src/variance.rs | 5 - .../rust-analyzer/crates/hir/src/attrs.rs | 8 +- .../rust-analyzer/crates/hir/src/display.rs | 21 +--- .../rust-analyzer/crates/hir/src/from_id.rs | 5 - .../crates/hir/src/has_source.rs | 11 +-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 51 +--------- .../rust-analyzer/crates/hir/src/semantics.rs | 12 +-- .../hir/src/semantics/child_by_source.rs | 3 - .../crates/hir/src/semantics/source_to_def.rs | 16 +-- .../crates/hir/src/source_analyzer.rs | 4 +- .../rust-analyzer/crates/hir/src/symbols.rs | 3 - .../src/handlers/extract_module.rs | 1 - .../src/handlers/fix_visibility.rs | 4 - .../ide-assists/src/handlers/move_bounds.rs | 1 - .../ide-completion/src/completions/type.rs | 4 +- .../crates/ide-completion/src/context.rs | 1 - .../ide-completion/src/context/analysis.rs | 3 - .../crates/ide-completion/src/item.rs | 1 - .../crates/ide-completion/src/render.rs | 8 +- .../crates/ide-db/src/active_parameter.rs | 1 - .../rust-analyzer/crates/ide-db/src/defs.rs | 15 +-- .../crates/ide-db/src/documentation.rs | 3 +- .../ide-db/src/imports/import_assets.rs | 2 - .../rust-analyzer/crates/ide-db/src/lib.rs | 2 - .../rust-analyzer/crates/ide-db/src/rename.rs | 1 - .../rust-analyzer/crates/ide-db/src/search.rs | 1 - .../crates/ide-db/src/symbol_index.rs | 1 - .../rust-analyzer/crates/ide/src/doc_links.rs | 5 +- .../crates/ide/src/file_structure.rs | 3 +- .../crates/ide/src/folding_ranges.rs | 7 -- .../crates/ide/src/hover/render.rs | 1 - .../rust-analyzer/crates/ide/src/moniker.rs | 1 - .../rust-analyzer/crates/ide/src/move_item.rs | 1 - .../crates/ide/src/navigation_target.rs | 11 --- .../crates/ide/src/references.rs | 2 +- .../rust-analyzer/crates/ide/src/runnables.rs | 1 - .../crates/ide/src/signature_help.rs | 4 - .../ide/src/syntax_highlighting/highlight.rs | 2 - .../ide/src/syntax_highlighting/inject.rs | 1 - .../ide/src/syntax_highlighting/tags.rs | 1 - .../test_data/highlight_strings.html | 4 +- .../crates/parser/src/grammar/items/traits.rs | 2 +- .../parser/src/syntax_kind/generated.rs | 2 - .../parser/inline/ok/trait_alias.rast | 2 +- .../inline/ok/trait_alias_where_clause.rast | 4 +- .../crates/rust-analyzer/src/lsp/to_proto.rs | 5 +- .../rust-analyzer/crates/span/src/ast_id.rs | 3 +- .../rust-analyzer/crates/syntax/rust.ungram | 8 +- .../rust-analyzer/crates/syntax/src/ast.rs | 3 +- .../crates/syntax/src/ast/edit_in_place.rs | 36 +------ .../crates/syntax/src/ast/generated/nodes.rs | 97 +------------------ .../crates/syntax/src/ast/node_ext.rs | 45 --------- .../xtask/src/codegen/grammar.rs | 1 - 74 files changed, 68 insertions(+), 577 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 53250510f875c..b4fcfa11aea74 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -554,7 +554,6 @@ impl AttrsWithOwner { AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it), }, AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it), - AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::MacroId(it) => match it { MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it), MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it), @@ -659,7 +658,6 @@ impl AttrsWithOwner { AttrDefId::StaticId(id) => any_has_attrs(db, id), AttrDefId::ConstId(id) => any_has_attrs(db, id), AttrDefId::TraitId(id) => any_has_attrs(db, id), - AttrDefId::TraitAliasId(id) => any_has_attrs(db, id), AttrDefId::TypeAliasId(id) => any_has_attrs(db, id), AttrDefId::MacroId(id) => match id { MacroId::Macro2Id(id) => any_has_attrs(db, id), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index c67bb2422ac65..4e1d598623abe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -15,8 +15,8 @@ use crate::{ EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, - ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, - TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, + TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attr::{Attrs, AttrsWithOwner}, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, @@ -28,7 +28,7 @@ use crate::{ nameres::crate_def_map, signatures::{ ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, - StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature, + StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, }, tt, visibility::{self, Visibility}, @@ -69,9 +69,6 @@ pub trait InternDatabase: RootQueryDb { #[salsa::interned] fn intern_trait(&self, loc: TraitLoc) -> TraitId; - #[salsa::interned] - fn intern_trait_alias(&self, loc: TraitAliasLoc) -> TraitAliasId; - #[salsa::interned] fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; @@ -152,11 +149,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { self.function_signature_with_source_map(e).0 } - #[salsa::tracked] - fn trait_alias_signature(&self, e: TraitAliasId) -> Arc { - self.trait_alias_signature_with_source_map(e).0 - } - #[salsa::tracked] fn type_alias_signature(&self, e: TypeAliasId) -> Arc { self.type_alias_signature_with_source_map(e).0 @@ -210,12 +202,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { e: FunctionId, ) -> (Arc, Arc); - #[salsa::invoke(TraitAliasSignature::query)] - fn trait_alias_signature_with_source_map( - &self, - e: TraitAliasId, - ) -> (Arc, Arc); - #[salsa::invoke(TypeAliasSignature::query)] fn type_alias_signature_with_source_map( &self, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs index 20018b61e5cc0..7d3a94b038330 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs @@ -33,8 +33,8 @@ pub mod keys { use crate::{ BlockId, ConstId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, - ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId, + ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitId, + TypeAliasId, TypeOrConstParamId, UnionId, UseId, dyn_map::{DynMap, Policy}, }; @@ -48,7 +48,6 @@ pub mod keys { pub const IMPL: Key = Key::new(); pub const EXTERN_BLOCK: Key = Key::new(); pub const TRAIT: Key = Key::new(); - pub const TRAIT_ALIAS: Key = Key::new(); pub const STRUCT: Key = Key::new(); pub const UNION: Key = Key::new(); pub const ENUM: Key = Key::new(); 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 3b9281ffb9c12..3794cb18e9360 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 @@ -33,7 +33,7 @@ use tt::TextRange; use crate::{ AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, - ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, + ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, builtin_type::BuiltinUint, db::DefDatabase, expr_store::{ @@ -252,28 +252,6 @@ pub(crate) fn lower_trait( (store, source_map, params) } -pub(crate) fn lower_trait_alias( - db: &dyn DefDatabase, - module: ModuleId, - trait_syntax: InFile, - trait_id: TraitAliasId, -) -> (ExpressionStore, ExpressionStoreSourceMap, Arc) { - let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id); - let mut collector = generics::GenericParamsCollector::with_self_param( - &mut expr_collector, - trait_id.into(), - trait_syntax.value.type_bound_list(), - ); - collector.lower( - &mut expr_collector, - trait_syntax.value.generic_param_list(), - trait_syntax.value.where_clause(), - ); - let params = collector.finish(); - let (store, source_map) = expr_collector.store.finish(); - (store, source_map, params) -} - pub(crate) fn lower_type_alias( db: &dyn DefDatabase, module: ModuleId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index b81dcc1fe96df..5b9da3c5e6680 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -183,7 +183,6 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi } GenericDefId::ImplId(id) => format!("unimplemented {id:?}"), GenericDefId::StaticId(id) => format!("unimplemented {id:?}"), - GenericDefId::TraitAliasId(id) => format!("unimplemented {id:?}"), GenericDefId::TraitId(id) => format!("unimplemented {id:?}"), GenericDefId::TypeAliasId(id) => format!("unimplemented {id:?}"), } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs index efb558a775816..b68674c7a74f4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs @@ -24,7 +24,6 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe ModuleDefId::ConstId(id) => id.into(), ModuleDefId::StaticId(id) => id.into(), ModuleDefId::TraitId(id) => id.into(), - ModuleDefId::TraitAliasId(id) => id.into(), ModuleDefId::TypeAliasId(id) => id.into(), ModuleDefId::EnumVariantId(_) => continue, ModuleDefId::BuiltinType(_) => continue, @@ -51,7 +50,6 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe GenericDefId::ImplId(_id) => (), GenericDefId::StaticId(_id) => (), - GenericDefId::TraitAliasId(_id) => (), GenericDefId::TraitId(_id) => (), GenericDefId::TypeAliasId(_id) => (), } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 94e683cb0f8fa..60cd66bf6b082 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -203,9 +203,6 @@ impl GenericParams { } GenericDefId::ImplId(impl_id) => db.impl_signature(impl_id).generic_params.clone(), GenericDefId::StaticId(_) => EMPTY.clone(), - GenericDefId::TraitAliasId(trait_alias_id) => { - db.trait_alias_signature(trait_alias_id).generic_params.clone() - } GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(), GenericDefId::TypeAliasId(type_alias_id) => { db.type_alias_signature(type_alias_id).generic_params.clone() @@ -246,10 +243,6 @@ impl GenericParams { let sig = db.static_signature(id); (EMPTY.clone(), sig.store.clone()) } - GenericDefId::TraitAliasId(id) => { - let sig = db.trait_alias_signature(id); - (sig.generic_params.clone(), sig.store.clone()) - } GenericDefId::TraitId(id) => { let sig = db.trait_signature(id); (sig.generic_params.clone(), sig.store.clone()) @@ -294,10 +287,6 @@ impl GenericParams { let (sig, sm) = db.static_signature_with_source_map(id); (EMPTY.clone(), sig.store.clone(), sm) } - GenericDefId::TraitAliasId(id) => { - let (sig, sm) = db.trait_alias_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } GenericDefId::TraitId(id) => { let (sig, sm) = db.trait_signature_with_source_map(id); (sig.generic_params.clone(), sig.store.clone(), sm) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 8f526d1a2369a..77ed664f4443d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -872,7 +872,6 @@ impl PerNs { PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob)) } ModuleDefId::TraitId(_) => PerNs::types(def, v, import), - ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import), ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import), ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import), ModuleDefId::MacroId(mac) => PerNs::macros(mac, v, import), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index c633339857492..f35df8d3a7e11 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -276,7 +276,6 @@ enum SmallModItem { Static(Static), Struct(Struct), Trait(Trait), - TraitAlias(TraitAlias), TypeAlias(TypeAlias), Union(Union), } @@ -404,7 +403,6 @@ ModItemId -> Static in small_data -> ast::Static, Struct in small_data -> ast::Struct, Trait in small_data -> ast::Trait, - TraitAlias in small_data -> ast::TraitAlias, TypeAlias in small_data -> ast::TypeAlias, Union in small_data -> ast::Union, Use in big_data -> ast::Use, @@ -583,12 +581,6 @@ pub struct Trait { pub(crate) visibility: RawVisibilityId, } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct TraitAlias { - pub name: Name, - pub(crate) visibility: RawVisibilityId, -} - #[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl {} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 032b287cd6a82..454e06399583c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -23,7 +23,7 @@ use crate::{ BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem, - Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, + Static, Struct, StructKind, Trait, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, }, }; @@ -134,7 +134,6 @@ impl<'a> Ctx<'a> { ast::Item::Const(ast) => self.lower_const(ast).into(), ast::Item::Module(ast) => self.lower_module(ast)?.into(), ast::Item::Trait(ast) => self.lower_trait(ast)?.into(), - ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(), ast::Item::Impl(ast) => self.lower_impl(ast).into(), ast::Item::Use(ast) => self.lower_use(ast)?.into(), ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(), @@ -267,19 +266,6 @@ impl<'a> Ctx<'a> { Some(ast_id) } - fn lower_trait_alias( - &mut self, - trait_alias_def: &ast::TraitAlias, - ) -> Option> { - let name = trait_alias_def.name()?.as_name(); - let visibility = self.lower_visibility(trait_alias_def); - let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); - - let alias = TraitAlias { name, visibility }; - self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias)); - Some(ast_id) - } - fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId { let ast_id = self.source_ast_id_map.ast_id(impl_def); // Note that trait impls don't get implicit `Self` unlike traits, because here they are a diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 696174cb072bf..94a6cce3ce33a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -8,7 +8,7 @@ use crate::{ item_tree::{ Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static, - Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, + Struct, Trait, TypeAlias, Union, Use, UseTree, UseTreeKind, }, visibility::RawVisibility, }; @@ -250,12 +250,6 @@ impl Printer<'_> { self.print_visibility(*visibility); w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } - ModItemId::TraitAlias(ast_id) => { - let TraitAlias { name, visibility } = &self.tree[ast_id]; - self.print_ast_id(ast_id.erase()); - self.print_visibility(*visibility); - wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); - } ModItemId::Impl(ast_id) => { let Impl {} = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index bdf8b453e2d65..1f5b1e023702f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -318,9 +318,6 @@ impl TraitId { } } -pub type TraitAliasLoc = ItemLoc; -impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); - type TypeAliasLoc = AssocItemLoc; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); @@ -742,7 +739,6 @@ pub enum ModuleDefId { ConstId(ConstId), StaticId(StaticId), TraitId(TraitId), - TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), MacroId(MacroId), @@ -756,7 +752,6 @@ impl_from!( ConstId, StaticId, TraitId, - TraitAliasId, TypeAliasId, BuiltinType for ModuleDefId @@ -862,7 +857,6 @@ pub enum GenericDefId { // More importantly, this completes the set of items that contain type references // which is to be used by the signature expression store in the future. StaticId(StaticId), - TraitAliasId(TraitAliasId), TraitId(TraitId), TypeAliasId(TypeAliasId), } @@ -872,7 +866,6 @@ impl_from!( FunctionId, ImplId, StaticId, - TraitAliasId, TraitId, TypeAliasId for GenericDefId @@ -902,7 +895,6 @@ impl GenericDefId { GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None), GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None), @@ -978,7 +970,6 @@ pub enum AttrDefId { StaticId(StaticId), ConstId(ConstId), TraitId(TraitId), - TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), MacroId(MacroId), ImplId(ImplId), @@ -997,7 +988,6 @@ impl_from!( ConstId, FunctionId, TraitId, - TraitAliasId, TypeAliasId, MacroId(Macro2Id, MacroRulesId, ProcMacroId), ImplId, @@ -1020,7 +1010,6 @@ impl TryFrom for AttrDefId { ModuleDefId::StaticId(it) => Ok(it.into()), ModuleDefId::TraitId(it) => Ok(it.into()), ModuleDefId::TypeAliasId(it) => Ok(it.into()), - ModuleDefId::TraitAliasId(id) => Ok(id.into()), ModuleDefId::MacroId(id) => Ok(id.into()), ModuleDefId::BuiltinType(_) => Err(()), } @@ -1266,7 +1255,6 @@ impl HasModule for GenericDefId { GenericDefId::FunctionId(it) => it.module(db), GenericDefId::AdtId(it) => it.module(db), GenericDefId::TraitId(it) => it.module(db), - GenericDefId::TraitAliasId(it) => it.module(db), GenericDefId::TypeAliasId(it) => it.module(db), GenericDefId::ImplId(it) => it.module(db), GenericDefId::ConstId(it) => it.module(db), @@ -1286,7 +1274,6 @@ impl HasModule for AttrDefId { AttrDefId::StaticId(it) => it.module(db), AttrDefId::ConstId(it) => it.module(db), AttrDefId::TraitId(it) => it.module(db), - AttrDefId::TraitAliasId(it) => it.module(db), AttrDefId::TypeAliasId(it) => it.module(db), AttrDefId::ImplId(it) => it.module(db), AttrDefId::ExternBlockId(it) => it.module(db), @@ -1316,7 +1303,6 @@ impl ModuleDefId { ModuleDefId::ConstId(id) => id.module(db), ModuleDefId::StaticId(id) => id.module(db), ModuleDefId::TraitId(id) => id.module(db), - ModuleDefId::TraitAliasId(id) => id.module(db), ModuleDefId::TypeAliasId(id) => id.module(db), ModuleDefId::MacroId(id) => id.module(db), ModuleDefId::BuiltinType(_) => return None, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 07210df887369..8d2a386de8ecc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -51,10 +51,18 @@ impl TraitItems { tr: TraitId, ) -> (TraitItems, DefDiagnostics) { let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db); + let ast_id_map = db.ast_id_map(ast_id.file_id); + let source = ast_id.with_value(ast_id_map.get(ast_id.value)).to_node(db); + if source.eq_token().is_some() { + // FIXME(trait-alias) probably needs special handling here + return ( + TraitItems { macro_calls: ThinVec::new(), items: Box::default() }, + DefDiagnostics::new(vec![]), + ); + } let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id); - let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); (TraitItems { macro_calls, items }, DefDiagnostics::new(diagnostics)) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 267c4451b9d71..07e61718222bf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -30,7 +30,7 @@ use crate::{ ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, - StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc, + StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc, attr::Attrs, db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, @@ -1954,20 +1954,6 @@ impl ModCollector<'_, '_> { false, ); } - ModItemId::TraitAlias(id) => { - let it = &self.item_tree[id]; - - let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); - update_def( - self.def_collector, - TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) } - .intern(db) - .into(), - &it.name, - vis, - false, - ); - } ModItemId::TypeAlias(id) => { let it = &self.item_tree[id]; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index a10990e6a8f9f..698292c2fbea4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -20,7 +20,7 @@ use crate::{ EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, + TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -105,7 +105,6 @@ pub enum TypeNs { TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), TraitId(TraitId), - TraitAliasId(TraitAliasId), ModuleId(ModuleId), } @@ -1150,7 +1149,6 @@ impl<'db> ModuleItemMap<'db> { let ty = match def.def { ModuleDefId::AdtId(it) => TypeNs::AdtId(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), @@ -1195,7 +1193,6 @@ fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> { ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) | ModuleDefId::TraitId(_) - | ModuleDefId::TraitAliasId(_) | ModuleDefId::TypeAliasId(_) | ModuleDefId::BuiltinType(_) | ModuleDefId::MacroId(_) @@ -1214,7 +1211,6 @@ fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option)> { ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::ModuleId(it) => TypeNs::ModuleId(it), @@ -1320,12 +1316,6 @@ impl HasResolver for TraitId { } } -impl HasResolver for TraitAliasId { - fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { - lookup_resolver(db, self).push_generic_params_scope(db, self.into()) - } -} - impl + Copy> HasResolver for T { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { let def = self.into(); @@ -1410,7 +1400,6 @@ impl HasResolver for GenericDefId { GenericDefId::FunctionId(inner) => inner.resolver(db), GenericDefId::AdtId(adt) => adt.resolver(db), GenericDefId::TraitId(inner) => inner.resolver(db), - GenericDefId::TraitAliasId(inner) => inner.resolver(db), GenericDefId::TypeAliasId(inner) => inner.resolver(db), GenericDefId::ImplId(inner) => inner.resolver(db), GenericDefId::ConstId(inner) => inner.resolver(db), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 598b2c0314a94..906c1c0e9ff14 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -20,15 +20,13 @@ use triomphe::Arc; use crate::{ ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId, - ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, - VariantId, + ItemContainerId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, attr::Attrs, db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, lower::{ - ExprCollector, lower_function, lower_generic_params, lower_trait, lower_trait_alias, - lower_type_alias, + ExprCollector, lower_function, lower_generic_params, lower_trait, lower_type_alias, }, }, hir::{ExprId, PatId, generics::GenericParams}, @@ -469,31 +467,6 @@ impl TraitSignature { } } -#[derive(Debug, PartialEq, Eq)] -pub struct TraitAliasSignature { - pub name: Name, - pub generic_params: Arc, - pub store: Arc, -} - -impl TraitAliasSignature { - pub fn query( - db: &dyn DefDatabase, - id: TraitAliasId, - ) -> (Arc, Arc) { - let loc = id.lookup(db); - - let source = loc.source(db); - let name = as_name_opt(source.value.name()); - let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id); - - ( - Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }), - Arc::new(source_map), - ) - } -} - bitflags! { #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] pub struct FnFlags: u16 { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index aa373a27b0d52..367b543cf9080 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -71,7 +71,7 @@ impl HasChildSource> for UseId { } impl HasChildSource for GenericDefId { - type Value = Either; + type Value = Either; fn child_source( &self, db: &dyn DefDatabase, @@ -89,12 +89,7 @@ impl HasChildSource for GenericDefId { GenericDefId::TraitId(id) => { let trait_ref = id.lookup(db).source(db).value; let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref))); - } - GenericDefId::TraitAliasId(id) => { - let alias = id.lookup(db).source(db).value; - let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias))); + params.insert(idx, Either::Right(trait_ref)); } _ => {} } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index e6470e5272d05..412b3ac425028 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -273,7 +273,7 @@ impl Generics { pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option { match def { - GenericDefId::TraitId(_) | GenericDefId::TraitAliasId(_) => { + GenericDefId::TraitId(_) => { let params = db.generic_params(def); params.trait_self_param().map(|idx| idx.into_raw().into_u32() as usize) } @@ -295,8 +295,7 @@ pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Opt GenericDefId::StaticId(_) | GenericDefId::AdtId(_) | GenericDefId::TraitId(_) - | GenericDefId::ImplId(_) - | GenericDefId::TraitAliasId(_) => return None, + | GenericDefId::ImplId(_) => return None, }; match container { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 7a11ec660d04b..d778cc0e30ed4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1790,7 +1790,6 @@ impl<'db> InferenceContext<'db> { TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) - | TypeNs::TraitAliasId(_) | TypeNs::ModuleId(_) => { // FIXME diagnostic (self.err_ty(), None) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 9519c38eeddfd..fb85909d7f41e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -220,10 +220,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { }; return (ty, None); } - TypeNs::TraitAliasId(_) => { - // FIXME(trait_alias): Implement trait alias. - return (TyKind::Error.intern(Interner), None); - } TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode { ParamLoweringMode::Placeholder => { TyKind::Placeholder(to_placeholder_idx(self.ctx.db, param_id.into())) @@ -311,8 +307,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { TypeNs::AdtId(_) | TypeNs::EnumVariantId(_) | TypeNs::TypeAliasId(_) - | TypeNs::TraitId(_) - | TypeNs::TraitAliasId(_) => {} + | TypeNs::TraitId(_) => {} } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index fc31973022bdd..c5f78e2f3cecb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -9,6 +9,7 @@ mod never_type; mod patterns; mod regression; mod simple; +mod trait_aliases; mod traits; mod type_alias_impl_traits; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 08a215fecf623..d8a058533f761 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -990,7 +990,6 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); ModuleDefId::AdtId(it) => it.into(), ModuleDefId::ConstId(it) => it.into(), ModuleDefId::TraitId(it) => it.into(), - ModuleDefId::TraitAliasId(it) => it.into(), ModuleDefId::TypeAliasId(it) => it.into(), _ => return, }) @@ -1021,10 +1020,6 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); let loc = it.lookup(&db); loc.source(&db).value.name().unwrap() } - GenericDefId::TraitAliasId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } GenericDefId::TypeAliasId(it) => { let loc = it.lookup(&db); loc.source(&db).value.name().unwrap() diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index c8645b6282392..928753ef0edeb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -19,7 +19,7 @@ use hir_ty::{db::HirDatabase, method_resolution}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, Field, Function, GenericParam, HasCrate, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, - Struct, Trait, TraitAlias, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, }; pub trait HasAttrs { @@ -48,7 +48,6 @@ impl_has_attrs![ (Static, StaticId), (Const, ConstId), (Trait, TraitId), - (TraitAlias, TraitAliasId), (TypeAlias, TypeAliasId), (Macro, MacroId), (Function, FunctionId), @@ -137,7 +136,6 @@ fn resolve_doc_path_on_( AttrDefId::StaticId(it) => it.resolver(db), AttrDefId::ConstId(it) => it.resolver(db), AttrDefId::TraitId(it) => it.resolver(db), - AttrDefId::TraitAliasId(it) => it.resolver(db), AttrDefId::TypeAliasId(it) => it.resolver(db), AttrDefId::ImplId(it) => it.resolver(db), AttrDefId::ExternBlockId(it) => it.resolver(db), @@ -216,10 +214,6 @@ fn resolve_assoc_or_field( DocLinkDef::ModuleDef(def) }); } - TypeNs::TraitAliasId(_) => { - // XXX: Do these get resolved? - return None; - } TypeNs::ModuleId(_) => { return None; } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 2960ebedf3806..b9c5131ffbb55 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -23,8 +23,8 @@ use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, - Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitAlias, TraitRef, TupleField, - TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, + Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, TyBuilder, + Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -751,6 +751,7 @@ impl HirDisplay for TraitRef<'_> { impl HirDisplay for Trait { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + // FIXME(trait-alias) needs special handling to print the equal sign write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); let has_where_clause = write_where_clause(def_id, f)?; @@ -802,22 +803,6 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi Ok(()) } -impl HirDisplay for TraitAlias { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.trait_alias_signature(self.id); - write!(f, "trait {}", data.name.display(f.db, f.edition()))?; - let def_id = GenericDefId::TraitAliasId(self.id); - write_generic_params(def_id, f)?; - f.write_str(" = ")?; - // FIXME: Currently we lower every bounds in a trait alias as a trait bound on `Self` i.e. - // `trait Foo = Bar` is stored and displayed as `trait Foo = where Self: Bar`, which might - // be less readable. - write_where_clause(def_id, f)?; - Ok(()) - } -} - impl HirDisplay for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index c6446693df3e4..bc025c5ef5cf1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -37,7 +37,6 @@ from_id![ (hir_def::EnumId, crate::Enum), (hir_def::TypeAliasId, crate::TypeAlias), (hir_def::TraitId, crate::Trait), - (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), (hir_def::FunctionId, crate::Function), @@ -113,7 +112,6 @@ impl From for ModuleDef { ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), - ModuleDefId::TraitAliasId(it) => ModuleDef::TraitAlias(it.into()), ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it.into()), ModuleDefId::MacroId(it) => ModuleDef::Macro(it.into()), @@ -131,7 +129,6 @@ impl From for ModuleDefId { ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()), ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()), - ModuleDef::TraitAlias(it) => ModuleDefId::TraitAliasId(it.into()), ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()), ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()), ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()), @@ -177,7 +174,6 @@ impl From for GenericDefId { GenericDef::Function(it) => GenericDefId::FunctionId(it.id), GenericDef::Adt(it) => GenericDefId::AdtId(it.into()), GenericDef::Trait(it) => GenericDefId::TraitId(it.id), - GenericDef::TraitAlias(it) => GenericDefId::TraitAliasId(it.id), GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), GenericDef::Impl(it) => GenericDefId::ImplId(it.id), GenericDef::Const(it) => GenericDefId::ConstId(it.id), @@ -192,7 +188,6 @@ impl From for GenericDef { GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), - GenericDefId::TraitAliasId(it) => GenericDef::TraitAlias(it.into()), GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), GenericDefId::ConstId(it) => GenericDef::Const(it.into()), diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 4767d4792e718..ae82275e38736 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -14,8 +14,7 @@ use tt::TextRange; use crate::{ Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, - Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, - db::HirDatabase, + Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase, }; pub trait HasSource { @@ -168,12 +167,6 @@ impl HasSource for Trait { Some(self.id.lookup(db).source(db)) } } -impl HasSource for TraitAlias { - type Ast = ast::TraitAlias; - fn source(self, db: &dyn HirDatabase) -> Option> { - Some(self.id.lookup(db).source(db)) - } -} impl HasSource for TypeAlias { type Ast = ast::TypeAlias; fn source(self, db: &dyn HirDatabase) -> Option> { @@ -202,7 +195,7 @@ impl HasSource for Impl { } impl HasSource for TypeOrConstParam { - type Ast = Either; + type Ast = Either; fn source(self, db: &dyn HirDatabase) -> Option> { let child_source = self.id.parent.child_source(db); child_source.map(|it| it.get(self.id.local_id).cloned()).transpose() diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 475906ae51a11..4eb50c1c31c52 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -52,7 +52,7 @@ use hir_def::{ CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, SyntheticSyntax, - TraitAliasId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, @@ -333,7 +333,6 @@ pub enum ModuleDef { Const(Const), Static(Static), Trait(Trait), - TraitAlias(TraitAlias), TypeAlias(TypeAlias), BuiltinType(BuiltinType), Macro(Macro), @@ -346,7 +345,6 @@ impl_from!( Const, Static, Trait, - TraitAlias, TypeAlias, BuiltinType, Macro @@ -373,7 +371,6 @@ impl ModuleDef { ModuleDef::Const(it) => Some(it.module(db)), ModuleDef::Static(it) => Some(it.module(db)), ModuleDef::Trait(it) => Some(it.module(db)), - ModuleDef::TraitAlias(it) => Some(it.module(db)), ModuleDef::TypeAlias(it) => Some(it.module(db)), ModuleDef::Macro(it) => Some(it.module(db)), ModuleDef::BuiltinType(_) => None, @@ -402,7 +399,6 @@ impl ModuleDef { ModuleDef::Const(it) => it.name(db)?, ModuleDef::Adt(it) => it.name(db), ModuleDef::Trait(it) => it.name(db), - ModuleDef::TraitAlias(it) => it.name(db), ModuleDef::Function(it) => it.name(db), ModuleDef::Variant(it) => it.name(db), ModuleDef::TypeAlias(it) => it.name(db), @@ -425,7 +421,6 @@ impl ModuleDef { Adt::Union(it) => it.id.into(), }, ModuleDef::Trait(it) => it.id.into(), - ModuleDef::TraitAlias(it) => it.id.into(), ModuleDef::Function(it) => it.id.into(), ModuleDef::TypeAlias(it) => it.id.into(), ModuleDef::Module(it) => it.id.into(), @@ -465,7 +460,6 @@ impl ModuleDef { ModuleDef::Module(_) | ModuleDef::Adt(_) | ModuleDef::Trait(_) - | ModuleDef::TraitAlias(_) | ModuleDef::TypeAlias(_) | ModuleDef::Macro(_) | ModuleDef::BuiltinType(_) => None, @@ -478,7 +472,6 @@ impl ModuleDef { ModuleDef::Function(it) => Some(it.into()), ModuleDef::Adt(it) => Some(it.into()), ModuleDef::Trait(it) => Some(it.into()), - ModuleDef::TraitAlias(it) => Some(it.into()), ModuleDef::TypeAlias(it) => Some(it.into()), ModuleDef::Module(_) | ModuleDef::Variant(_) @@ -498,7 +491,6 @@ impl ModuleDef { ModuleDef::Const(it) => it.attrs(db), ModuleDef::Static(it) => it.attrs(db), ModuleDef::Trait(it) => it.attrs(db), - ModuleDef::TraitAlias(it) => it.attrs(db), ModuleDef::TypeAlias(it) => it.attrs(db), ModuleDef::Macro(it) => it.attrs(db), ModuleDef::BuiltinType(_) => return None, @@ -524,7 +516,6 @@ impl HasVisibility for ModuleDef { ModuleDef::Const(it) => it.visibility(db), ModuleDef::Static(it) => it.visibility(db), ModuleDef::Trait(it) => it.visibility(db), - ModuleDef::TraitAlias(it) => it.visibility(db), ModuleDef::TypeAlias(it) => it.visibility(db), ModuleDef::Variant(it) => it.visibility(db), ModuleDef::Macro(it) => it.visibility(db), @@ -3045,29 +3036,6 @@ impl HasVisibility for Trait { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TraitAlias { - pub(crate) id: TraitAliasId, -} - -impl TraitAlias { - pub fn module(self, db: &dyn HirDatabase) -> Module { - Module { id: self.id.lookup(db).container } - } - - pub fn name(self, db: &dyn HirDatabase) -> Name { - db.trait_alias_signature(self.id).name.clone() - } -} - -impl HasVisibility for TraitAlias { - fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - let loc = self.id.lookup(db); - let source = loc.source(db); - visibility_from_ast(db, self.id, source.map(|src| src.visibility())) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TypeAlias { pub(crate) id: TypeAliasId, @@ -3690,7 +3658,6 @@ pub enum GenericDef { Function(Function), Adt(Adt), Trait(Trait), - TraitAlias(TraitAlias), TypeAlias(TypeAlias), Impl(Impl), // consts can have type parameters from their parents (i.e. associated consts of traits) @@ -3701,7 +3668,6 @@ impl_from!( Function, Adt(Struct, Enum, Union), Trait, - TraitAlias, TypeAlias, Impl, Const, @@ -3751,7 +3717,6 @@ impl GenericDef { GenericDef::Function(it) => it.id.into(), GenericDef::Adt(it) => it.into(), GenericDef::Trait(it) => it.id.into(), - GenericDef::TraitAlias(it) => it.id.into(), GenericDef::TypeAlias(it) => it.id.into(), GenericDef::Impl(it) => it.id.into(), GenericDef::Const(it) => it.id.into(), @@ -3776,7 +3741,6 @@ impl GenericDef { GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1, GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1, GenericDefId::StaticId(_) => return, - GenericDefId::TraitAliasId(it) => db.trait_alias_signature_with_source_map(it).1, GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1, GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1, }; @@ -3813,7 +3777,6 @@ impl GenericDef { GenericDef::Adt(Adt::Enum(_)) => "enum", GenericDef::Adt(Adt::Union(_)) => "union", GenericDef::Trait(_) => "trait", - GenericDef::TraitAlias(_) => "trait alias", GenericDef::TypeAlias(_) => "type alias", GenericDef::Impl(_) => "impl", GenericDef::Const(_) => "constant", @@ -6401,12 +6364,6 @@ impl HasCrate for Trait { } } -impl HasCrate for TraitAlias { - fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() - } -} - impl HasCrate for Static { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.module(db).krate() @@ -6500,12 +6457,6 @@ impl HasContainer for Trait { } } -impl HasContainer for TraitAlias { - fn container(&self, db: &dyn HirDatabase) -> ItemContainer { - ItemContainer::Module(Module { id: self.id.lookup(db).container }) - } -} - impl HasContainer for ExternBlock { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { ItemContainer::Module(Module { id: self.id.lookup(db).container }) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 05f06f97fdc26..b43165fd8ad70 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -46,8 +46,8 @@ use crate::{ Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, - Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField, - Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TupleField, Type, + TypeAlias, TypeParam, Union, Variant, VariantDef, db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{SourceAnalyzer, name_hygiene, resolve_hir_path}, @@ -85,8 +85,7 @@ impl PathResolution { | ModuleDef::Function(_) | ModuleDef::Module(_) | ModuleDef::Static(_) - | ModuleDef::Trait(_) - | ModuleDef::TraitAlias(_), + | ModuleDef::Trait(_), ) => None, PathResolution::Def(ModuleDef::TypeAlias(alias)) => { Some(TypeNs::TypeAliasId((*alias).into())) @@ -343,10 +342,6 @@ impl Semantics<'_, DB> { self.imp.to_def(s) } - pub fn to_trait_alias_def(&self, t: &ast::TraitAlias) -> Option { - self.imp.to_def(t) - } - pub fn to_trait_def(&self, t: &ast::Trait) -> Option { self.imp.to_def(t) } @@ -2138,7 +2133,6 @@ to_def_impls![ (crate::Enum, ast::Enum, enum_to_def), (crate::Union, ast::Union, union_to_def), (crate::Trait, ast::Trait, trait_to_def), - (crate::TraitAlias, ast::TraitAlias, trait_alias_to_def), (crate::Impl, ast::Impl, impl_to_def), (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), (crate::Const, ast::Const, const_to_def), diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index e7db93d375d33..5019a5987e513 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -154,9 +154,6 @@ impl ChildBySource for ItemScope { } ModuleDefId::StaticId(id) => insert_item_loc(db, map, file_id, id, keys::STATIC), ModuleDefId::TraitId(id) => insert_item_loc(db, map, file_id, id, keys::TRAIT), - ModuleDefId::TraitAliasId(id) => { - insert_item_loc(db, map, file_id, id, keys::TRAIT_ALIAS) - } ModuleDefId::AdtId(adt) => match adt { AdtId::StructId(id) => insert_item_loc(db, map, file_id, id, keys::STRUCT), AdtId::UnionId(id) => insert_item_loc(db, map, file_id, id, keys::UNION), diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 71ee0f6938960..44df4d8fc8c80 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -89,8 +89,8 @@ use either::Either; use hir_def::{ AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, - Lookup, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, - UnionId, UseId, VariantId, + Lookup, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, + UseId, VariantId, dyn_map::{ DynMap, keys::{self, Key}, @@ -252,12 +252,6 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn trait_to_def(&mut self, src: InFile<&ast::Trait>) -> Option { self.to_def(src, keys::TRAIT) } - pub(super) fn trait_alias_to_def( - &mut self, - src: InFile<&ast::TraitAlias>, - ) -> Option { - self.to_def(src, keys::TRAIT_ALIAS) - } pub(super) fn impl_to_def(&mut self, src: InFile<&ast::Impl>) -> Option { self.to_def(src, keys::IMPL) } @@ -555,9 +549,6 @@ impl SourceToDefCtx<'_, '_> { } ast::Item::Enum(it) => this.enum_to_def(InFile::new(file_id, it)).map(Into::into), ast::Item::Trait(it) => this.trait_to_def(InFile::new(file_id, it)).map(Into::into), - ast::Item::TraitAlias(it) => { - this.trait_alias_to_def(InFile::new(file_id, it)).map(Into::into) - } ast::Item::TypeAlias(it) => { this.type_alias_to_def(InFile::new(file_id, it)).map(Into::into) } @@ -636,9 +627,6 @@ impl SourceToDefCtx<'_, '_> { ast::Item::TypeAlias(it) => ChildContainer::GenericDefId( self.type_alias_to_def(container.with_value(it))?.into(), ), - ast::Item::TraitAlias(it) => ChildContainer::GenericDefId( - self.trait_alias_to_def(container.with_value(it))?.into(), - ), ast::Item::Struct(it) => { let def = self.struct_to_def(container.with_value(it))?; let is_in_body = it.field_list().is_some_and(|it| { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index d25fb1d8cdb7e..126392af4619a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -10,7 +10,7 @@ use std::iter::{self, once}; use crate::{ Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, - TraitAlias, TupleField, Type, TypeAlias, Variant, + TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -1587,7 +1587,6 @@ fn resolve_hir_path_( TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), - TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())), }; match unresolved { @@ -1737,7 +1736,6 @@ fn resolve_hir_path_qualifier( TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), - TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), TypeNs::ModuleId(it) => PathResolution::Def(ModuleDef::Module(it.into())), }; match unresolved { diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index dca10193e29bf..d8c624e5c6896 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -148,9 +148,6 @@ impl<'a> SymbolCollector<'a> { let trait_do_not_complete = this.push_decl(id, name, false, None); this.collect_from_trait(id, trait_do_not_complete); } - ModuleDefId::TraitAliasId(id) => { - this.push_decl(id, name, false, None); - } ModuleDefId::TypeAliasId(id) => { this.push_decl(id, name, false, None); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index e783b8693456c..dad19bfb8a2c8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -613,7 +613,6 @@ impl Module { | Definition::Const(_) | Definition::Static(_) | Definition::Trait(_) - | Definition::TraitAlias(_) | Definition::TypeAlias(_) ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs index 3badc17d01af4..55de537debf3d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs @@ -136,10 +136,6 @@ fn target_data_for_def( target_name = Some(t.name(db)); offset_target_and_file_id(db, t)? } - hir::ModuleDef::TraitAlias(t) => { - target_name = Some(t.name(db)); - offset_target_and_file_id(db, t)? - } hir::ModuleDef::TypeAlias(t) => { target_name = Some(t.name(db)); offset_target_and_file_id(db, t)? diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs index a9df6f6fc3669..e5425abab097a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs @@ -55,7 +55,6 @@ pub(crate) fn move_bounds_to_where_clause( match parent { ast::Fn(it) => it.get_or_create_where_clause(), ast::Trait(it) => it.get_or_create_where_clause(), - ast::TraitAlias(it) => it.get_or_create_where_clause(), ast::Impl(it) => it.get_or_create_where_clause(), ast::Enum(it) => it.get_or_create_where_clause(), ast::Struct(it) => it.get_or_create_where_clause(), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index 7c38c7d8ce44f..fc27cbd65a1ee 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -37,9 +37,7 @@ pub(crate) fn complete_type_path( true } // Type things are fine - ScopeDef::ModuleDef( - BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TraitAlias(_) | TypeAlias(_), - ) + ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_)) | ScopeDef::AdtSelfType(_) | ScopeDef::Unknown | ScopeDef::GenericParam(TypeParam(_)) => location.complete_types(), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index cfd7f80d40b30..28c00cde126ca 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -525,7 +525,6 @@ impl CompletionContext<'_> { hir::ModuleDef::Const(it) => self.is_visible(it), hir::ModuleDef::Static(it) => self.is_visible(it), hir::ModuleDef::Trait(it) => self.is_visible(it), - hir::ModuleDef::TraitAlias(it) => self.is_visible(it), hir::ModuleDef::TypeAlias(it) => self.is_visible(it), hir::ModuleDef::Macro(it) => self.is_visible(it), hir::ModuleDef::BuiltinType(_) => Visible::Yes, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 9d246017131a0..23db63c1a95fe 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1037,9 +1037,6 @@ fn classify_name_ref<'db>( sema.source(trait_)?.value.generic_param_list() } } - hir::ModuleDef::TraitAlias(trait_) => { - sema.source(trait_)?.value.generic_param_list() - } hir::ModuleDef::TypeAlias(ty_) => { sema.source(ty_)?.value.generic_param_list() } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index f27cd07816657..5fb9dc93c93da 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -399,7 +399,6 @@ impl CompletionItemKind { SymbolKind::Struct => "st", SymbolKind::ToolModule => "tm", SymbolKind::Trait => "tt", - SymbolKind::TraitAlias => "tr", SymbolKind::TypeAlias => "ta", SymbolKind::TypeParam => "tp", SymbolKind::Union => "un", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 3d7a4067c2cd0..7d23f9d14c66f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -486,10 +486,7 @@ fn render_resolution_path( | ScopeDef::Label(_) | ScopeDef::Unknown | ScopeDef::ModuleDef( - ModuleDef::Trait(_) - | ModuleDef::TraitAlias(_) - | ModuleDef::Module(_) - | ModuleDef::TypeAlias(_), + ModuleDef::Trait(_) | ModuleDef::Module(_) | ModuleDef::TypeAlias(_), ) => (), }; @@ -542,9 +539,6 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static), ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait), - ScopeDef::ModuleDef(TraitAlias(..)) => { - CompletionItemKind::SymbolKind(SymbolKind::TraitAlias) - } ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias), ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 9edfc113f764c..4fb7d142ed5f1 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -125,7 +125,6 @@ pub fn generic_def_for_node( hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::TraitAlias(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => { variant = Some(it); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 2a4fcf6a2e5f7..61a21ccf2f775 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -16,7 +16,7 @@ use hir::{ ExternCrateDecl, Field, Function, GenericDef, GenericParam, GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, - TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, + TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use span::Edition; use stdx::{format_to, impl_from}; @@ -40,7 +40,6 @@ pub enum Definition { Const(Const), Static(Static), Trait(Trait), - TraitAlias(TraitAlias), TypeAlias(TypeAlias), SelfType(Impl), GenericParam(GenericParam), @@ -83,7 +82,6 @@ impl Definition { Definition::Const(it) => it.module(db), Definition::Static(it) => it.module(db), Definition::Trait(it) => it.module(db), - Definition::TraitAlias(it) => it.module(db), Definition::TypeAlias(it) => it.module(db), Definition::Variant(it) => it.module(db), Definition::SelfType(it) => it.module(db), @@ -122,7 +120,6 @@ impl Definition { Definition::Const(it) => container_to_definition(it.container(db)), Definition::Static(it) => container_to_definition(it.container(db)), Definition::Trait(it) => container_to_definition(it.container(db)), - Definition::TraitAlias(it) => container_to_definition(it.container(db)), Definition::TypeAlias(it) => container_to_definition(it.container(db)), Definition::Variant(it) => Some(Adt::Enum(it.parent_enum(db)).into()), Definition::SelfType(it) => Some(it.module(db).into()), @@ -151,7 +148,6 @@ impl Definition { Definition::Const(it) => it.visibility(db), Definition::Static(it) => it.visibility(db), Definition::Trait(it) => it.visibility(db), - Definition::TraitAlias(it) => it.visibility(db), Definition::TypeAlias(it) => it.visibility(db), Definition::Variant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), @@ -185,7 +181,6 @@ impl Definition { Definition::Const(it) => it.name(db)?, Definition::Static(it) => it.name(db), Definition::Trait(it) => it.name(db), - Definition::TraitAlias(it) => it.name(db), Definition::TypeAlias(it) => it.name(db), Definition::BuiltinType(it) => it.name(), Definition::TupleField(it) => it.name(), @@ -230,7 +225,6 @@ impl Definition { Definition::Const(it) => it.docs_with_rangemap(db), Definition::Static(it) => it.docs_with_rangemap(db), Definition::Trait(it) => it.docs_with_rangemap(db), - Definition::TraitAlias(it) => it.docs_with_rangemap(db), Definition::TypeAlias(it) => { it.docs_with_rangemap(db).or_else(|| { // docs are missing, try to fall back to the docs of the aliased item. @@ -321,7 +315,6 @@ impl Definition { Definition::Const(it) => it.display(db, display_target).to_string(), Definition::Static(it) => it.display(db, display_target).to_string(), Definition::Trait(it) => it.display(db, display_target).to_string(), - Definition::TraitAlias(it) => it.display(db, display_target).to_string(), Definition::TypeAlias(it) => it.display(db, display_target).to_string(), Definition::BuiltinType(it) => { it.name().display(db, display_target.edition).to_string() @@ -589,7 +582,6 @@ impl<'db> NameClass<'db> { ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?), ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?), ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?), - ast::Item::TraitAlias(it) => Definition::TraitAlias(sema.to_def(&it)?), ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?), ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)), ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)), @@ -895,7 +887,7 @@ impl<'db> NameRefClass<'db> { } impl_from!( - Field, Module, Function, Adt, Variant, Const, Static, Trait, TraitAlias, TypeAlias, BuiltinType, Local, + Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local, GenericParam, Label, Macro, ExternCrateDecl for Definition ); @@ -975,7 +967,6 @@ impl From for Definition { ModuleDef::Const(it) => Definition::Const(it), ModuleDef::Static(it) => Definition::Static(it), ModuleDef::Trait(it) => Definition::Trait(it), - ModuleDef::TraitAlias(it) => Definition::TraitAlias(it), ModuleDef::TypeAlias(it) => Definition::TypeAlias(it), ModuleDef::Macro(it) => Definition::Macro(it), ModuleDef::BuiltinType(it) => Definition::BuiltinType(it), @@ -1017,7 +1008,6 @@ impl From for Definition { GenericDef::Function(it) => it.into(), GenericDef::Adt(it) => it.into(), GenericDef::Trait(it) => it.into(), - GenericDef::TraitAlias(it) => it.into(), GenericDef::TypeAlias(it) => it.into(), GenericDef::Impl(it) => it.into(), GenericDef::Const(it) => it.into(), @@ -1033,7 +1023,6 @@ impl TryFrom for GenericDef { Definition::Function(it) => Ok(it.into()), Definition::Adt(it) => Ok(it.into()), Definition::Trait(it) => Ok(it.into()), - Definition::TraitAlias(it) => Ok(it.into()), Definition::TypeAlias(it) => Ok(it.into()), Definition::SelfType(it) => Ok(it.into()), Definition::Const(it) => Ok(it.into()), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index 30c355f8b3f93..cab19aadfd010 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -195,8 +195,7 @@ macro_rules! impl_has_docs { } impl_has_docs![ - Variant, Field, Static, Const, Trait, TraitAlias, TypeAlias, Macro, Function, Adt, Module, - Impl, Crate, + Variant, Field, Static, Const, Trait, TypeAlias, Macro, Function, Adt, Module, Impl, Crate, ]; macro_rules! impl_has_docs_enum { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 9f35988924b92..1012f993344fe 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -475,8 +475,6 @@ fn validate_resolvable( } // FIXME ModuleDef::Trait(_) => return None, - // FIXME - ModuleDef::TraitAlias(_) => return None, ModuleDef::TypeAlias(alias) => alias.ty(db), ModuleDef::BuiltinType(builtin) => builtin.ty(db), ModuleDef::Adt(adt) => adt.ty(db), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 49f7f63a04a42..1f074de4cd7d2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -273,7 +273,6 @@ pub enum SymbolKind { Struct, ToolModule, Trait, - TraitAlias, TypeAlias, TypeParam, Union, @@ -306,7 +305,6 @@ impl From for SymbolKind { hir::ModuleDef::Adt(hir::Adt::Enum(..)) => SymbolKind::Enum, hir::ModuleDef::Adt(hir::Adt::Union(..)) => SymbolKind::Union, hir::ModuleDef::Trait(..) => SymbolKind::Trait, - hir::ModuleDef::TraitAlias(..) => SymbolKind::TraitAlias, hir::ModuleDef::TypeAlias(..) => SymbolKind::TypeAlias, hir::ModuleDef::BuiltinType(..) => SymbolKind::TypeAlias, } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 424b27a398b20..a8800c142a22e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -163,7 +163,6 @@ impl Definition { Definition::Const(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Static(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Trait(it) => name_range(it, sema).and_then(syn_ctx_is_root), - Definition::TraitAlias(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::TypeAlias(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Local(it) => { name_range(it.primary_source(sema.db), sema).and_then(syn_ctx_is_root) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index abd4dc8300b39..f1d076e874d5c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -352,7 +352,6 @@ impl Definition { hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()), - hir::GenericDef::TraitAlias(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 9c4e6f5cbf82f..78ade30c7e3ed 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -357,7 +357,6 @@ impl Query { hir::ModuleDef::Adt(..) | hir::ModuleDef::TypeAlias(..) | hir::ModuleDef::BuiltinType(..) - | hir::ModuleDef::TraitAlias(..) | hir::ModuleDef::Trait(..) ); if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) { diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index d47cc65079384..c197d559aa89a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -225,7 +225,6 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), - Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Macro(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Field(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), @@ -671,11 +670,9 @@ fn filename_and_frag_for_def( None => String::from("index.html"), }, Definition::Trait(t) => { + // FIXME(trait-alias): url should be traitalias. for aliases format!("trait.{}.html", t.name(db).as_str()) } - Definition::TraitAlias(t) => { - format!("traitalias.{}.html", t.name(db).as_str()) - } Definition::TypeAlias(t) => { format!("type.{}.html", t.name(db).as_str()) } diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index ac15af0334fc8..d5c6eaca97448 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -162,7 +162,6 @@ fn structure_node(node: &SyntaxNode, config: &FileStructureConfig) -> Option decl(it, StructureNodeKind::SymbolKind(SymbolKind::Enum)), ast::Variant(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Variant)), ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), - ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)), ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), @@ -553,7 +552,7 @@ fn let_statements() { navigation_range: 251..256, node_range: 245..262, kind: SymbolKind( - TraitAlias, + Trait, ), detail: None, deprecated: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs index ac64413effebf..3969490e8dcf5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs @@ -29,7 +29,6 @@ pub enum FoldKind { Consts, Statics, TypeAliases, - TraitAliases, ExternCrates, // endregion: item runs } @@ -147,11 +146,6 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { res.push(Fold { range, kind: FoldKind::TypeAliases }) } }, - ast::TraitAlias(alias) => { - if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) { - res.push(Fold { range, kind: FoldKind::TraitAliases }) - } - }, ast::ExternCrate(extern_crate) => { if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) { res.push(Fold { range, kind: FoldKind::ExternCrates }) @@ -351,7 +345,6 @@ mod tests { FoldKind::ReturnType => "returntype", FoldKind::MatchArm => "matcharm", FoldKind::Function => "function", - FoldKind::TraitAliases => "traitaliases", FoldKind::ExternCrates => "externcrates", }; assert_eq!(kind, &attr.unwrap()); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 1c0272cdfacd1..e4c7d42ffe3b1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -401,7 +401,6 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) - Definition::GenericParam(generic_param) => match generic_param.parent() { hir::GenericDef::Adt(it) => Some(it.name(db)), hir::GenericDef::Trait(it) => Some(it.name(db)), - hir::GenericDef::TraitAlias(it) => Some(it.name(db)), hir::GenericDef::TypeAlias(it) => Some(it.name(db)), hir::GenericDef::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 795c1f2ca3c0b..f1aa03c8f2672 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -209,7 +209,6 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Definition::Const(..) => Constant, Definition::Static(..) => StaticVariable, Definition::Trait(..) => Trait, - Definition::TraitAlias(..) => Trait, Definition::TypeAlias(it) => { if it.as_assoc_item(db).is_some() { AssociatedType diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs index f3bb3df1cd8d7..b5d47c83a5543 100644 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs @@ -72,7 +72,6 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - SyntaxKind::MACRO_CALL, SyntaxKind::TYPE_ALIAS, SyntaxKind::TRAIT, - SyntaxKind::TRAIT_ALIAS, SyntaxKind::IMPL, SyntaxKind::MACRO_DEF, SyntaxKind::STRUCT, diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 7dc18141bdbc1..61b4de0e0e396 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -226,9 +226,6 @@ impl TryToNav for FileSymbol { hir::ModuleDef::Trait(it) => { Some(it.display(db, display_target).to_string()) } - hir::ModuleDef::TraitAlias(it) => { - Some(it.display(db, display_target).to_string()) - } hir::ModuleDef::TypeAlias(it) => { Some(it.display(db, display_target).to_string()) } @@ -261,7 +258,6 @@ impl TryToNav for Definition { Definition::Const(it) => it.try_to_nav(db), Definition::Static(it) => it.try_to_nav(db), Definition::Trait(it) => it.try_to_nav(db), - Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), Definition::ExternCrateDecl(it) => it.try_to_nav(db), Definition::InlineAsmOperand(it) => it.try_to_nav(db), @@ -287,7 +283,6 @@ impl TryToNav for hir::ModuleDef { hir::ModuleDef::Const(it) => it.try_to_nav(db), hir::ModuleDef::Static(it) => it.try_to_nav(db), hir::ModuleDef::Trait(it) => it.try_to_nav(db), - hir::ModuleDef::TraitAlias(it) => it.try_to_nav(db), hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), hir::ModuleDef::Macro(it) => it.try_to_nav(db), hir::ModuleDef::BuiltinType(_) => None, @@ -366,12 +361,6 @@ impl ToNavFromAst for hir::Trait { container_name(db, self, self.krate(db).edition(db)) } } -impl ToNavFromAst for hir::TraitAlias { - const KIND: SymbolKind = SymbolKind::TraitAlias; - fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self, self.krate(db).edition(db)) - } -} impl TryToNav for D where diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 86b88a17c75fc..dc509b3858389 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -1783,7 +1783,7 @@ trait Bar$0 = Foo where Self: ; fn foo(_: impl Bar, _: &dyn Bar) {} "#, expect![[r#" - Bar TraitAlias FileId(0) 13..42 19..22 + Bar Trait FileId(0) 13..42 19..22 FileId(0) 53..56 FileId(0) 66..69 diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 83e5c5ab1dfeb..77c84292cf3e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -493,7 +493,6 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { Definition::Const(it) => it.attrs(db), Definition::Static(it) => it.attrs(db), Definition::Trait(it) => it.attrs(db), - Definition::TraitAlias(it) => it.attrs(db), Definition::TypeAlias(it) => it.attrs(db), Definition::Macro(it) => it.attrs(db), Definition::SelfType(it) => it.attrs(db), diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 2cccb9639f3eb..86d02b4098bd2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -339,10 +339,6 @@ fn signature_help_for_generics( res.doc = it.docs(db); format_to!(res.signature, "trait {}", it.name(db).display(db, edition)); } - hir::GenericDef::TraitAlias(it) => { - res.doc = it.docs(db); - format_to!(res.signature, "trait {}", it.name(db).display(db, edition)); - } hir::GenericDef::TypeAlias(it) => { res.doc = it.docs(db); format_to!(res.signature, "type {}", it.name(db).display(db, edition)); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 8bde8fd970063..d73575fb9549a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -576,7 +576,6 @@ pub(super) fn highlight_def( h } Definition::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)), - Definition::TraitAlias(_) => Highlight::new(HlTag::Symbol(SymbolKind::TraitAlias)), Definition::TypeAlias(type_) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); @@ -780,7 +779,6 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { MACRO_RULES => SymbolKind::Macro, CONST_PARAM => SymbolKind::ConstParam, SELF_PARAM => SymbolKind::SelfParam, - TRAIT_ALIAS => SymbolKind::TraitAlias, ASM_OPERAND_NAMED => SymbolKind::Local, _ => return default.into(), }; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 7f5c2c1ec849b..fb33307249a77 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -311,7 +311,6 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::Const(_) => SymbolKind::Const, Definition::Static(_) => SymbolKind::Static, Definition::Trait(_) => SymbolKind::Trait, - Definition::TraitAlias(_) => SymbolKind::TraitAlias, Definition::TypeAlias(_) => SymbolKind::TypeAlias, Definition::BuiltinLifetime(_) => SymbolKind::LifetimeParam, Definition::BuiltinType(_) => return HlTag::BuiltinType, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index 3b5d1af0ac72a..4b8762640c743 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -160,7 +160,6 @@ impl HlTag { SymbolKind::Struct => "struct", SymbolKind::ToolModule => "tool_module", SymbolKind::Trait => "trait", - SymbolKind::TraitAlias => "trait_alias", SymbolKind::TypeAlias => "type_alias", SymbolKind::TypeParam => "type_param", SymbolKind::Union => "union", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index f7d798208037e..47ee2ad1c0d70 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -78,8 +78,8 @@ } use foo::bar as baz; -trait Bar = Baz; -trait Foo = Bar; +trait Bar = Baz; +trait Foo = Bar; fn main() { let a = '\n'; diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs index 47f86ce8c6cc4..c1b1a3fc8a94a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs @@ -20,7 +20,7 @@ pub(super) fn trait_(p: &mut Parser<'_>, m: Marker) { // trait Z = where Self: T; generic_params::opt_where_clause(p); p.expect(T![;]); - m.complete(p, TRAIT_ALIAS); + m.complete(p, TRAIT); return; } diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 3a8041d2df9ee..93e02a92abdad 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -284,7 +284,6 @@ pub enum SyntaxKind { STRUCT, TOKEN_TREE, TRAIT, - TRAIT_ALIAS, TRY_EXPR, TUPLE_EXPR, TUPLE_FIELD, @@ -457,7 +456,6 @@ impl SyntaxKind { | STRUCT | TOKEN_TREE | TRAIT - | TRAIT_ALIAS | TRY_EXPR | TUPLE_EXPR | TUPLE_FIELD diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias.rast index c45f870898007..2ef66484ae48f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias.rast @@ -1,5 +1,5 @@ SOURCE_FILE - TRAIT_ALIAS + TRAIT TRAIT_KW "trait" WHITESPACE " " NAME diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias_where_clause.rast index 8f678247731dc..4443d9d142630 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias_where_clause.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/trait_alias_where_clause.rast @@ -1,5 +1,5 @@ SOURCE_FILE - TRAIT_ALIAS + TRAIT TRAIT_KW "trait" WHITESPACE " " NAME @@ -50,7 +50,7 @@ SOURCE_FILE IDENT "Copy" SEMICOLON ";" WHITESPACE "\n" - TRAIT_ALIAS + TRAIT TRAIT_KW "trait" WHITESPACE " " NAME diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 292be1d5315de..d51ddb86d197f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -61,7 +61,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, SymbolKind::Enum => lsp_types::SymbolKind::ENUM, SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER, - SymbolKind::Trait | SymbolKind::TraitAlias => lsp_types::SymbolKind::INTERFACE, + SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE, SymbolKind::Macro | SymbolKind::ProcMacro | SymbolKind::BuiltinAttr @@ -156,7 +156,6 @@ pub(crate) fn completion_item_kind( SymbolKind::Static => lsp_types::CompletionItemKind::VALUE, SymbolKind::Struct => lsp_types::CompletionItemKind::STRUCT, SymbolKind::Trait => lsp_types::CompletionItemKind::INTERFACE, - SymbolKind::TraitAlias => lsp_types::CompletionItemKind::INTERFACE, SymbolKind::TypeAlias => lsp_types::CompletionItemKind::STRUCT, SymbolKind::TypeParam => lsp_types::CompletionItemKind::TYPE_PARAMETER, SymbolKind::Union => lsp_types::CompletionItemKind::STRUCT, @@ -817,7 +816,6 @@ fn semantic_token_type_and_modifiers( SymbolKind::Union => types::UNION, SymbolKind::TypeAlias => types::TYPE_ALIAS, SymbolKind::Trait => types::INTERFACE, - SymbolKind::TraitAlias => types::INTERFACE, SymbolKind::Macro => types::MACRO, SymbolKind::ProcMacro => types::PROC_MACRO, SymbolKind::BuiltinAttr => types::BUILTIN_ATTRIBUTE, @@ -909,7 +907,6 @@ pub(crate) fn folding_range( | FoldKind::WhereClause | FoldKind::ReturnType | FoldKind::Array - | FoldKind::TraitAliases | FoldKind::ExternCrates | FoldKind::MatchArm | FoldKind::Function => None, diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index a9288ecd6fa1f..e803747998b54 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -485,8 +485,7 @@ register_has_name_ast_id! { MacroRules = name, Module = name, Static = name, - Trait = name, - TraitAlias = name + Trait = name } macro_rules! register_assoc_item_ast_id { diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 6d8a360d715b7..d73d60c51f0c8 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -154,7 +154,6 @@ Item = | Static | Struct | Trait -| TraitAlias | TypeAlias | Union | Use @@ -306,11 +305,8 @@ Trait = Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList? - (':' TypeBoundList?)? WhereClause? AssocItemList - -TraitAlias = - Attr* Visibility? - 'trait' Name GenericParamList? '=' TypeBoundList? WhereClause? ';' + (((':' TypeBoundList?)? WhereClause? AssocItemList) | + ('=' TypeBoundList? WhereClause? ';')) AssocItemList = '{' Attr* AssocItem* '}' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index a9aeeedb6542e..19c1c5ebea333 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -26,8 +26,7 @@ pub use self::{ generated::{nodes::*, tokens::*}, node_ext::{ AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind, - SlicePatComponents, StructKind, TraitOrAlias, TypeBoundKind, TypeOrConstParam, - VisibilityKind, + SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind, }, operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix}, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 160f000387b3d..1cd8146f68630 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -99,38 +99,10 @@ impl GenericParamsOwnerEdit for ast::Trait { fn get_or_create_where_clause(&self) -> ast::WhereClause { if self.where_clause().is_none() { - let position = match self.assoc_item_list() { - Some(items) => Position::before(items.syntax()), - None => Position::last_child_of(self.syntax()), - }; - create_where_clause(position); - } - self.where_clause().unwrap() - } -} - -impl GenericParamsOwnerEdit for ast::TraitAlias { - fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { - match self.generic_param_list() { - Some(it) => it, - None => { - let position = if let Some(name) = self.name() { - Position::after(name.syntax) - } else if let Some(trait_token) = self.trait_token() { - Position::after(trait_token) - } else { - Position::last_child_of(self.syntax()) - }; - create_generic_param_list(position) - } - } - } - - fn get_or_create_where_clause(&self) -> ast::WhereClause { - if self.where_clause().is_none() { - let position = match self.semicolon_token() { - Some(tok) => Position::before(tok), - None => Position::last_child_of(self.syntax()), + let position = match (self.assoc_item_list(), self.semicolon_token()) { + (Some(items), _) => Position::before(items.syntax()), + (_, Some(tok)) => Position::before(tok), + (None, None) => Position::last_child_of(self.syntax()), }; create_where_clause(position); } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index ceb2866ebcdf7..d60196d492fc3 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1614,29 +1614,15 @@ impl Trait { #[inline] pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } #[inline] - pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } - #[inline] - pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } - #[inline] - pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } -} -pub struct TraitAlias { - pub(crate) syntax: SyntaxNode, -} -impl ast::HasAttrs for TraitAlias {} -impl ast::HasDocComments for TraitAlias {} -impl ast::HasGenericParams for TraitAlias {} -impl ast::HasName for TraitAlias {} -impl ast::HasVisibility for TraitAlias {} -impl TraitAlias { - #[inline] - pub fn type_bound_list(&self) -> Option { support::child(&self.syntax) } - #[inline] pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } #[inline] pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } #[inline] + pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } + #[inline] pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } + #[inline] + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } } pub struct TryExpr { pub(crate) syntax: SyntaxNode, @@ -2107,7 +2093,6 @@ pub enum Item { Static(Static), Struct(Struct), Trait(Trait), - TraitAlias(TraitAlias), TypeAlias(TypeAlias), Union(Union), Use(Use), @@ -6801,42 +6786,6 @@ impl fmt::Debug for Trait { f.debug_struct("Trait").field("syntax", &self.syntax).finish() } } -impl AstNode for TraitAlias { - #[inline] - fn kind() -> SyntaxKind - where - Self: Sized, - { - TRAIT_ALIAS - } - #[inline] - fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_ALIAS } - #[inline] - fn cast(syntax: SyntaxNode) -> Option { - if Self::can_cast(syntax.kind()) { - Some(Self { syntax }) - } else { - None - } - } - #[inline] - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} -impl hash::Hash for TraitAlias { - fn hash(&self, state: &mut H) { self.syntax.hash(state); } -} -impl Eq for TraitAlias {} -impl PartialEq for TraitAlias { - fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } -} -impl Clone for TraitAlias { - fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } -} -impl fmt::Debug for TraitAlias { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TraitAlias").field("syntax", &self.syntax).finish() - } -} impl AstNode for TryExpr { #[inline] fn kind() -> SyntaxKind @@ -8471,10 +8420,6 @@ impl From for Item { #[inline] fn from(node: Trait) -> Item { Item::Trait(node) } } -impl From for Item { - #[inline] - fn from(node: TraitAlias) -> Item { Item::TraitAlias(node) } -} impl From for Item { #[inline] fn from(node: TypeAlias) -> Item { Item::TypeAlias(node) } @@ -8506,7 +8451,6 @@ impl AstNode for Item { | STATIC | STRUCT | TRAIT - | TRAIT_ALIAS | TYPE_ALIAS | UNION | USE @@ -8529,7 +8473,6 @@ impl AstNode for Item { STATIC => Item::Static(Static { syntax }), STRUCT => Item::Struct(Struct { syntax }), TRAIT => Item::Trait(Trait { syntax }), - TRAIT_ALIAS => Item::TraitAlias(TraitAlias { syntax }), TYPE_ALIAS => Item::TypeAlias(TypeAlias { syntax }), UNION => Item::Union(Union { syntax }), USE => Item::Use(Use { syntax }), @@ -8554,7 +8497,6 @@ impl AstNode for Item { Item::Static(it) => &it.syntax, Item::Struct(it) => &it.syntax, Item::Trait(it) => &it.syntax, - Item::TraitAlias(it) => &it.syntax, Item::TypeAlias(it) => &it.syntax, Item::Union(it) => &it.syntax, Item::Use(it) => &it.syntax, @@ -8984,7 +8926,6 @@ impl AstNode for AnyHasAttrs { | STMT_LIST | STRUCT | TRAIT - | TRAIT_ALIAS | TRY_EXPR | TUPLE_EXPR | TUPLE_FIELD @@ -9257,10 +9198,6 @@ impl From for AnyHasAttrs { #[inline] fn from(node: Trait) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } } } -impl From for AnyHasAttrs { - #[inline] - fn from(node: TraitAlias) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } } -} impl From for AnyHasAttrs { #[inline] fn from(node: TryExpr) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } } @@ -9330,7 +9267,6 @@ impl AstNode for AnyHasDocComments { | STATIC | STRUCT | TRAIT - | TRAIT_ALIAS | TUPLE_FIELD | TYPE_ALIAS | UNION @@ -9420,10 +9356,6 @@ impl From for AnyHasDocComments { #[inline] fn from(node: Trait) -> AnyHasDocComments { AnyHasDocComments { syntax: node.syntax } } } -impl From for AnyHasDocComments { - #[inline] - fn from(node: TraitAlias) -> AnyHasDocComments { AnyHasDocComments { syntax: node.syntax } } -} impl From for AnyHasDocComments { #[inline] fn from(node: TupleField) -> AnyHasDocComments { AnyHasDocComments { syntax: node.syntax } } @@ -9488,7 +9420,7 @@ impl ast::HasGenericParams for AnyHasGenericParams {} impl AstNode for AnyHasGenericParams { #[inline] fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, CONST | ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION) + matches!(kind, CONST | ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION) } #[inline] fn cast(syntax: SyntaxNode) -> Option { @@ -9536,10 +9468,6 @@ impl From for AnyHasGenericParams { #[inline] fn from(node: Trait) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } } } -impl From for AnyHasGenericParams { - #[inline] - fn from(node: TraitAlias) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } } -} impl From for AnyHasGenericParams { #[inline] fn from(node: TypeAlias) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } } @@ -9646,7 +9574,6 @@ impl AstNode for AnyHasName { | STATIC | STRUCT | TRAIT - | TRAIT_ALIAS | TYPE_ALIAS | TYPE_PARAM | UNION @@ -9739,10 +9666,6 @@ impl From for AnyHasName { #[inline] fn from(node: Trait) -> AnyHasName { AnyHasName { syntax: node.syntax } } } -impl From for AnyHasName { - #[inline] - fn from(node: TraitAlias) -> AnyHasName { AnyHasName { syntax: node.syntax } } -} impl From for AnyHasName { #[inline] fn from(node: TypeAlias) -> AnyHasName { AnyHasName { syntax: node.syntax } } @@ -9832,7 +9755,6 @@ impl AstNode for AnyHasVisibility { | STATIC | STRUCT | TRAIT - | TRAIT_ALIAS | TUPLE_FIELD | TYPE_ALIAS | UNION @@ -9910,10 +9832,6 @@ impl From for AnyHasVisibility { #[inline] fn from(node: Trait) -> AnyHasVisibility { AnyHasVisibility { syntax: node.syntax } } } -impl From for AnyHasVisibility { - #[inline] - fn from(node: TraitAlias) -> AnyHasVisibility { AnyHasVisibility { syntax: node.syntax } } -} impl From for AnyHasVisibility { #[inline] fn from(node: TupleField) -> AnyHasVisibility { AnyHasVisibility { syntax: node.syntax } } @@ -10639,11 +10557,6 @@ impl std::fmt::Display for Trait { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for TraitAlias { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for TryExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 62a7d4df2cf6b..42b0f5cf2da1c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -880,51 +880,6 @@ impl AstNode for TypeOrConstParam { impl HasAttrs for TypeOrConstParam {} -#[derive(Debug, Clone)] -pub enum TraitOrAlias { - Trait(ast::Trait), - TraitAlias(ast::TraitAlias), -} - -impl TraitOrAlias { - pub fn name(&self) -> Option { - match self { - TraitOrAlias::Trait(x) => x.name(), - TraitOrAlias::TraitAlias(x) => x.name(), - } - } -} - -impl AstNode for TraitOrAlias { - fn can_cast(kind: SyntaxKind) -> bool - where - Self: Sized, - { - matches!(kind, SyntaxKind::TRAIT | SyntaxKind::TRAIT_ALIAS) - } - - fn cast(syntax: SyntaxNode) -> Option - where - Self: Sized, - { - let res = match syntax.kind() { - SyntaxKind::TRAIT => TraitOrAlias::Trait(ast::Trait { syntax }), - SyntaxKind::TRAIT_ALIAS => TraitOrAlias::TraitAlias(ast::TraitAlias { syntax }), - _ => return None, - }; - Some(res) - } - - fn syntax(&self) -> &SyntaxNode { - match self { - TraitOrAlias::Trait(it) => it.syntax(), - TraitOrAlias::TraitAlias(it) => it.syntax(), - } - } -} - -impl HasAttrs for TraitOrAlias {} - pub enum VisibilityKind { In(ast::Path), PubCrate, diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs index 824b38fc872d8..9bd87a7ef5fe0 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs @@ -1081,7 +1081,6 @@ fn extract_struct_traits(ast: &mut AstSrc) { "Enum", "Variant", "Trait", - "TraitAlias", "Module", "Static", "Const", From 0d2f8aff1be821907a824e5bad705c9385570fdc Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 4 Aug 2025 16:11:59 +0800 Subject: [PATCH 038/251] add test for trait alias projections --- .../crates/hir-ty/src/tests/trait_aliases.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/tests/trait_aliases.rs diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/trait_aliases.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/trait_aliases.rs new file mode 100644 index 0000000000000..302ce550b8534 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/trait_aliases.rs @@ -0,0 +1,21 @@ +use crate::tests::check_types; + +#[test] +fn projection() { + check_types( + r#" +#![feature(trait_alias)] + +pub trait A { + type Output; +} + +pub trait B = A; + +pub fn a(x: T::Output) { + x; +// ^ u32 +} +"#, + ); +} From b416845683e0892075352dd55889c625aef0e55c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 13 Aug 2025 09:18:50 +0200 Subject: [PATCH 039/251] Print fields of interned IDs in hir-ty instead of just the ID --- .../rust-analyzer/crates/hir-ty/src/db.rs | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 18b8db21161fd..6e24aea76d445 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -3,7 +3,7 @@ use std::sync; -use base_db::{Crate, impl_intern_key}; +use base_db::Crate; use hir_def::{ AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, @@ -459,40 +459,44 @@ fn hir_database_is_dyn_compatible() { fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } -#[salsa_macros::interned(no_lifetime, revisions = usize::MAX)] +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedTypeOrConstParamId { pub loc: TypeOrConstParamId, } -impl ::std::fmt::Debug for InternedTypeOrConstParamId { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - f.debug_tuple(stringify!(InternedTypeOrConstParamId)) - .field(&format_args!("{:04x}", self.0.index())) - .finish() - } -} -#[salsa_macros::interned(no_lifetime, revisions = usize::MAX)] +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedLifetimeParamId { pub loc: LifetimeParamId, } -impl ::std::fmt::Debug for InternedLifetimeParamId { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - f.debug_tuple(stringify!(InternedLifetimeParamId)) - .field(&format_args!("{:04x}", self.0.index())) - .finish() - } -} -impl_intern_key!(InternedConstParamId, ConstParamId); +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[derive(PartialOrd, Ord)] +pub struct InternedConstParamId { + pub loc: ConstParamId, +} -impl_intern_key!(InternedOpaqueTyId, ImplTraitId); +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[derive(PartialOrd, Ord)] +pub struct InternedOpaqueTyId { + pub loc: ImplTraitId, +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InternedClosure(pub DefWithBodyId, pub ExprId); -impl_intern_key!(InternedClosureId, InternedClosure); + +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[derive(PartialOrd, Ord)] +pub struct InternedClosureId { + pub loc: InternedClosure, +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); -impl_intern_key!(InternedCoroutineId, InternedCoroutine); + +#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[derive(PartialOrd, Ord)] +pub struct InternedCoroutineId { + pub loc: InternedCoroutine, +} From 2a509717b4ddc1a8d73575583c8487956804121a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 13 Aug 2025 09:18:50 +0200 Subject: [PATCH 040/251] Fix metrics checking out repos into toplevel folder instead of `target` --- src/tools/rust-analyzer/xtask/src/metrics.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs index 6ff6a1b15310a..c9eea87106060 100644 --- a/src/tools/rust-analyzer/xtask/src/metrics.rs +++ b/src/tools/rust-analyzer/xtask/src/metrics.rs @@ -16,13 +16,16 @@ type Unit = String; impl flags::Metrics { pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> { let mut metrics = Metrics::new(sh)?; - if !Path::new("./target/rustc-perf").exists() { - sh.create_dir("./target/rustc-perf")?; - cmd!(sh, "git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf") - .run()?; + if !Path::new("./target/metrics/rustc-perf").exists() { + sh.create_dir("./target/metrics/rustc-perf")?; + cmd!( + sh, + "git clone https://github.com/rust-lang/rustc-perf.git ./target/metrics/rustc-perf" + ) + .run()?; } { - let _d = sh.push_dir("./target/rustc-perf"); + let _d = sh.push_dir("./target/metrics/rustc-perf"); let revision = &metrics.perf_revision; cmd!(sh, "git reset --hard {revision}").run()?; } @@ -88,11 +91,12 @@ impl Metrics { cmd!( sh, - "git clone --depth=1 --branch 1.76.0 https://github.com/rust-lang/rust.git --single-branch" + "git clone --depth=1 --branch 1.76.0 https://github.com/rust-lang/rust.git --single-branch ./target/metrics/rust" ) .run()?; - let output = cmd!(sh, "./target/release/rust-analyzer rustc-tests ./rust").read()?; + let output = + cmd!(sh, "./target/release/rust-analyzer rustc-tests ./target/metrics/rust").read()?; for (metric, value, unit) in parse_metrics(&output) { self.report(metric, value, unit.into()); } @@ -106,7 +110,7 @@ impl Metrics { self.measure_analysis_stats_path( sh, bench, - &format!("./target/rustc-perf/collector/compile-benchmarks/{bench}"), + &format!("./target/metrics/rustc-perf/collector/compile-benchmarks/{bench}"), ) } fn measure_analysis_stats_path( From b62116bda772584e90591bbc6ebf3880a22b0080 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 13 Aug 2025 15:33:08 +0800 Subject: [PATCH 041/251] fix errors after rebase --- src/tools/rust-analyzer/crates/hir-def/src/signatures.rs | 4 ++++ .../crates/hir-ty/src/lower_nextsolver/path.rs | 7 +------ .../rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs | 6 +----- .../crates/hir-ty/src/next_solver/interner.rs | 8 ++++++-- src/tools/rust-analyzer/crates/ide/src/file_structure.rs | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 906c1c0e9ff14..bf72fafeae724 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -402,6 +402,7 @@ bitflags::bitflags! { const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 6; const RUSTC_PAREN_SUGAR = 1 << 7; const COINDUCTIVE = 1 << 8; + const ALIAS = 1 << 9; } } @@ -426,6 +427,9 @@ impl TraitSignature { if source.value.unsafe_token().is_some() { flags.insert(TraitFlags::UNSAFE); } + if source.value.eq_token().is_some() { + flags.insert(TraitFlags::ALIAS); + } if attrs.by_key(sym::fundamental).exists() { flags |= TraitFlags::FUNDAMENTAL; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index b95bb1130fa20..df67b2c59b512 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -260,10 +260,6 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }; return (ty, None); } - TypeNs::TraitAliasId(_) => { - // FIXME(trait_alias): Implement trait alias. - return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None); - } TypeNs::GenericParam(param_id) => { let generics = self.ctx.generics(); let idx = generics.type_or_const_param_idx(param_id.into()); @@ -343,8 +339,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { TypeNs::AdtId(_) | TypeNs::EnumVariantId(_) | TypeNs::TypeAliasId(_) - | TypeNs::TraitId(_) - | TypeNs::TraitAliasId(_) => {} + | TypeNs::TraitId(_) => {} } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index cfbc10e740e4b..64eab2d6b8185 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -2,7 +2,7 @@ use hir_def::{ AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, UnionId, + TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -24,7 +24,6 @@ pub enum SolverDefId { FunctionId(FunctionId), ImplId(ImplId), StaticId(StaticId), - TraitAliasId(TraitAliasId), TraitId(TraitId), TypeAliasId(TypeAliasId), ForeignId(TypeAliasId), @@ -40,7 +39,6 @@ impl_from!( FunctionId, ImplId, StaticId, - TraitAliasId, TraitId, TypeAliasId, InternedClosureId, @@ -57,7 +55,6 @@ impl From for SolverDefId { GenericDefId::FunctionId(function_id) => SolverDefId::FunctionId(function_id), GenericDefId::ImplId(impl_id) => SolverDefId::ImplId(impl_id), GenericDefId::StaticId(static_id) => SolverDefId::StaticId(static_id), - GenericDefId::TraitAliasId(trait_alias_id) => SolverDefId::TraitAliasId(trait_alias_id), GenericDefId::TraitId(trait_id) => SolverDefId::TraitId(trait_id), GenericDefId::TypeAliasId(type_alias_id) => SolverDefId::TypeAliasId(type_alias_id), } @@ -74,7 +71,6 @@ impl TryFrom for GenericDefId { SolverDefId::FunctionId(function_id) => GenericDefId::FunctionId(function_id), SolverDefId::ImplId(impl_id) => GenericDefId::ImplId(impl_id), SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id), - SolverDefId::TraitAliasId(trait_alias_id) => GenericDefId::TraitAliasId(trait_alias_id), SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id), SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id), SolverDefId::ForeignId(_) => return Err(value), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 9c1bd52065fd2..17a4e7290c2cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1172,7 +1172,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { | SolverDefId::AdtId(_) | SolverDefId::TraitId(_) | SolverDefId::ImplId(_) - | SolverDefId::TraitAliasId(_) | SolverDefId::Ctor(..) | SolverDefId::InternedOpaqueTyId(..) => panic!(), }; @@ -1790,7 +1789,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool { - matches!(trait_def_id, SolverDefId::TraitAliasId(_)) + let trait_ = match trait_def_id { + SolverDefId::TraitId(id) => id, + _ => panic!("Unexpected SolverDefId in trait_is_alias"), + }; + let trait_data = self.db().trait_signature(trait_); + trait_data.flags.contains(TraitFlags::ALIAS) } fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index d5c6eaca97448..21254fc4d6a22 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -943,7 +943,7 @@ fn let_statements() { navigation_range: 251..256, node_range: 245..262, kind: SymbolKind( - TraitAlias, + Trait, ), detail: None, deprecated: false, From 4bbbe6ee2b0c3c630d605c47ba0d4215d2522240 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 13 Aug 2025 09:42:32 +0200 Subject: [PATCH 042/251] fix: Attach db for inlay hint compute --- .../crates/hir-ty/src/next_solver/interner.rs | 2 +- .../crates/ide/src/inlay_hints.rs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 9c1bd52065fd2..54fec4aefbd45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -289,7 +289,7 @@ impl<'db> DbInterner<'db> { krate: None, block: None, }) - .unwrap() + .expect("db is expected to be attached") } pub fn new_with( diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index f6416fe51c307..424890fe370c4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -107,14 +107,16 @@ pub(crate) fn inlay_hints( } }; let mut preorder = file.preorder(); - while let Some(event) = preorder.next() { - if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) - { - preorder.skip_subtree(); - continue; + salsa::attach(sema.db, || { + while let Some(event) = preorder.next() { + if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) + { + preorder.skip_subtree(); + continue; + } + hints(event); } - hints(event); - } + }); if let Some(range_limit) = range_limit { acc.retain(|hint| range_limit.contains_range(hint.range)); } @@ -736,7 +738,7 @@ fn label_of_ty( config: &InlayHintsConfig, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { - let iter_item_type = salsa::attach(sema.db, || hint_iterator(sema, famous_defs, ty)); + let iter_item_type = hint_iterator(sema, famous_defs, ty); match iter_item_type { Some((iter_trait, item, ty)) => { const LABEL_START: &str = "impl "; From 39ac6e1eed6312dfb41cd45410804bf629a8b7d1 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 10:01:17 +0200 Subject: [PATCH 043/251] update a few fixmes, and one trivial improvement --- .../crates/hir-ty/src/next_solver/interner.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 9c1bd52065fd2..402c73bb88223 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -22,8 +22,8 @@ use rustc_type_ir::inherent::{ use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ - AliasTerm, AliasTermKind, AliasTy, EarlyBinder, FlagComputation, Flags, ImplPolarity, InferTy, - ProjectionPredicate, TraitPredicate, TraitRef, Upcast, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, + ImplPolarity, InferTy, ProjectionPredicate, TraitPredicate, TraitRef, Upcast, }; use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; @@ -1024,8 +1024,8 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { false } - fn expand_abstract_consts>(self, t: T) -> T { - t + fn expand_abstract_consts>(self, _: T) -> T { + unreachable!("only used by the old trait solver in rustc"); } fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf { @@ -1054,6 +1054,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ), SolverDefId::InternedOpaqueTyId(_def_id) => { // FIXME(next-solver): track variances + // + // We compute them based on the only `Ty` level info in rustc, + // move `variances_of_opaque` into `rustc_next_trait_solver` for reuse. VariancesOf::new_from_iter( self, (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant), @@ -1074,6 +1077,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { crate::TyDefId::TypeAliasId(id) } SolverDefId::AdtId(id) => crate::TyDefId::AdtId(id), + // FIXME(next-solver): need to support opaque types. This uses the types of + // `query mir_borrowck` in rustc. If we're ignoring regions, we could simply + // use the type inferred by general type inference here. _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), }; self.db().ty_ns(def_id) @@ -1087,9 +1093,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { AdtDef::new(def_id, self) } - fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> rustc_type_ir::AliasTyKind { - // FIXME: not currently creating any others - rustc_type_ir::AliasTyKind::Projection + fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> AliasTyKind { + match alias.def_id { + SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, + SolverDefId::TypeAliasId(_) => AliasTyKind::Projection, + _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), + } } fn alias_term_kind( @@ -1100,7 +1109,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, - _ => unreachable!("Unexpected alias: {:?}", alias.def_id), + _ => todo!("Unexpected alias: {:?}", alias.def_id), } } @@ -1741,7 +1750,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn has_item_definition(self, def_id: Self::DefId) -> bool { - // FIXME: should check if has value + // FIXME(next-solver): should check if the associated item has a value. true } @@ -1811,7 +1820,8 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool { - // FIXME(next-solver) + // FIXME(next-solver): should check the `TraitFlags` for + // the `#[rustc_do_not_implement_via_object]` flag true } @@ -1982,7 +1992,8 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::LocalDefId, ) -> rustc_type_ir::EarlyBinder { - // FIXME(next-solver) + // FIXME(next-solver): This should look at the type computed for the + // opaque by HIR typeck. unimplemented!() } From 00941b3142bf7b50a39b1a2dfa167d3642b5f3db Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 10:07:12 +0200 Subject: [PATCH 044/251] implement `type_of_opaque` --- .../rust-analyzer/crates/hir-ty/src/layout.rs | 23 +--- .../crates/hir-ty/src/next_solver/interner.rs | 100 +++++++++--------- .../rust-analyzer/crates/hir-ty/src/tests.rs | 2 +- ...e_alias_impl_traits.rs => opaque_types.rs} | 16 +++ 4 files changed, 69 insertions(+), 72 deletions(-) rename src/tools/rust-analyzer/crates/hir-ty/src/tests/{type_alias_impl_traits.rs => opaque_types.rs} (92%) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 819bd583deaed..e7bb529ad8f26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -335,27 +335,6 @@ pub fn layout_of_ty_ns_query<'db>( ptr.valid_range_mut().start = 1; Layout::scalar(dl, ptr) } - TyKind::Alias(_, ty) => match ty.def_id { - SolverDefId::TypeAliasId(_) => { - return Err(LayoutError::HasPlaceholder); - } - SolverDefId::InternedOpaqueTyId(opaque) => { - let impl_trait_id = db.lookup_intern_impl_trait_id(opaque); - match impl_trait_id { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let infer = db.infer(func.into()); - return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); - } - crate::ImplTraitId::TypeAliasImplTrait(..) => { - return Err(LayoutError::NotImplemented); - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { - return Err(LayoutError::NotImplemented); - } - } - } - _ => unreachable!(), - }, TyKind::Closure(c, args) => { let id = match c { SolverDefId::InternedClosureId(id) => id, @@ -389,7 +368,7 @@ pub fn layout_of_ty_ns_query<'db>( } TyKind::Error(_) => return Err(LayoutError::HasErrorType), - TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) => { + TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) | TyKind::Alias(..) => { return Err(LayoutError::HasPlaceholder); } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 402c73bb88223..294d071f58aef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -626,12 +626,8 @@ impl<'db> inherent::AdtDef> for AdtDef { fn struct_tail_ty( self, interner: DbInterner<'db>, - ) -> Option< - rustc_type_ir::EarlyBinder< - DbInterner<'db>, - as rustc_type_ir::Interner>::Ty, - >, - > { + ) -> Option, as rustc_type_ir::Interner>::Ty>> + { let db = interner.db(); let hir_def::AdtId::StructId(struct_id) = self.inner().id else { return None; @@ -645,7 +641,7 @@ impl<'db> inherent::AdtDef> for AdtDef { fn all_field_tys( self, interner: DbInterner<'db>, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< DbInterner<'db>, impl IntoIterator as rustc_type_ir::Interner>::Ty>, > { @@ -679,19 +675,15 @@ impl<'db> inherent::AdtDef> for AdtDef { .collect(), }; - rustc_type_ir::EarlyBinder::bind(tys) + EarlyBinder::bind(tys) } fn sizedness_constraint( self, interner: DbInterner<'db>, sizedness: SizedTraitKind, - ) -> Option< - rustc_type_ir::EarlyBinder< - DbInterner<'db>, - as rustc_type_ir::Interner>::Ty, - >, - > { + ) -> Option, as rustc_type_ir::Interner>::Ty>> + { if self.is_struct() { let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; @@ -1066,7 +1058,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } - fn type_of(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder { + fn type_of(self, def_id: Self::DefId) -> EarlyBinder { let def_id = match def_id { SolverDefId::TypeAliasId(id) => { use hir_def::Lookup; @@ -1077,9 +1069,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { crate::TyDefId::TypeAliasId(id) } SolverDefId::AdtId(id) => crate::TyDefId::AdtId(id), - // FIXME(next-solver): need to support opaque types. This uses the types of - // `query mir_borrowck` in rustc. If we're ignoring regions, we could simply - // use the type inferred by general type inference here. + // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. + // + // We currently always use the type from HIR typeck which ignores regions. This + // should be fine. + SolverDefId::InternedOpaqueTyId(_) => { + return self.type_of_opaque_hir_typeck(def_id); + } _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), }; self.db().ty_ns(def_id) @@ -1109,7 +1105,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, - _ => todo!("Unexpected alias: {:?}", alias.def_id), + _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1204,8 +1200,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn fn_sig( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder>> - { + ) -> EarlyBinder>> { let id = match def_id { SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), SolverDefId::Ctor(ctor) => match ctor { @@ -1258,7 +1253,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { explicit_item_bounds(self, def_id).map_bound(|bounds| { Clauses::new_from_iter(self, elaborate(self, bounds).collect::>()) }) @@ -1268,7 +1263,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_self_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { explicit_item_bounds(self, def_id).map_bound(|bounds| { Clauses::new_from_iter( self, @@ -1280,7 +1275,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn item_non_self_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let all_bounds: FxHashSet<_> = self.item_bounds(def_id).skip_binder().into_iter().collect(); let own_bounds: FxHashSet<_> = self.item_self_bounds(def_id).skip_binder().into_iter().collect(); @@ -1298,7 +1293,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) @@ -1308,7 +1303,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn own_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) @@ -1318,8 +1313,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn explicit_super_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> - { + ) -> EarlyBinder> { let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) @@ -1327,15 +1321,14 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .cloned() .map(|p| (p, Span::dummy())) .collect(); - rustc_type_ir::EarlyBinder::bind(predicates) + EarlyBinder::bind(predicates) } #[tracing::instrument(skip(self), ret)] fn explicit_implied_predicates_of( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> - { + ) -> EarlyBinder> { let predicates: Vec<(Clause<'db>, Span)> = self .db() .generic_predicates_ns(def_id.try_into().unwrap()) @@ -1343,13 +1336,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { .cloned() .map(|p| (p, Span::dummy())) .collect(); - rustc_type_ir::EarlyBinder::bind(predicates) + EarlyBinder::bind(predicates) } fn impl_super_outlives( self, impl_def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let impl_id = match impl_def_id { SolverDefId::ImplId(id) => id, _ => unreachable!(), @@ -1372,11 +1365,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn const_conditions( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< Self, impl IntoIterator>>, > { - rustc_type_ir::EarlyBinder::bind([unimplemented!()]) + EarlyBinder::bind([unimplemented!()]) } fn has_target_features(self, def_id: Self::DefId) -> bool { @@ -1763,7 +1756,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn impl_trait_ref( self, impl_def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder> { + ) -> EarlyBinder> { let impl_id = match impl_def_id { SolverDefId::ImplId(id) => id, _ => panic!("Unexpected SolverDefId in impl_trait_ref"), @@ -1960,12 +1953,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn explicit_implied_const_bounds( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< + ) -> EarlyBinder< Self, impl IntoIterator>>, > { // FIXME(next-solver) - rustc_type_ir::EarlyBinder::bind([]) + EarlyBinder::bind([]) } fn fn_is_const(self, def_id: Self::DefId) -> bool { @@ -1988,22 +1981,31 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { None } - fn type_of_opaque_hir_typeck( - self, - def_id: Self::LocalDefId, - ) -> rustc_type_ir::EarlyBinder { - // FIXME(next-solver): This should look at the type computed for the - // opaque by HIR typeck. - unimplemented!() + fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> EarlyBinder { + match def_id { + SolverDefId::InternedOpaqueTyId(opaque) => { + let impl_trait_id = self.db().lookup_intern_impl_trait_id(opaque); + match impl_trait_id { + crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { + let infer = self.db().infer(func.into()); + EarlyBinder::bind(infer.type_of_rpit[idx].to_nextsolver(self)) + } + crate::ImplTraitId::TypeAliasImplTrait(..) + | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + // FIXME(next-solver) + EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed)) + } + } + } + _ => panic!("Unexpected SolverDefId in type_of_opaque_hir_typeck"), + } } fn coroutine_hidden_types( self, def_id: Self::DefId, - ) -> rustc_type_ir::EarlyBinder< - Self, - rustc_type_ir::Binder>, - > { + ) -> EarlyBinder>> + { // FIXME(next-solver) unimplemented!() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index fc31973022bdd..d89cf4bcd45cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -6,11 +6,11 @@ mod incremental; mod macros; mod method_resolution; mod never_type; +mod opaque_types; mod patterns; mod regression; mod simple; mod traits; -mod type_alias_impl_traits; use base_db::{Crate, SourceDatabase}; use expect_test::Expect; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs similarity index 92% rename from src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs rename to src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs index e2b7bf379cc3b..36578545a9f49 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/type_alias_impl_traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs @@ -159,3 +159,19 @@ static ALIAS: i32 = { "#]], ) } + +#[test] +fn leak_auto_traits() { + check_no_mismatches( + r#" +//- minicore: send +fn foo() -> impl Sized {} + +fn is_send(_: T) {} + +fn main() { + is_send(foo()); +} + "#, + ); +} From 5849fef132daf525016379b6bfc6bd25459371dd Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 10:30:34 +0200 Subject: [PATCH 045/251] layout_of uses `PostAnalysis` --- src/tools/rust-analyzer/crates/hir-ty/src/layout.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index e7bb529ad8f26..2d0471d7e5545 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -182,7 +182,7 @@ pub fn layout_of_ty_ns_query<'db>( }; let dl = &*target; let cx = LayoutCx::new(dl); - let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); let ty = deeply_normalize(infer_ctxt.at(&cause, ParamEnv::empty()), ty).unwrap_or(ty); let result = match ty.kind() { @@ -368,7 +368,11 @@ pub fn layout_of_ty_ns_query<'db>( } TyKind::Error(_) => return Err(LayoutError::HasErrorType), - TyKind::Placeholder(_) | TyKind::Bound(..) | TyKind::Infer(..) | TyKind::Param(..) | TyKind::Alias(..) => { + TyKind::Placeholder(_) + | TyKind::Bound(..) + | TyKind::Infer(..) + | TyKind::Param(..) + | TyKind::Alias(..) => { return Err(LayoutError::HasPlaceholder); } }; From 67b1e329080519085716c8e444a43eede0d196a6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 11:00:00 +0200 Subject: [PATCH 046/251] manually normalize alias --- .../crates/hir-ty/src/next_solver/interner.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 294d071f58aef..c530c28f88613 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -626,8 +626,7 @@ impl<'db> inherent::AdtDef> for AdtDef { fn struct_tail_ty( self, interner: DbInterner<'db>, - ) -> Option, as rustc_type_ir::Interner>::Ty>> - { + ) -> Option, Ty<'db>>> { let db = interner.db(); let hir_def::AdtId::StructId(struct_id) = self.inner().id else { return None; @@ -641,10 +640,7 @@ impl<'db> inherent::AdtDef> for AdtDef { fn all_field_tys( self, interner: DbInterner<'db>, - ) -> EarlyBinder< - DbInterner<'db>, - impl IntoIterator as rustc_type_ir::Interner>::Ty>, - > { + ) -> EarlyBinder, impl IntoIterator>> { let db = interner.db(); // FIXME: this is disabled just to match the behavior with chalk right now let field_tys = |id: VariantId| { @@ -682,8 +678,7 @@ impl<'db> inherent::AdtDef> for AdtDef { self, interner: DbInterner<'db>, sizedness: SizedTraitKind, - ) -> Option, as rustc_type_ir::Interner>::Ty>> - { + ) -> Option, Ty<'db>>> { if self.is_struct() { let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; From 1d57d7800db05934a466457c443975d71c4d1e29 Mon Sep 17 00:00:00 2001 From: donni-h <56559005+donni-h@users.noreply.github.com> Date: Wed, 13 Aug 2025 13:03:52 +0200 Subject: [PATCH 047/251] Fix dead link to Cargo.toml in documentation ../../Cargo.toml resolves to https://rust-analyzer.github.io/Cargo.toml, which is an invalid link --- src/tools/rust-analyzer/docs/book/src/contributing/style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/style.md b/src/tools/rust-analyzer/docs/book/src/contributing/style.md index 746f3eb132117..fe09fb6c2fd52 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/style.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/style.md @@ -101,7 +101,7 @@ Including a description and GIF suitable for the changelog means less work for t ## Clippy -We use Clippy to improve the code, but if some lints annoy you, allow them in the [Cargo.toml](../../Cargo.toml) [workspace.lints.clippy] section. +We use Clippy to improve the code, but if some lints annoy you, allow them in the [Cargo.toml](https://github.com/rust-lang/rust-analyzer/blob/master/Cargo.toml) [workspace.lints.clippy] section. # Code From 8ef6a8ff6defd019dff7865ab602bc7acba1afc2 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 13 Aug 2025 15:24:53 +0100 Subject: [PATCH 048/251] [internal] Update to the latest @vscode/vsce for extension build This isn't a logic change, but it fixes an npm warning during the build. vsce itself hasn't had any major changes between 3.2.2 and 3.6. * https://github.com/microsoft/vscode-vsce/releases/tag/v3.3.0 * https://github.com/microsoft/vscode-vsce/releases/tag/v3.4.0 * https://github.com/microsoft/vscode-vsce/releases/tag/v3.5.0 * https://github.com/microsoft/vscode-vsce/releases/tag/v3.6.0 --- .../editors/code/package-lock.json | 1368 ++++++++++++++--- .../rust-analyzer/editors/code/package.json | 2 +- 2 files changed, 1169 insertions(+), 201 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 1dc11ee4e4b81..ad8708e00c519 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -26,7 +26,7 @@ "@typescript-eslint/eslint-plugin": "^8.25.0", "@typescript-eslint/parser": "^8.25.0", "@vscode/test-electron": "^2.4.1", - "@vscode/vsce": "^3.2.2", + "@vscode/vsce": "^3.6.0", "esbuild": "^0.25.0", "eslint": "^9.21.0", "eslint-config-prettier": "^10.0.2", @@ -41,6 +41,23 @@ "vscode": "^1.93.0" } }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, "node_modules/@azure/abort-controller": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", @@ -212,6 +229,31 @@ "node": ">=16" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", @@ -947,6 +989,217 @@ "node": ">= 8" } }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@stylistic/eslint-plugin": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.1.0.tgz", @@ -984,6 +1237,136 @@ "eslint": ">=9.0.0" } }, + "node_modules/@textlint/ast-node-types": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.2.1.tgz", + "integrity": "sha512-20fEcLPsXg81yWpApv4FQxrZmlFF/Ta7/kz1HGIL+pJo5cSTmkc+eCki3GpOPZIoZk0tbJU8hrlwUb91F+3SNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.2.1.tgz", + "integrity": "sha512-oollG/BHa07+mMt372amxHohteASC+Zxgollc1sZgiyxo4S6EuureV3a4QIQB0NecA+Ak3d0cl0WI/8nou38jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.2.1", + "@textlint/resolver": "15.2.1", + "@textlint/types": "15.2.1", + "chalk": "^4.1.2", + "debug": "^4.4.1", + "js-yaml": "^3.14.1", + "lodash": "^4.17.21", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/module-interop": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.2.1.tgz", + "integrity": "sha512-b/C/ZNrm05n1ypymDknIcpkBle30V2ZgE3JVqQlA9PnQV46Ky510qrZk6s9yfKgA3m1YRnAw04m8xdVtqjq1qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.2.1.tgz", + "integrity": "sha512-FY3aK4tElEcOJVUsaMj4Zro4jCtKEEwUMIkDL0tcn6ljNcgOF7Em+KskRRk/xowFWayqDtdz5T3u7w/6fjjuJQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.2.1.tgz", + "integrity": "sha512-zyqNhSatK1cwxDUgosEEN43hFh3WCty9Zm2Vm3ogU566IYegifwqN54ey/CiRy/DiO4vMcFHykuQnh2Zwp6LLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.2.1" + } + }, "node_modules/@tsconfig/strictest": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@tsconfig/strictest/-/strictest-2.0.5.tgz", @@ -1015,6 +1398,20 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/vscode": { "version": "1.93.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.93.0.tgz", @@ -1220,16 +1617,20 @@ } }, "node_modules/@vscode/vsce": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.2.2.tgz", - "integrity": "sha512-4TqdUq/yKlQTHcQMk/DamR632bq/+IJDomSbexOMee/UAYWqYm0XHWA6scGslsCpzY+sCWEhhl0nqdOB0XW1kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.6.0.tgz", + "integrity": "sha512-u2ZoMfymRNJb14aHNawnXJtXHLXDVKc1oKZaH4VELKT/9iWKRVgtQOdwxCgtwSxJoqYvuK4hGlBWQJ05wxADhg==", "dev": true, "license": "MIT", "dependencies": { "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.1", + "@secretlint/secretlint-formatter-sarif": "^10.1.1", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.1", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.1", "@vscode/vsce-sign": "^2.0.0", "azure-devops-node-api": "^12.5.0", - "chalk": "^2.4.2", + "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", "cockatiel": "^3.1.2", "commander": "^12.1.0", @@ -1243,6 +1644,7 @@ "minimatch": "^3.0.3", "parse-semver": "^1.1.1", "read": "^1.0.7", + "secretlint": "^10.1.1", "semver": "^7.5.2", "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", @@ -1486,6 +1888,22 @@ "integrity": "sha512-PMqBCBvrOVDRqLGooQb+z+t1Q0PiPyurUQeZRR5uHBOVZcW8B04KMmnT12USnhpNX2wCPagWzLVppQMUG3u0Dw==", "license": "MIT" }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -1500,16 +1918,18 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/argparse": { @@ -1519,6 +1939,16 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1564,6 +1994,22 @@ ], "license": "MIT" }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -1598,6 +2044,13 @@ "dev": true, "license": "ISC" }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -1720,18 +2173,20 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/cheerio": { @@ -1845,39 +2300,6 @@ "node": ">=8" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1938,20 +2360,21 @@ } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/combined-stream": { @@ -2469,9 +2892,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2685,6 +3108,23 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2730,6 +3170,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -2829,16 +3282,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eslint": { "version": "9.21.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", @@ -2964,22 +3407,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -2991,43 +3418,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3041,16 +3431,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3064,19 +3444,6 @@ "node": "*" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -3095,6 +3462,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -3213,6 +3594,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", @@ -3360,6 +3758,21 @@ "license": "MIT", "optional": true }, + "node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3492,6 +3905,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -3505,6 +3949,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3513,13 +3964,13 @@ "license": "MIT" }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-symbols": { @@ -3702,6 +4153,19 @@ "node": ">=0.8.19" } }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3872,6 +4336,24 @@ "dev": true, "license": "ISC" }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/jackspeak": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", @@ -3897,6 +4379,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3931,6 +4420,19 @@ "dev": true, "license": "MIT" }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonc-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", @@ -3938,6 +4440,19 @@ "dev": true, "license": "MIT" }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -4103,6 +4618,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -4159,6 +4681,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", @@ -4430,12 +4959,61 @@ "license": "MIT", "optional": true }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/node-sarif-builder": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.2.0.tgz", + "integrity": "sha512-kVIOdynrF2CRodHZeP/97Rh1syTUHBNiw17hUCIVhlhEsWlfJm19MuO56s4MdKbr22xWx6mzMnNAgXzVlIYM9Q==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -4661,6 +5239,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -4688,6 +5279,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -4795,6 +5404,19 @@ "node": "20 || >=22" } }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4802,6 +5424,13 @@ "dev": true, "license": "MIT" }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", @@ -4815,6 +5444,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -4962,6 +5601,19 @@ "rc": "cli.js" } }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -4986,6 +5638,39 @@ "node": ">=0.8" } }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -5018,6 +5703,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5146,6 +5841,28 @@ "dev": true, "license": "ISC" }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -5326,6 +6043,80 @@ "simple-concat": "^1.0.0" } }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -5487,17 +6278,130 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/tar-fs": { @@ -5587,6 +6491,46 @@ "node": ">= 6" } }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/tmp": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", @@ -5667,6 +6611,19 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-rest-client": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", @@ -5747,6 +6704,29 @@ "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5781,6 +6761,30 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -5928,42 +6932,6 @@ "node": ">=8" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 328eb509b4eea..4975ca858671b 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -63,7 +63,7 @@ "@typescript-eslint/eslint-plugin": "^8.25.0", "@typescript-eslint/parser": "^8.25.0", "@vscode/test-electron": "^2.4.1", - "@vscode/vsce": "^3.2.2", + "@vscode/vsce": "^3.6.0", "esbuild": "^0.25.0", "eslint": "^9.21.0", "eslint-config-prettier": "^10.0.2", From 23e8a1e1398f5c17f4c64fe740479c2df31c9fd0 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 19:49:59 +0000 Subject: [PATCH 049/251] Don't panic if unable to identify host in metrics --- src/tools/rust-analyzer/xtask/src/metrics.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs index c9eea87106060..fd4b600b03470 100644 --- a/src/tools/rust-analyzer/xtask/src/metrics.rs +++ b/src/tools/rust-analyzer/xtask/src/metrics.rs @@ -160,7 +160,7 @@ struct Host { impl Metrics { fn new(sh: &Shell) -> anyhow::Result { - let host = Host::new(sh)?; + let host = Host::new(sh).unwrap_or_else(|_| Host::unknown()); let timestamp = SystemTime::now(); let revision = cmd!(sh, "git rev-parse HEAD").read()?; let perf_revision = "a584462e145a0c04760fd9391daefb4f6bd13a99".into(); @@ -191,9 +191,13 @@ impl Metrics { } impl Host { + fn unknown() -> Host { + Host { os: "unknown".into(), cpu: "unknown".into(), mem: "unknown".into() } + } + fn new(sh: &Shell) -> anyhow::Result { if cfg!(not(target_os = "linux")) { - return Ok(Host { os: "unknown".into(), cpu: "unknown".into(), mem: "unknown".into() }); + return Ok(Host::unknown()); } let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_owned(); From 8e5818df2eb7d77f3cbed5cbf0c292e8a770d760 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 19:50:15 +0000 Subject: [PATCH 050/251] Shift vars when mapping Dyn --- .../rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 3a3206bef38b5..4696cf479c191 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1147,6 +1147,9 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) } }), ); + + let p = shift_vars(interner, p, 1); + let where_clause = match p.skip_binder() { rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { let trait_ref = TraitRef::new( From 861f9122c899a8ec52c62ecb0a1435226dd5fc1a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 14 Aug 2025 08:34:31 +0800 Subject: [PATCH 051/251] Fix indent for convert_match_to_let_else Example --- ``` //- minicore: option fn f() { let x$0 = match Some(()) { Some(it) => it, None => {//comment println!("nope"); return }, }; } ``` **Old output**: ```rust fn f() { let Some(x) = Some(()) else {//comment println!("nope"); return }; } ``` **This PR output**: ```rust fn f() { let Some(x) = Some(()) else {//comment println!("nope"); return }; } ``` --- .../src/handlers/convert_match_to_let_else.rs | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs index 9126e869b9a05..1a6d176c9054c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs @@ -1,7 +1,7 @@ use ide_db::defs::{Definition, NameRefClass}; use syntax::{ AstNode, SyntaxNode, - ast::{self, HasName, Name, syntax_factory::SyntaxFactory}, + ast::{self, HasName, Name, edit::AstNodeEdit, syntax_factory::SyntaxFactory}, syntax_editor::SyntaxEditor, }; @@ -45,7 +45,7 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<' return None; } - let diverging_arm_expr = match diverging_arm.expr()? { + let diverging_arm_expr = match diverging_arm.expr()?.dedent(1.into()) { ast::Expr::BlockExpr(block) if block.modifier().is_none() && block.label().is_none() => { block.to_string() } @@ -150,7 +150,12 @@ fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> Syn } } editor.add_mappings(make.finish_with_mappings()); - editor.finish().new_root().clone() + let new_node = editor.finish().new_root().clone(); + if let Some(pat) = ast::Pat::cast(new_node.clone()) { + pat.dedent(1.into()).syntax().clone() + } else { + new_node + } } #[cfg(test)] @@ -209,6 +214,53 @@ fn foo(opt: Option) -> Result { ); } + #[test] + fn indent_level() { + check_assist( + convert_match_to_let_else, + r#" +//- minicore: option +enum Foo { + A(u32), + B(u32), + C(String), +} + +fn foo(opt: Option) -> Result { + let mut state = 2; + let va$0lue = match opt { + Some( + Foo::A(it) + | Foo::B(it) + ) => it, + _ => { + state = 3; + return Err(()) + }, + }; +} + "#, + r#" +enum Foo { + A(u32), + B(u32), + C(String), +} + +fn foo(opt: Option) -> Result { + let mut state = 2; + let Some( + Foo::A(value) + | Foo::B(value) + ) = opt else { + state = 3; + return Err(()) + }; +} + "#, + ); + } + #[test] fn should_not_be_applicable_if_extracting_arm_is_not_an_identity_expr() { cov_mark::check_count!(extracting_arm_is_not_an_identity_expr, 2); @@ -489,9 +541,9 @@ fn f() { r#" fn f() { let Some(x) = Some(()) else {//comment - println!("nope"); - return - }; + println!("nope"); + return + }; } "#, ); From c78177b7f93c9b691a9b8365eaba9c8d11df4cd0 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 14 Aug 2025 10:05:11 +0800 Subject: [PATCH 052/251] Add guard to let-chain for replace_match_with_if_let ```rust fn main() { match$0 Some(0) { Some(n) if n % 2 == 0 && n != 6 => (), _ => code(), } } ``` -> ```rust fn main() { if let Some(n) = Some(0) && n % 2 == 0 && n != 6 { () } else { code() } } --- .../src/handlers/replace_if_let_with_match.rs | 64 +++++++++++++++---- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 15d3db5e749f0..dd244375dc91e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -8,7 +8,7 @@ use ide_db::{ ty_filter::TryEnum, }; use syntax::{ - AstNode, T, TextRange, + AstNode, Edition, T, TextRange, ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory}, }; @@ -187,7 +187,7 @@ fn make_else_arm( // Assist: replace_match_with_if_let // -// Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression. +// Replaces a binary `match` with a wildcard pattern with an `if let` expression. // // ``` // enum Action { Move { distance: u32 }, Stop } @@ -225,18 +225,24 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' let mut arms = match_arm_list.arms(); let (first_arm, second_arm) = (arms.next()?, arms.next()?); - if arms.next().is_some() || first_arm.guard().is_some() || second_arm.guard().is_some() { + if arms.next().is_some() || second_arm.guard().is_some() { + return None; + } + if first_arm.guard().is_some() && ctx.edition() < Edition::Edition2024 { return None; } - let (if_let_pat, then_expr, else_expr) = pick_pattern_and_expr_order( + let (if_let_pat, guard, then_expr, else_expr) = pick_pattern_and_expr_order( &ctx.sema, first_arm.pat()?, second_arm.pat()?, first_arm.expr()?, second_arm.expr()?, + first_arm.guard(), + second_arm.guard(), )?; let scrutinee = match_expr.expr()?; + let guard = guard.and_then(|it| it.condition()); let let_ = match &if_let_pat { ast::Pat::LiteralPat(p) @@ -277,6 +283,11 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' } _ => make.expr_let(if_let_pat, scrutinee).into(), }; + let condition = if let Some(guard) = guard { + make.expr_bin(condition, ast::BinaryOp::LogicOp(ast::LogicOp::And), guard).into() + } else { + condition + }; let then_expr = then_expr.clone_for_update(); then_expr.reindent_to(IndentLevel::single()); let then_block = make_block_expr(then_expr); @@ -303,18 +314,23 @@ fn pick_pattern_and_expr_order( pat2: ast::Pat, expr: ast::Expr, expr2: ast::Expr, -) -> Option<(ast::Pat, ast::Expr, ast::Expr)> { + guard: Option, + guard2: Option, +) -> Option<(ast::Pat, Option, ast::Expr, ast::Expr)> { + if guard.is_some() && guard2.is_some() { + return None; + } let res = match (pat, pat2) { (ast::Pat::WildcardPat(_), _) => return None, - (pat, ast::Pat::WildcardPat(_)) => (pat, expr, expr2), - (pat, _) if is_empty_expr(&expr2) => (pat, expr, expr2), - (_, pat) if is_empty_expr(&expr) => (pat, expr2, expr), + (pat, ast::Pat::WildcardPat(_)) => (pat, guard, expr, expr2), + (pat, _) if is_empty_expr(&expr2) => (pat, guard, expr, expr2), + (_, pat) if is_empty_expr(&expr) => (pat, guard, expr2, expr), (pat, pat2) => match (binds_name(sema, &pat), binds_name(sema, &pat2)) { (true, true) => return None, - (true, false) => (pat, expr, expr2), - (false, true) => (pat2, expr2, expr), - _ if is_sad_pat(sema, &pat) => (pat2, expr2, expr), - (false, false) => (pat, expr, expr2), + (true, false) => (pat, guard, expr, expr2), + (false, true) => (pat2, guard2, expr2, expr), + _ if is_sad_pat(sema, &pat) => (pat2, guard2, expr2, expr), + (false, false) => (pat, guard, expr, expr2), }, }; Some(res) @@ -1849,6 +1865,30 @@ fn main() { code() } } +"#, + ) + } + + #[test] + fn test_replace_match_with_if_let_chain() { + check_assist( + replace_match_with_if_let, + r#" +fn main() { + match$0 Some(0) { + Some(n) if n % 2 == 0 && n != 6 => (), + _ => code(), + } +} +"#, + r#" +fn main() { + if let Some(n) = Some(0) && n % 2 == 0 && n != 6 { + () + } else { + code() + } +} "#, ) } From 6772f18557e24d9d1f8572839d0ef3cde3b0ac44 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 14 Aug 2025 14:33:33 +0200 Subject: [PATCH 053/251] Track diagnostic generations per package --- .../crates/rust-analyzer/src/diagnostics.rs | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 30f530100f9df..ee50237c405e6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -26,17 +26,15 @@ pub struct DiagnosticsMapConfig { pub(crate) type DiagnosticsGeneration = usize; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub(crate) struct WorkspaceFlycheckDiagnostic { - pub(crate) generation: DiagnosticsGeneration, - pub(crate) per_package: - FxHashMap>, FxHashMap>>, + pub(crate) per_package: FxHashMap>, PackageFlycheckDiagnostic>, } -impl WorkspaceFlycheckDiagnostic { - fn new(generation: DiagnosticsGeneration) -> Self { - WorkspaceFlycheckDiagnostic { generation, per_package: Default::default() } - } +#[derive(Debug, Clone)] +pub(crate) struct PackageFlycheckDiagnostic { + generation: DiagnosticsGeneration, + per_file: FxHashMap>, } #[derive(Debug, Default, Clone)] @@ -68,7 +66,7 @@ impl DiagnosticCollection { let Some(check) = self.check.get_mut(flycheck_id) else { return; }; - self.changes.extend(check.per_package.drain().flat_map(|(_, v)| v.into_keys())); + self.changes.extend(check.per_package.drain().flat_map(|(_, v)| v.per_file.into_keys())); if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { fixes.clear(); } @@ -79,7 +77,7 @@ impl DiagnosticCollection { self.changes.extend( self.check .iter_mut() - .flat_map(|it| it.per_package.drain().flat_map(|(_, v)| v.into_keys())), + .flat_map(|it| it.per_package.drain().flat_map(|(_, v)| v.per_file.into_keys())), ) } @@ -93,7 +91,7 @@ impl DiagnosticCollection { }; let package_id = Some(package_id); if let Some(checks) = check.per_package.remove(&package_id) { - self.changes.extend(checks.into_keys()); + self.changes.extend(checks.per_file.into_keys()); } if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { fixes.remove(&package_id); @@ -105,8 +103,20 @@ impl DiagnosticCollection { flycheck_id: usize, generation: DiagnosticsGeneration, ) { - if self.check.get(flycheck_id).is_some_and(|it| it.generation < generation) { - self.clear_check(flycheck_id); + if let Some(flycheck) = self.check.get_mut(flycheck_id) { + let mut packages = vec![]; + self.changes.extend( + flycheck + .per_package + .extract_if(|_, v| v.generation < generation) + .inspect(|(package_id, _)| packages.push(package_id.clone())) + .flat_map(|(_, v)| v.per_file.into_keys()), + ); + if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { + for package in packages { + fixes.remove(&package); + } + } } } @@ -126,21 +136,19 @@ impl DiagnosticCollection { fix: Option>, ) { if self.check.len() <= flycheck_id { - self.check - .resize_with(flycheck_id + 1, || WorkspaceFlycheckDiagnostic::new(generation)); + self.check.resize_with(flycheck_id + 1, WorkspaceFlycheckDiagnostic::default); } + let check = &mut self.check[flycheck_id]; + let package = check.per_package.entry(package_id.clone()).or_insert_with(|| { + PackageFlycheckDiagnostic { generation, per_file: FxHashMap::default() } + }); // Getting message from old generation. Might happen in restarting checks. - if self.check[flycheck_id].generation > generation { + if package.generation > generation { return; } - self.check[flycheck_id].generation = generation; - let diagnostics = self.check[flycheck_id] - .per_package - .entry(package_id.clone()) - .or_default() - .entry(file_id) - .or_default(); + package.generation = generation; + let diagnostics = package.per_file.entry(file_id).or_default(); for existing_diagnostic in diagnostics.iter() { if are_diagnostics_equal(existing_diagnostic, &diagnostic) { return; @@ -210,7 +218,7 @@ impl DiagnosticCollection { .check .iter() .flat_map(|it| it.per_package.values()) - .filter_map(move |it| it.get(&file_id)) + .filter_map(move |it| it.per_file.get(&file_id)) .flatten(); native_syntax.chain(native_semantic).chain(check) } From 58ec13d79389f3886e71d43a0fcf501b84c1a40f Mon Sep 17 00:00:00 2001 From: Ralf Anton Beier Date: Mon, 11 Aug 2025 06:16:34 +0200 Subject: [PATCH 054/251] feat: hint at unterminated strings in unknown prefix errors When encountering 'unknown literal prefix' errors, check for unbalanced quotes in recent code and suggest checking for unterminated string literals. --- .../crates/parser/src/lexed_str.rs | 30 ++++++++++++++++++- .../unterminated_string_unknown_prefix.rast | 15 ++++++++++ .../err/unterminated_string_unknown_prefix.rs | 5 ++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 8fff1c3db7485..dcf397142cac0 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -149,6 +149,24 @@ impl<'a> Converter<'a> { } } + /// Check for likely unterminated string by analyzing STRING token content + fn has_likely_unterminated_string(&self) -> bool { + let Some(last_idx) = self.res.kind.len().checked_sub(1) else { return false }; + + for i in (0..=last_idx).rev().take(5) { + if self.res.kind[i] == STRING { + let start = self.res.start[i] as usize; + let end = self.res.start.get(i + 1).map(|&s| s as usize).unwrap_or(self.offset); + let content = &self.res.text[start..end]; + + if content.contains('(') && (content.contains("//") || content.contains(";\n")) { + return true; + } + } + } + false + } + fn finalize_with_eof(mut self) -> LexedStr<'a> { self.res.push(EOF, self.offset); self.res @@ -267,7 +285,17 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Unknown => ERROR, rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT, rustc_lexer::TokenKind::UnknownPrefix => { - errors.push("unknown literal prefix".into()); + let has_unterminated = self.has_likely_unterminated_string(); + + let error_msg = if has_unterminated { + format!( + "unknown literal prefix `{}` (note: check for unterminated string literal)", + token_text + ) + } else { + "unknown literal prefix".to_owned() + }; + errors.push(error_msg); IDENT } rustc_lexer::TokenKind::Eof => EOF, diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast new file mode 100644 index 0000000000000..f7f24ca3f810a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast @@ -0,0 +1,15 @@ +FN_KW "fn" +WHITESPACE " " +IDENT "main" +L_PAREN "(" +R_PAREN ")" +WHITESPACE " " +L_CURLY "{" +WHITESPACE "\n " +IDENT "hello" +L_PAREN "(" +STRING "\"world);\n // a bunch of code was here\n env(\"FLAGS" +STRING "\", \"" +MINUS "-" +IDENT "help" error: unknown literal prefix `help` (note: check for unterminated string literal) +STRING "\")\n}" error: Missing trailing `"` symbol to terminate the string literal diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs new file mode 100644 index 0000000000000..338b9582605bd --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs @@ -0,0 +1,5 @@ +fn main() { + hello("world); + // a bunch of code was here + env("FLAGS", "-help") +} \ No newline at end of file From cc3c5cfb2e46c04778ebba4b0c71e87cb7f7cef7 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Thu, 14 Aug 2025 17:04:54 +0000 Subject: [PATCH 055/251] Add test for webrender-2022 metrics --- .../crates/hir-ty/src/tests/traits.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 2e4346a86973b..9d72105624a05 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4994,3 +4994,35 @@ fn main() { "#]], ); } + +#[test] +fn trait_object_binders() { + check_infer( + r#" +//- minicore: iterator, dispatch_from_dyn +fn main() { + struct Box(*const T); + impl Iterator for Box { + type Item = I::Item; + fn next(&mut self) -> Option { + loop {} + } + } + let iter: Box + 'static> = loop {}; + let _ = iter.into_iter(); +}"#, + expect![[r#" + 10..313 '{ ...r(); }': () + 223..227 'iter': Box + 'static> + 273..280 'loop {}': ! + 278..280 '{}': () + 290..291 '_': Box + 'static> + 294..298 'iter': Box + 'static> + 294..310 'iter.i...iter()': Box + 'static> + 152..156 'self': &'? mut Box + 177..208 '{ ... }': Option> + 191..198 'loop {}': ! + 196..198 '{}': () + "#]], + ); +} From 06336efca9cd5851a72ff43db3641485e0e06a79 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 03:07:43 +0000 Subject: [PATCH 056/251] add comment --- .../rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 4696cf479c191..20cd8626f299b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1148,6 +1148,13 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) }), ); + // Rust and chalk have slightly different + // representation for trait objects. + // + // Chalk uses `for for<'a> T0: Trait<'a>` while rustc + // uses `ExistentialPredicate`s, which do not have a self ty. + // We need to shift escaping bound vars by 1 to accommodate + // the newly introduced `for` binder. let p = shift_vars(interner, p, 1); let where_clause = match p.skip_binder() { From b38dd2acb598adb14bd1f08f39090909be13498b Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 15 Aug 2025 20:15:21 +0300 Subject: [PATCH 057/251] Use a more specific error message when talking about the server logs --- src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index f8f29eee126ed..a8a54930c6e5e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -152,7 +152,9 @@ impl GlobalState { if self.fetch_build_data_error().is_err() { status.health |= lsp_ext::Health::Warning; message.push_str("Failed to run build scripts of some packages.\n\n"); - message.push_str("Please refer to the logs for more details on the errors."); + message.push_str( + "Please refer to the language server logs for more details on the errors.", + ); } if let Some(err) = &self.config_errors { status.health |= lsp_ext::Health::Warning; From b9861fb75dda32fb349894fe8c73ab68d0c2f5f7 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 17 Aug 2025 16:09:52 +0900 Subject: [PATCH 058/251] fix: Make lang items query properly filter out overwritten/excluded sysroots --- .../rust-analyzer/crates/base-db/src/lib.rs | 2 + .../crates/hir-def/src/lang_item.rs | 16 ++- .../crates/hir-def/src/nameres.rs | 4 + .../crates/hir-def/src/nameres/collector.rs | 19 +-- .../crates/hir-ty/src/tests/regression.rs | 51 +++++++ .../rust-analyzer/crates/ide-db/src/lib.rs | 6 +- .../crates/test-fixture/src/lib.rs | 136 +++++++++++------- 7 files changed, 166 insertions(+), 68 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index b8eadb608fea5..dbf949c470c4d 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -30,6 +30,8 @@ use triomphe::Arc; pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}; pub type FxIndexSet = indexmap::IndexSet; +pub type FxIndexMap = + indexmap::IndexMap>; #[macro_export] macro_rules! impl_intern_key { 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 a0be69cb2f96e..600f206770016 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 @@ -12,7 +12,7 @@ use crate::{ StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path, - nameres::{assoc::TraitItems, crate_def_map}, + nameres::{assoc::TraitItems, crate_def_map, crate_local_def_map}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -170,7 +170,19 @@ pub fn lang_item( { return Some(target); } - start_crate.data(db).dependencies.iter().find_map(|dep| lang_item(db, dep.crate_id, item)) + + // Our `CrateGraph` eagerly inserts sysroot dependencies like `core` or `std` into dependencies + // even if the target crate has `#![no_std]`, `#![no_core]` or shadowed sysroot dependencies + // like `dependencies.std.path = ".."`. So we use `extern_prelude()` instead of + // `CrateData.dependencies` here, which has already come through such sysroot complexities + // while nameres. + // + // See https://github.com/rust-lang/rust-analyzer/pull/20475 for details. + crate_local_def_map(db, start_crate).local(db).extern_prelude().find_map(|(_, (krate, _))| { + // Some crates declares themselves as extern crate like `extern crate self as core`. + // Ignore these to prevent cycles. + if krate.krate == start_crate { None } else { lang_item(db, krate.krate, item) } + }) } #[derive(Default, Debug, Clone, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 5030585147dee..bf6fc15b7d199 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -545,6 +545,10 @@ impl DefMap { self.data.no_std || self.data.no_core } + pub fn is_no_core(&self) -> bool { + self.data.no_core + } + pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option { self.data.fn_proc_macro_mapping.get(&id).copied() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 07e61718222bf..0f84728dcb4a8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -27,10 +27,11 @@ use triomphe::Arc; use crate::{ AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc, - ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, - LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, - MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, - StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc, + ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, + ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, + MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, + ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, + UseLoc, attr::Attrs, db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, @@ -69,7 +70,7 @@ pub(super) fn collect_defs( // populate external prelude and dependency list let mut deps = - FxHashMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default()); + FxIndexMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default()); for dep in &krate.dependencies { tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); @@ -220,7 +221,7 @@ struct DefCollector<'db> { /// Set only in case of blocks. crate_local_def_map: Option<&'db LocalDefMap>, // The dependencies of the current crate, including optional deps like `test`. - deps: FxHashMap, + deps: FxIndexMap, glob_imports: FxHashMap>, unresolved_imports: Vec, indeterminate_imports: Vec<(ImportDirective, PerNs)>, @@ -332,7 +333,9 @@ impl<'db> DefCollector<'db> { let skip = dep.is_sysroot() && match dep.crate_id.data(self.db).origin { CrateOrigin::Lang(LangCrateOrigin::Core) => crate_data.no_core, - CrateOrigin::Lang(LangCrateOrigin::Std) => crate_data.no_std, + CrateOrigin::Lang(LangCrateOrigin::Std) => { + crate_data.no_core || crate_data.no_std + } _ => false, }; if skip { @@ -2550,7 +2553,7 @@ mod tests { def_map, local_def_map: LocalDefMap::default(), crate_local_def_map: None, - deps: FxHashMap::default(), + deps: FxIndexMap::default(), glob_imports: FxHashMap::default(), unresolved_imports: Vec::new(), indeterminate_imports: Vec::new(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 25061e1dbdb9d..212fec4a4e4f4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2388,3 +2388,54 @@ pub trait Destruct {} "#, ); } + +#[test] +fn no_duplicated_lang_item_metadata() { + check_types( + r#" +//- minicore: pointee +//- /main.rs crate:main deps:std,core +use std::AtomicPtr; +use std::null_mut; + +fn main() { + let x: AtomicPtr<()> = AtomicPtr::new(null_mut()); + //^ AtomicPtr<()> +} + +//- /lib.rs crate:r#std deps:core +#![no_std] +pub use core::*; + +//- /lib.rs crate:r#core +#![no_core] + +#[lang = "pointee_trait"] +pub trait Pointee { + #[lang = "metadata_type"] + type Metadata; +} + +pub struct AtomicPtr(T); + +impl AtomicPtr { + pub fn new(p: *mut T) -> AtomicPtr { + loop {} + } +} + +#[lang = "pointee_sized"] +pub trait PointeeSized {} +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} +#[lang = "sized"] +pub trait Sized: MetaSized {} + +pub trait Thin = Pointee + PointeeSized; + +pub fn null_mut() -> *mut T { + loop {} +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 1f074de4cd7d2..9d2474d91da67 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -66,13 +66,9 @@ pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; pub use ::line_index; /// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience. -pub use base_db; +pub use base_db::{self, FxIndexMap, FxIndexSet}; pub use span::{self, FileId}; -pub type FxIndexSet = indexmap::IndexSet>; -pub type FxIndexMap = - indexmap::IndexMap>; - pub type FilePosition = FilePositionWrapper; pub type FileRange = FileRangeWrapper; diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 4413d2f222c15..57fca70547bf9 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -3,8 +3,8 @@ use std::{any::TypeId, mem, str::FromStr, sync}; use base_db::{ Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, - DependencyBuilder, Env, FileChange, FileSet, LangCrateOrigin, SourceDatabase, SourceRoot, - Version, VfsPath, salsa, + DependencyBuilder, Env, FileChange, FileSet, FxIndexMap, LangCrateOrigin, SourceDatabase, + SourceRoot, Version, VfsPath, salsa, }; use cfg::CfgOptions; use hir_expand::{ @@ -20,7 +20,6 @@ use hir_expand::{ }; use intern::{Symbol, sym}; use paths::AbsPathBuf; -use rustc_hash::FxHashMap; use span::{Edition, FileId, Span}; use stdx::itertools::Itertools; use test_utils::{ @@ -147,7 +146,7 @@ impl ChangeFixture { let mut files = Vec::new(); let mut crate_graph = CrateGraphBuilder::default(); - let mut crates = FxHashMap::default(); + let mut crates = FxIndexMap::default(); let mut crate_deps = Vec::new(); let mut default_crate_root: Option = None; let mut default_edition = Edition::CURRENT; @@ -249,37 +248,7 @@ impl ChangeFixture { file_id = FileId::from_raw(file_id.index() + 1); } - if crates.is_empty() { - let crate_root = default_crate_root - .expect("missing default crate root, specify a main.rs or lib.rs"); - crate_graph.add_crate_root( - crate_root, - default_edition, - Some(CrateName::new("ra_test_fixture").unwrap().into()), - None, - default_cfg.clone(), - Some(default_cfg), - default_env, - CrateOrigin::Local { repo: None, name: None }, - false, - proc_macro_cwd.clone(), - crate_ws_data.clone(), - ); - } else { - for (from, to, prelude) in crate_deps { - let from_id = crates[&from]; - let to_id = crates[&to]; - let sysroot = crate_graph[to_id].basic.origin.is_lang(); - crate_graph - .add_dep( - from_id, - DependencyBuilder::with_prelude(to.clone(), to_id, prelude, sysroot), - ) - .unwrap(); - } - } - - if let Some(mini_core) = mini_core { + let mini_core = mini_core.map(|mini_core| { let core_file = file_id; file_id = FileId::from_raw(file_id.index() + 1); @@ -289,8 +258,6 @@ impl ChangeFixture { source_change.change_file(core_file, Some(mini_core.source_code())); - let all_crates = crate_graph.iter().collect::>(); - let core_crate = crate_graph.add_crate_root( core_file, Edition::CURRENT, @@ -308,16 +275,58 @@ impl ChangeFixture { crate_ws_data.clone(), ); - for krate in all_crates { + ( + move || { + DependencyBuilder::with_prelude( + CrateName::new("core").unwrap(), + core_crate, + true, + true, + ) + }, + core_crate, + ) + }); + + if crates.is_empty() { + let crate_root = default_crate_root + .expect("missing default crate root, specify a main.rs or lib.rs"); + let root = crate_graph.add_crate_root( + crate_root, + default_edition, + Some(CrateName::new("ra_test_fixture").unwrap().into()), + None, + default_cfg.clone(), + Some(default_cfg), + default_env, + CrateOrigin::Local { repo: None, name: None }, + false, + proc_macro_cwd.clone(), + crate_ws_data.clone(), + ); + if let Some((mini_core, _)) = mini_core { + crate_graph.add_dep(root, mini_core()).unwrap(); + } + } else { + // Insert minicore first to match with `project-model::workspace` + if let Some((mini_core, core_crate)) = mini_core { + let all_crates = crate_graph.iter().collect::>(); + for krate in all_crates { + if krate == core_crate { + continue; + } + crate_graph.add_dep(krate, mini_core()).unwrap(); + } + } + + for (from, to, prelude) in crate_deps { + let from_id = crates[&from]; + let to_id = crates[&to]; + let sysroot = crate_graph[to_id].basic.origin.is_lang(); crate_graph .add_dep( - krate, - DependencyBuilder::with_prelude( - CrateName::new("core").unwrap(), - core_crate, - true, - true, - ), + from_id, + DependencyBuilder::with_prelude(to.clone(), to_id, prelude, sysroot), ) .unwrap(); } @@ -627,11 +636,23 @@ impl FileMeta { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ForceNoneLangOrigin { + Yes, + No, +} + fn parse_crate( crate_str: String, current_source_root_kind: SourceRootKind, explicit_non_workspace_member: bool, ) -> (String, CrateOrigin, Option) { + let (crate_str, force_non_lang_origin) = if let Some(s) = crate_str.strip_prefix("r#") { + (s.to_owned(), ForceNoneLangOrigin::Yes) + } else { + (crate_str, ForceNoneLangOrigin::No) + }; + // syntax: // "my_awesome_crate" // "my_awesome_crate@0.0.1,http://example.com" @@ -646,16 +667,25 @@ fn parse_crate( let non_workspace_member = explicit_non_workspace_member || matches!(current_source_root_kind, SourceRootKind::Library); - let origin = match LangCrateOrigin::from(&*name) { - LangCrateOrigin::Other => { - let name = Symbol::intern(&name); - if non_workspace_member { - CrateOrigin::Library { repo, name } - } else { - CrateOrigin::Local { repo, name: Some(name) } + let origin = if force_non_lang_origin == ForceNoneLangOrigin::Yes { + let name = Symbol::intern(&name); + if non_workspace_member { + CrateOrigin::Library { repo, name } + } else { + CrateOrigin::Local { repo, name: Some(name) } + } + } else { + match LangCrateOrigin::from(&*name) { + LangCrateOrigin::Other => { + let name = Symbol::intern(&name); + if non_workspace_member { + CrateOrigin::Library { repo, name } + } else { + CrateOrigin::Local { repo, name: Some(name) } + } } + origin => CrateOrigin::Lang(origin), } - origin => CrateOrigin::Lang(origin), }; (name, origin, version) From 9c7ef48a7bedda1847acb0bfdfe7271e2268c2b7 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 8 Aug 2025 02:06:01 +0000 Subject: [PATCH 059/251] Convert some of dyn_compatibility to next-solver and remove generic_predicates_without_parent_query --- .../rust-analyzer/crates/hir-ty/src/db.rs | 10 -- .../crates/hir-ty/src/dyn_compatibility.rs | 104 +++++++++++++----- .../rust-analyzer/crates/hir-ty/src/lower.rs | 16 --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 2 +- 4 files changed, 79 insertions(+), 53 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 6e24aea76d445..7a5daac69922f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -179,16 +179,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; - #[salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)] - fn generic_predicates_without_parent_with_diagnostics( - &self, - def: GenericDefId, - ) -> (GenericPredicates, Diagnostics); - - #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)] - #[salsa::transparent] - fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; - #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 2d21947ec60fc..f571b64464d92 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -13,6 +13,9 @@ use hir_def::{ TypeAliasId, lang_item::LangItem, signatures::TraitFlags, }; use rustc_hash::FxHashSet; +use rustc_type_ir::{ + AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, inherent::IntoKind, +}; use smallvec::SmallVec; use crate::{ @@ -21,6 +24,7 @@ use crate::{ db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, generics::{generics, trait_self_param_idx}, + next_solver::{DbInterner, SolverDefId, TraitPredicate}, to_chalk_trait_id, utils::elaborate_clause_supertraits, }; @@ -319,6 +323,61 @@ fn contains_illegal_self_type_reference>( t.visit_with(visitor.as_dyn(), outer_binder).is_break() } +fn contains_illegal_self_type_reference_ns< + 'db, + T: rustc_type_ir::TypeVisitable>, +>( + db: &'db dyn HirDatabase, + trait_: TraitId, + t: &T, + allow_self_projection: AllowSelfProjection, +) -> bool { + struct IllegalSelfTypeVisitor<'db> { + db: &'db dyn HirDatabase, + trait_: TraitId, + super_traits: Option>, + allow_self_projection: AllowSelfProjection, + } + impl<'db> rustc_type_ir::TypeVisitor> for IllegalSelfTypeVisitor<'db> { + type Result = ControlFlow<()>; + + fn visit_ty( + &mut self, + ty: as rustc_type_ir::Interner>::Ty, + ) -> Self::Result { + match ty.kind() { + rustc_type_ir::TyKind::Param(param) if param.index == 0 => ControlFlow::Break(()), + rustc_type_ir::TyKind::Param(_) => ControlFlow::Continue(()), + rustc_type_ir::TyKind::Alias(AliasTyKind::Projection, proj) => match self + .allow_self_projection + { + AllowSelfProjection::Yes => { + let trait_ = proj.trait_def_id(DbInterner::new_with(self.db, None, None)); + let trait_ = match trait_ { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + if self.super_traits.is_none() { + self.super_traits = Some(all_super_traits(self.db, self.trait_)); + } + if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) { + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self) + } + } + AllowSelfProjection::No => ty.super_visit_with(self), + }, + _ => ty.super_visit_with(self), + } + } + } + + let mut visitor = + IllegalSelfTypeVisitor { db, trait_, super_traits: None, allow_self_projection }; + t.visit_with(&mut visitor).is_break() +} + fn dyn_compatibility_violation_for_assoc_item( db: &dyn HirDatabase, trait_: TraitId, @@ -415,40 +474,33 @@ where cb(MethodViolationCode::UndispatchableReceiver)?; } - let predicates = &*db.generic_predicates_without_parent(func.into()); - let trait_self_idx = trait_self_param_idx(db, func.into()); + let predicates = &*db.generic_predicates_without_parent_ns(func.into()); for pred in predicates { - let pred = pred.skip_binders().skip_binders(); + let pred = pred.kind().skip_binder(); - if matches!(pred, WhereClause::TypeOutlives(_)) { + if matches!(pred, ClauseKind::TypeOutlives(_)) { continue; } // Allow `impl AutoTrait` predicates - if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred { - let trait_data = db.trait_signature(from_chalk_trait_id(*trait_id)); - if trait_data.flags.contains(TraitFlags::AUTO) - && substitution - .as_slice(Interner) - .first() - .and_then(|arg| arg.ty(Interner)) - .and_then(|ty| ty.bound_var(Interner)) - .is_some_and(|b| { - b.debruijn == DebruijnIndex::ONE && Some(b.index) == trait_self_idx - }) - { - continue; - } + let interner = DbInterner::new_with(db, None, None); + if let ClauseKind::Trait(TraitPredicate { + trait_ref: pred_trait_ref, + polarity: PredicatePolarity::Positive, + }) = pred + && let SolverDefId::TraitId(trait_id) = pred_trait_ref.def_id + && let trait_data = db.trait_signature(trait_id) + && trait_data.flags.contains(TraitFlags::AUTO) + && pred_trait_ref.self_ty() + == crate::next_solver::Ty::new( + interner, + rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0 }), + ) + { + continue; } - if contains_illegal_self_type_reference( - db, - func.into(), - trait_, - pred, - DebruijnIndex::ONE, - AllowSelfProjection::Yes, - ) { + if contains_illegal_self_type_reference_ns(db, trait_, &pred, AllowSelfProjection::Yes) { cb(MethodViolationCode::WhereClauseReferencesSelf)?; break; } 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 7b6b3c3f8181a..065d2ea084070 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1179,22 +1179,6 @@ pub(crate) fn generic_predicates_query( generic_predicates_filtered_by(db, def, |_, _| true).0 } -pub(crate) fn generic_predicates_without_parent_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates { - db.generic_predicates_without_parent_with_diagnostics(def).0 -} - -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent -pub(crate) fn generic_predicates_without_parent_with_diagnostics_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> (GenericPredicates, Diagnostics) { - generic_predicates_filtered_by(db, def, |_, d| d == def) -} - /// Resolve the where clause(s) of an item with generics, /// with a given filter fn generic_predicates_filtered_by( diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 4eb50c1c31c52..11486ec8d6690 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -3750,7 +3750,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.generic_predicates_without_parent_with_diagnostics(def).1, + db.generic_predicates_without_parent_with_diagnostics_ns(def).1, &source_map, ); for (param_id, param) in generics.iter_type_or_consts() { From a25a1e34eca61265a78593e5438062033b68f2ca Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 8 Aug 2025 21:10:47 +0000 Subject: [PATCH 060/251] Convert more of dyn_compatibility to next-solver --- .../crates/hir-ty/src/dyn_compatibility.rs | 253 +++++++++--------- 1 file changed, 123 insertions(+), 130 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index f571b64464d92..237cc34d7099b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -4,7 +4,6 @@ use std::ops::ControlFlow; use chalk_ir::{ DebruijnIndex, - cast::Cast, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, }; use chalk_solve::rust_ir::InlineBound; @@ -12,20 +11,26 @@ use hir_def::{ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, lang_item::LangItem, signatures::TraitFlags, }; +use intern::Symbol; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, inherent::IntoKind, + AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _, + Upcast, + inherent::{IntoKind, SliceLike}, }; use smallvec::SmallVec; use crate::{ - AliasEq, AliasTy, Binders, BoundVar, CallableSig, DomainGoal, GoalData, ImplTraitId, Interner, - OpaqueTyId, ProjectionTyExt, Substitution, TraitRef, Ty, TyKind, WhereClause, all_super_traits, - db::HirDatabase, + AliasEq, AliasTy, Binders, BoundVar, ImplTraitId, Interner, ProjectionTyExt, Ty, TyKind, + WhereClause, all_super_traits, + db::{HirDatabase, InternedOpaqueTyId}, from_assoc_type_id, from_chalk_trait_id, - generics::{generics, trait_self_param_idx}, - next_solver::{DbInterner, SolverDefId, TraitPredicate}, - to_chalk_trait_id, + generics::trait_self_param_idx, + next_solver::{ + Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TypingMode, + infer::DbInternerInferExt, mk_param, + }, + traits::next_trait_solve_in_ctxt, utils::elaborate_clause_supertraits, }; @@ -434,26 +439,17 @@ where cb(MethodViolationCode::AsyncFn)?; } - let sig = db.callable_item_signature(func.into()); - if sig.skip_binders().params().iter().skip(1).any(|ty| { - contains_illegal_self_type_reference( - db, - func.into(), - trait_, - ty, - DebruijnIndex::INNERMOST, - AllowSelfProjection::Yes, - ) + let sig = db.callable_item_signature_ns(func.into()); + if sig.skip_binder().inputs().iter().skip(1).any(|ty| { + contains_illegal_self_type_reference_ns(db, trait_, &ty, AllowSelfProjection::Yes) }) { cb(MethodViolationCode::ReferencesSelfInput)?; } - if contains_illegal_self_type_reference( + if contains_illegal_self_type_reference_ns( db, - func.into(), trait_, - sig.skip_binders().ret(), - DebruijnIndex::INNERMOST, + &sig.skip_binder().output(), AllowSelfProjection::Yes, ) { cb(MethodViolationCode::ReferencesSelfOutput)?; @@ -483,7 +479,7 @@ where } // Allow `impl AutoTrait` predicates - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); if let ClauseKind::Trait(TraitPredicate { trait_ref: pred_trait_ref, polarity: PredicatePolarity::Positive, @@ -509,34 +505,30 @@ where ControlFlow::Continue(()) } -fn receiver_is_dispatchable( +fn receiver_is_dispatchable<'db>( db: &dyn HirDatabase, trait_: TraitId, func: FunctionId, - sig: &Binders, + sig: &crate::next_solver::EarlyBinder< + 'db, + crate::next_solver::Binder<'db, rustc_type_ir::FnSig>>, + >, ) -> bool { - let Some(trait_self_idx) = trait_self_param_idx(db, func.into()) else { - return false; - }; + let sig = sig.instantiate_identity(); + + let interner: DbInterner<'_> = DbInterner::new_with(db, Some(trait_.krate(db)), None); + let self_param_ty = crate::next_solver::Ty::new( + interner, + rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0 }), + ); // `self: Self` can't be dispatched on, but this is already considered dyn-compatible // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 - if sig - .skip_binders() - .params() - .first() - .and_then(|receiver| receiver.bound_var(Interner)) - .is_some_and(|b| { - b == BoundVar { debruijn: DebruijnIndex::INNERMOST, index: trait_self_idx } - }) - { + if sig.inputs().iter().next().is_some_and(|p| p.skip_binder() == self_param_ty) { return true; } - let placeholder_subst = generics(db, func.into()).placeholder_subst(db); - - let substituted_sig = sig.clone().substitute(Interner, &placeholder_subst); - let Some(receiver_ty) = substituted_sig.params().first() else { + let Some(&receiver_ty) = sig.inputs().skip_binder().as_slice().first() else { return false; }; @@ -549,118 +541,119 @@ fn receiver_is_dispatchable( return false; }; - // Type `U` - let unsized_self_ty = - TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner); - // `Receiver[Self => U]` - let Some(unsized_receiver_ty) = receiver_for_self_ty(db, func, unsized_self_ty.clone()) else { + let meta_sized_did = LangItem::MetaSized.resolve_trait(db, krate); + let Some(meta_sized_did) = meta_sized_did else { return false; }; - let self_ty = placeholder_subst.as_slice(Interner)[trait_self_idx].assert_ty_ref(Interner); - let unsized_predicate = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(unsize_did), - substitution: Substitution::from_iter(Interner, [self_ty.clone(), unsized_self_ty.clone()]), - }); - let unsized_predicate = - Binders::empty(Interner, unsized_predicate.cast::(Interner)); - let trait_predicate = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(trait_), - substitution: Substitution::from_iter( - Interner, - std::iter::once(unsized_self_ty.cast(Interner)) - .chain(placeholder_subst.iter(Interner).skip(1).cloned()), - ), - }); - let trait_predicate = Binders::empty(Interner, trait_predicate.cast::(Interner)); - - let generic_predicates = &*db.generic_predicates(func.into()); + // Type `U` + let unsized_self_ty = crate::next_solver::Ty::new_param(interner, u32::MAX, Symbol::empty()); + // `Receiver[Self => U]` + let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty); + + let param_env = { + let generic_predicates = &*db.generic_predicates_ns(func.into()); + + // Self: Unsize + let unsize_predicate = crate::next_solver::TraitRef::new( + interner, + SolverDefId::TraitId(unsize_did), + [self_param_ty, unsized_self_ty], + ); + + // U: Trait + let trait_def_id = SolverDefId::TraitId(trait_); + let args = GenericArgs::for_item(interner, trait_def_id, |name, index, kind, _| { + if index == 0 { unsized_self_ty.into() } else { mk_param(index, name, kind) } + }); + let trait_predicate = + crate::next_solver::TraitRef::new_from_args(interner, trait_def_id, args); + + let meta_sized_predicate = crate::next_solver::TraitRef::new( + interner, + SolverDefId::TraitId(meta_sized_did), + [unsized_self_ty], + ); + + ParamEnv { + clauses: Clauses::new_from_iter( + interner, + generic_predicates.iter().copied().chain([ + unsize_predicate.upcast(interner), + trait_predicate.upcast(interner), + meta_sized_predicate.upcast(interner), + ]), + ), + } + }; - let goals = std::iter::once(unsized_predicate).chain(std::iter::once(trait_predicate)).chain( - generic_predicates.iter().map(|pred| { - pred.clone() - .substitute(Interner, &placeholder_subst) - .map(|g| g.cast::(Interner)) - }), - ); - let clauses = chalk_ir::ProgramClauses::from_iter( - Interner, - goals.into_iter().map(|g| { - chalk_ir::ProgramClause::new( - Interner, - chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication { - consequence: g, - conditions: chalk_ir::Goals::empty(Interner), - constraints: chalk_ir::Constraints::empty(Interner), - priority: chalk_ir::ClausePriority::High, - })), - ) - }), + // Receiver: DispatchFromDyn U]> + let predicate = crate::next_solver::TraitRef::new( + interner, + SolverDefId::TraitId(dispatch_from_dyn_did), + [receiver_ty, unsized_receiver_ty], ); - let env: chalk_ir::Environment = chalk_ir::Environment { clauses }; - - let obligation = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(dispatch_from_dyn_did), - substitution: Substitution::from_iter(Interner, [receiver_ty.clone(), unsized_receiver_ty]), - }); - let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(obligation)).intern(Interner); - - let in_env = chalk_ir::InEnvironment::new(&env, goal); + let goal = crate::next_solver::Goal::new(interner, param_env, predicate); - let mut table = chalk_solve::infer::InferenceTable::::new(); - let canonicalized = table.canonicalize(Interner, in_env); - - db.trait_solve(krate, None, canonicalized.quantified).certain() + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + // the receiver is dispatchable iff the obligation holds + let res = next_trait_solve_in_ctxt(&infcx, goal); + res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) } -fn receiver_for_self_ty(db: &dyn HirDatabase, func: FunctionId, ty: Ty) -> Option { - let generics = generics(db, func.into()); - let trait_self_idx = trait_self_param_idx(db, func.into())?; - let subst = generics.placeholder_subst(db); - let subst = Substitution::from_iter( - Interner, - subst.iter(Interner).enumerate().map(|(idx, arg)| { - if idx == trait_self_idx { ty.clone().cast(Interner) } else { arg.clone() } - }), +fn receiver_for_self_ty<'db>( + interner: DbInterner<'db>, + func: FunctionId, + receiver_ty: crate::next_solver::Ty<'db>, + self_ty: crate::next_solver::Ty<'db>, +) -> crate::next_solver::Ty<'db> { + let args = crate::next_solver::GenericArgs::for_item( + interner, + SolverDefId::FunctionId(func), + |name, index, kind, _| { + if index == 0 { self_ty.into() } else { mk_param(index, name, kind) } + }, ); - let sig = db.callable_item_signature(func.into()); - let sig = sig.substitute(Interner, &subst); - sig.params_and_return.first().cloned() + + + crate::next_solver::EarlyBinder::bind(receiver_ty).instantiate(interner, args) } -fn contains_illegal_impl_trait_in_trait( - db: &dyn HirDatabase, - sig: &Binders, +fn contains_illegal_impl_trait_in_trait<'db>( + db: &'db dyn HirDatabase, + sig: &crate::next_solver::EarlyBinder< + 'db, + crate::next_solver::Binder<'db, rustc_type_ir::FnSig>>, + >, ) -> Option { - struct OpaqueTypeCollector(FxHashSet); - - impl TypeVisitor for OpaqueTypeCollector { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } + struct OpaqueTypeCollector(FxHashSet); - fn interner(&self) -> Interner { - Interner - } + impl<'db> rustc_type_ir::TypeVisitor> for OpaqueTypeCollector { + type Result = ControlFlow<()>; - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { - if let TyKind::OpaqueType(opaque_ty_id, _) = ty.kind(Interner) { - self.0.insert(*opaque_ty_id); + fn visit_ty( + &mut self, + ty: as rustc_type_ir::Interner>::Ty, + ) -> Self::Result { + if let rustc_type_ir::TyKind::Alias(AliasTyKind::Opaque, op) = ty.kind() { + let id = match op.def_id { + SolverDefId::InternedOpaqueTyId(id) => id, + _ => unreachable!(), + }; + self.0.insert(id); } - ty.super_visit_with(self.as_dyn(), outer_binder) + ty.super_visit_with(self) } } - let ret = sig.skip_binders().ret(); + let ret = sig.skip_binder().output(); let mut visitor = OpaqueTypeCollector(FxHashSet::default()); - _ = ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST); + _ = ret.visit_with(&mut visitor); // Since we haven't implemented RPITIT in proper way like rustc yet, // just check whether `ret` contains RPIT for now for opaque_ty in visitor.0 { - let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.into()); + let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty); if matches!(impl_trait_id, ImplTraitId::ReturnTypeImplTrait(..)) { return Some(MethodViolationCode::ReferencesImplTraitInTrait); } From 3f78a1fd5af1bc436062b9b5045b813304b9bb05 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Sat, 9 Aug 2025 23:28:48 +0000 Subject: [PATCH 061/251] impl HirDisplay for next_solver::Ty --- .../crates/hir-ty/src/consteval_nextsolver.rs | 8 +- .../crates/hir-ty/src/display.rs | 551 ++++++++++-------- .../crates/hir-ty/src/dyn_compatibility.rs | 1 - .../rust-analyzer/crates/hir-ty/src/layout.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 23 + .../crates/hir-ty/src/next_solver/mapping.rs | 7 +- .../next_solver/project/solve_normalize.rs | 13 +- .../crates/hir-ty/src/primitive.rs | 34 ++ .../rust-analyzer/crates/hir-ty/src/tests.rs | 40 +- .../hir-ty/src/tests/closure_captures.rs | 12 +- .../crates/hir-ty/src/tests/opaque_types.rs | 2 +- .../crates/hir-ty/src/tests/regression.rs | 6 +- .../crates/hir-ty/src/tests/traits.rs | 52 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 13 +- .../ide-completion/src/context/tests.rs | 7 +- .../crates/ide/src/hover/render.rs | 2 +- .../crates/ide/src/inlay_hints.rs | 76 +-- .../crates/ide/src/inlay_hints/adjustment.rs | 18 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 12 +- .../crates/ide/src/navigation_target.rs | 11 +- .../rust-analyzer/crates/ide/src/runnables.rs | 18 +- .../crates/ide/src/signature_help.rs | 5 +- .../crates/ide/src/static_index.rs | 52 +- .../crates/ide/src/view_memory_layout.rs | 9 +- 24 files changed, 584 insertions(+), 392 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index da4aff54de378..cdf861290ab92 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -132,9 +132,9 @@ pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Cr ) } -pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option { +pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { let interner = DbInterner::new_with(db, None, None); - match (*c).kind() { + match c.kind() { ConstKind::Param(_) => None, ConstKind::Infer(_) => None, ConstKind::Bound(_, _) => None, @@ -147,7 +147,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< }; let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner); - try_const_usize(db, &ec) + try_const_usize(db, ec) } ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().0, false))), ConstKind::Error(_) => None, @@ -212,7 +212,7 @@ pub(crate) fn const_eval_discriminant_variant( let c = if is_signed { try_const_isize(db, &c).unwrap() } else { - try_const_usize(db, &c).unwrap() as i128 + try_const_usize(db, c).unwrap() as i128 }; Ok(c) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 8f35a3c214551..9f87c37834d77 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -11,8 +11,8 @@ use base_db::Crate; use chalk_ir::{BoundVar, Safety, TyKind}; use either::Either; use hir_def::{ - GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, - ModuleId, TraitId, + GenericDefId, HasModule, ImportPathConfig, LocalFieldId, Lookup, ModuleDefId, ModuleId, + TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -37,26 +37,34 @@ use rustc_apfloat::{ ieee::{Half as f16, Quad as f128}, }; use rustc_hash::FxHashSet; +use rustc_type_ir::{ + AliasTyKind, + inherent::{AdtDef, IntoKind, SliceLike}, +}; use smallvec::SmallVec; use span::Edition; use stdx::never; use triomphe::Arc; use crate::{ - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, - ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, - LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, - QuantifiedWhereClause, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, - TyExt, WhereClause, - consteval::try_const_usize, + AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, + ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, + LifetimeOutlives, MemoryMap, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, + TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval_nextsolver, db::{HirDatabase, InternedClosure}, - from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, + from_assoc_type_id, from_placeholder_idx, generics::generics, infer::normalize, layout::Layout, lt_from_placeholder_idx, - mapping::from_chalk, mir::pad16, + next_solver::{ + BoundExistentialPredicate, Ctor, DbInterner, GenericArgs, SolverDefId, + mapping::{ + ChalkToNextSolver, convert_args_for_result, convert_const_for_result, + convert_region_for_result, convert_ty_for_result, + }, + }, primitive, to_assoc_type_id, utils::{self, ClosureSubst, detect_variant_from_bytes}, }; @@ -185,6 +193,29 @@ impl HirFormatter<'_> { DisplayLifetime::Never => false, } } + + fn render_region(&self, lifetime: crate::next_solver::Region<'_>) -> bool { + match self.display_lifetimes { + DisplayLifetime::Always => true, + DisplayLifetime::OnlyStatic => { + matches!(lifetime.kind(), rustc_type_ir::RegionKind::ReStatic) + } + DisplayLifetime::OnlyNamed => { + matches!( + lifetime.kind(), + rustc_type_ir::RegionKind::RePlaceholder(_) + | rustc_type_ir::RegionKind::ReEarlyParam(_) + ) + } + DisplayLifetime::OnlyNamedOrStatic => matches!( + lifetime.kind(), + rustc_type_ir::RegionKind::ReStatic + | rustc_type_ir::RegionKind::RePlaceholder(_) + | rustc_type_ir::RegionKind::ReEarlyParam(_) + ), + DisplayLifetime::Never => false, + } + } } pub trait HirDisplay { @@ -476,10 +507,6 @@ impl DisplayKind { matches!(self, Self::SourceCode { .. }) } - fn is_test(self) -> bool { - matches!(self, Self::Test) - } - fn allows_opaque(self) -> bool { match self { Self::SourceCode { allow_opaque, .. } => allow_opaque, @@ -721,59 +748,87 @@ fn render_const_scalar( ty: &Ty, ) -> Result<(), HirDisplayError> { let trait_env = TraitEnvironment::empty(f.krate()); + let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); let ty = normalize(f.db, trait_env.clone(), ty.clone()); - match ty.kind(Interner) { - TyKind::Scalar(s) => match s { - Scalar::Bool => write!(f, "{}", b[0] != 0), - Scalar::Char => { - let it = u128::from_le_bytes(pad16(b, false)) as u32; - let Ok(c) = char::try_from(it) else { - return f.write_str(""); - }; - write!(f, "{c:?}") - } - Scalar::Int(_) => { - let it = i128::from_le_bytes(pad16(b, true)); - write!(f, "{it}") - } - Scalar::Uint(_) => { - let it = u128::from_le_bytes(pad16(b, false)); - write!(f, "{it}") - } - Scalar::Float(fl) => match fl { - chalk_ir::FloatTy::F16 => { - // FIXME(#17451): Replace with builtins once they are stabilised. - let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into()); - let s = it.to_string(); - if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { - // Match Rust debug formatting - write!(f, "{s}.0") - } else { - write!(f, "{s}") - } - } - chalk_ir::FloatTy::F32 => { - let it = f32::from_le_bytes(b.try_into().unwrap()); - write!(f, "{it:?}") - } - chalk_ir::FloatTy::F64 => { - let it = f64::from_le_bytes(b.try_into().unwrap()); - write!(f, "{it:?}") + let ty = ty.to_nextsolver(interner); + render_const_scalar_inner(f, b, memory_map, ty, trait_env, interner) +} + +fn render_const_scalar_ns( + f: &mut HirFormatter<'_>, + b: &[u8], + memory_map: &MemoryMap, + ty: crate::next_solver::Ty<'_>, +) -> Result<(), HirDisplayError> { + let trait_env = TraitEnvironment::empty(f.krate()); + let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); + let ty = crate::next_solver::project::solve_normalize::normalize( + interner, + trait_env.env.to_nextsolver(interner), + ty, + ); + render_const_scalar_inner(f, b, memory_map, ty, trait_env, interner) +} + +fn render_const_scalar_inner( + f: &mut HirFormatter<'_>, + b: &[u8], + memory_map: &MemoryMap, + ty: crate::next_solver::Ty<'_>, + trait_env: Arc, + interner: DbInterner<'_>, +) -> Result<(), HirDisplayError> { + use rustc_type_ir::TyKind; + match ty.kind() { + TyKind::Bool => write!(f, "{}", b[0] != 0), + TyKind::Char => { + let it = u128::from_le_bytes(pad16(b, false)) as u32; + let Ok(c) = char::try_from(it) else { + return f.write_str(""); + }; + write!(f, "{c:?}") + } + TyKind::Int(_) => { + let it = i128::from_le_bytes(pad16(b, true)); + write!(f, "{it}") + } + TyKind::Uint(_) => { + let it = u128::from_le_bytes(pad16(b, false)); + write!(f, "{it}") + } + TyKind::Float(fl) => match fl { + rustc_type_ir::FloatTy::F16 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into()); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") } - chalk_ir::FloatTy::F128 => { - // FIXME(#17451): Replace with builtins once they are stabilised. - let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap())); - let s = it.to_string(); - if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { - // Match Rust debug formatting - write!(f, "{s}.0") - } else { - write!(f, "{s}") - } + } + rustc_type_ir::FloatTy::F32 => { + let it = f32::from_le_bytes(b.try_into().unwrap()); + write!(f, "{it:?}") + } + rustc_type_ir::FloatTy::F64 => { + let it = f64::from_le_bytes(b.try_into().unwrap()); + write!(f, "{it:?}") + } + rustc_type_ir::FloatTy::F128 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap())); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") } - }, + } }, - TyKind::Ref(_, _, t) => match t.kind(Interner) { + TyKind::Ref(_, t, _) => match t.kind() { TyKind::Str => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); @@ -786,7 +841,7 @@ fn render_const_scalar( TyKind::Slice(ty) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); - let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else { + let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env) else { return f.write_str(""); }; let size_one = layout.size.bytes_usize(); @@ -810,11 +865,11 @@ fn render_const_scalar( f.write_str(", ")?; } let offset = size_one * i; - render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?; + render_const_scalar_ns(f, &bytes[offset..offset + size_one], memory_map, ty)?; } f.write_str("]") } - TyKind::Dyn(_) => { + TyKind::Dynamic(_, _, _) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); let Ok(t) = memory_map.vtable_ty(ty_id) else { @@ -828,15 +883,16 @@ fn render_const_scalar( return f.write_str(""); }; f.write_str("&")?; - render_const_scalar(f, bytes, memory_map, t) + render_const_scalar_ns(f, bytes, memory_map, t.to_nextsolver(interner)) } - TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.0 { - hir_def::AdtId::StructId(s) => { + TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id() { + SolverDefId::AdtId(hir_def::AdtId::StructId(s)) => { let data = f.db.struct_signature(s); write!(f, "&{}", data.name.display(f.db, f.edition()))?; Ok(()) } - _ => f.write_str(""), + SolverDefId::AdtId(_) => f.write_str(""), + _ => unreachable!(), }, _ => { let addr = usize::from_le_bytes(match b.try_into() { @@ -850,7 +906,7 @@ fn render_const_scalar( return f.write_str(""); } }); - let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else { + let Ok(layout) = f.db.layout_of_ty_ns(t, trait_env) else { return f.write_str(""); }; let size = layout.size.bytes_usize(); @@ -858,37 +914,40 @@ fn render_const_scalar( return f.write_str(""); }; f.write_str("&")?; - render_const_scalar(f, bytes, memory_map, t) + render_const_scalar_ns(f, bytes, memory_map, t) } }, - TyKind::Tuple(_, subst) => { - let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else { + TyKind::Tuple(tys) => { + let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env.clone()) else { return f.write_str(""); }; f.write_str("(")?; let mut first = true; - for (id, ty) in subst.iter(Interner).enumerate() { + for (id, ty) in tys.iter().enumerate() { if first { first = false; } else { f.write_str(", ")?; } - let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument let offset = layout.fields.offset(id).bytes_usize(); - let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env.clone()) else { f.write_str("")?; continue; }; let size = layout.size.bytes_usize(); - render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?; + render_const_scalar_ns(f, &b[offset..offset + size], memory_map, ty)?; } f.write_str(")") } - TyKind::Adt(adt, subst) => { - let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else { + TyKind::Adt(def, args) => { + let def = match def.def_id() { + SolverDefId::AdtId(def) => def, + _ => unreachable!(), + }; + let Ok(layout) = f.db.layout_of_adt_ns(def, args, trait_env.clone()) else { return f.write_str(""); }; - match adt.0 { + match def { hir_def::AdtId::StructId(s) => { let data = f.db.struct_signature(s); write!(f, "{}", data.name.display(f.db, f.edition()))?; @@ -897,9 +956,9 @@ fn render_const_scalar( s.fields(f.db), f, &field_types, - f.db.trait_environment(adt.0.into()), + f.db.trait_environment(def.into()), &layout, - subst, + args, b, memory_map, ) @@ -929,9 +988,9 @@ fn render_const_scalar( var_id.fields(f.db), f, &field_types, - f.db.trait_environment(adt.0.into()), + f.db.trait_environment(def.into()), var_layout, - subst, + args, b, memory_map, ) @@ -939,16 +998,16 @@ fn render_const_scalar( } } TyKind::FnDef(..) => ty.hir_fmt(f), - TyKind::Function(_) | TyKind::Raw(_, _) => { + TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => { let it = u128::from_le_bytes(pad16(b, false)); write!(f, "{it:#X} as ")?; ty.hir_fmt(f) } TyKind::Array(ty, len) => { - let Some(len) = try_const_usize(f.db, len) else { + let Some(len) = consteval_nextsolver::try_const_usize(f.db, len) else { return f.write_str(""); }; - let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else { + let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env) else { return f.write_str(""); }; let size_one = layout.size.bytes_usize(); @@ -961,7 +1020,7 @@ fn render_const_scalar( f.write_str(", ")?; } let offset = size_one * i; - render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?; + render_const_scalar_ns(f, &b[offset..offset + size_one], memory_map, ty)?; } f.write_str("]") } @@ -969,17 +1028,19 @@ fn render_const_scalar( TyKind::Closure(_, _) => f.write_str(""), TyKind::Coroutine(_, _) => f.write_str(""), TyKind::CoroutineWitness(_, _) => f.write_str(""), + TyKind::CoroutineClosure(_, _) => f.write_str(""), + TyKind::UnsafeBinder(_) => f.write_str(""), // The below arms are unreachable, since const eval will bail out before here. TyKind::Foreign(_) => f.write_str(""), - TyKind::Error + TyKind::Pat(_, _) => f.write_str(""), + TyKind::Error(..) | TyKind::Placeholder(_) - | TyKind::Alias(_) - | TyKind::AssociatedType(_, _) - | TyKind::OpaqueType(_, _) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => f.write_str(""), + | TyKind::Alias(_, _) + | TyKind::Param(_) + | TyKind::Bound(_, _) + | TyKind::Infer(_) => f.write_str(""), // The below arms are unreachable, since we handled them in ref case. - TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str(""), + TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _, _) => f.write_str(""), } } @@ -989,15 +1050,18 @@ fn render_variant_after_name( field_types: &ArenaMap>, trait_env: Arc, layout: &Layout, - subst: &Substitution, + args: GenericArgs<'_>, b: &[u8], memory_map: &MemoryMap, ) -> Result<(), HirDisplayError> { + let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); match data.shape { FieldsShape::Record | FieldsShape::Tuple => { let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); - let ty = field_types[id].clone().substitute(Interner, subst); + let ty = field_types[id] + .clone() + .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else { return f.write_str(""); }; @@ -1045,18 +1109,30 @@ impl HirDisplay for Ty { &self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>, ) -> Result<(), HirDisplayError> { + let ty = self.to_nextsolver(DbInterner::new_with(db, None, None)); + ty.hir_fmt(f) + } +} + +impl<'db> HirDisplay for crate::next_solver::Ty<'db> { + fn hir_fmt( + &self, + f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>, + ) -> Result<(), HirDisplayError> { + let interner = DbInterner::new_with(db, None, None); if f.should_truncate() { return write!(f, "{TYPE_HINT_TRUNCATION}"); } - match self.kind(Interner) { + use rustc_type_ir::TyKind; + match self.kind() { TyKind::Never => write!(f, "!")?, TyKind::Str => write!(f, "str")?, - TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?, - TyKind::Scalar(Scalar::Char) => write!(f, "char")?, - &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?, - &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?, - &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?, + TyKind::Bool => write!(f, "bool")?, + TyKind::Char => write!(f, "char")?, + TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string_ns(t))?, + TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string_ns(t))?, + TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string_ns(t))?, TyKind::Slice(t) => { write!(f, "[")?; t.hir_fmt(f)?; @@ -1066,27 +1142,27 @@ impl HirDisplay for Ty { write!(f, "[")?; t.hir_fmt(f)?; write!(f, "; ")?; - c.hir_fmt(f)?; + convert_const_for_result(interner, c).hir_fmt(f)?; write!(f, "]")?; } - kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => { - if let TyKind::Ref(_, l, _) = kind { + kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => { + if let TyKind::Ref(l, _, _) = kind { f.write_char('&')?; - if f.render_lifetime(l) { - l.hir_fmt(f)?; + if f.render_region(l) { + convert_region_for_result(l).hir_fmt(f)?; f.write_char(' ')?; } match m { - Mutability::Not => (), - Mutability::Mut => f.write_str("mut ")?, + rustc_ast_ir::Mutability::Not => (), + rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?, } } else { write!( f, "*{}", match m { - Mutability::Not => "const ", - Mutability::Mut => "mut ", + rustc_ast_ir::Mutability::Not => "const ", + rustc_ast_ir::Mutability::Mut => "mut ", } )?; } @@ -1102,25 +1178,42 @@ impl HirDisplay for Ty { } }) }; - let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) { - TyKind::Dyn(dyn_ty) => { - let bounds = dyn_ty.bounds.skip_binders().interned(); - let render_lifetime = f.render_lifetime(&dyn_ty.lifetime); - (bounds.len() + render_lifetime as usize, contains_impl_fn(bounds)) + let contains_impl_fn_ns = |bounds: &[BoundExistentialPredicate<'_>]| { + bounds.iter().any(|bound| match bound.skip_binder() { + rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { + let trait_ = match trait_ref.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + fn_traits(db, trait_).any(|it| it == trait_) + } + _ => false, + }) + }; + let (preds_to_print, has_impl_fn_pred) = match t.kind() { + TyKind::Dynamic(bounds, region, _) => { + let render_lifetime = f.render_region(region); + ( + bounds.len() + render_lifetime as usize, + contains_impl_fn_ns(bounds.as_slice()), + ) } - TyKind::Alias(AliasTy::Opaque(OpaqueTy { - opaque_ty_id, - substitution: parameters, - })) - | TyKind::OpaqueType(opaque_ty_id, parameters) => { - let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); + TyKind::Alias(AliasTyKind::Opaque, ty) => { + let opaque_ty_id = match ty.def_id { + SolverDefId::InternedOpaqueTyId(id) => id, + _ => unreachable!(), + }; + let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id); if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id { let datas = db .return_type_impl_traits(func) .expect("impl trait id without data"); let data = (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - let bounds = data.substitute(Interner, parameters); + let bounds = data.substitute( + Interner, + &convert_args_for_result(interner, ty.args.as_slice()), + ); let mut len = bounds.skip_binders().len(); // Don't count Sized but count when it absent @@ -1167,24 +1260,31 @@ impl HirDisplay for Ty { t.hir_fmt(f)?; } } - TyKind::Tuple(_, substs) => { - if substs.len(Interner) == 1 { + TyKind::Tuple(tys) => { + if tys.len() == 1 { write!(f, "(")?; - substs.at(Interner, 0).hir_fmt(f)?; + tys.as_slice()[0].hir_fmt(f)?; write!(f, ",)")?; } else { write!(f, "(")?; - f.write_joined(substs.as_slice(Interner), ", ")?; + f.write_joined(tys.as_slice(), ", ")?; write!(f, ")")?; } } - TyKind::Function(fn_ptr) => { - let sig = CallableSig::from_fn_ptr(fn_ptr); + TyKind::FnPtr(sig, header) => { + let sig = CallableSig::from_fn_sig_and_header(interner, sig, header); sig.hir_fmt(f)?; } - TyKind::FnDef(def, parameters) => { - let def = from_chalk(db, *def); - let sig = db.callable_item_signature(def).substitute(Interner, parameters); + TyKind::FnDef(def, args) => { + let def = match def { + SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), + SolverDefId::Ctor(Ctor::Enum(e)) => CallableDefId::EnumVariantId(e), + SolverDefId::Ctor(Ctor::Struct(s)) => CallableDefId::StructId(s), + _ => unreachable!(), + }; + let sig = db + .callable_item_signature(def) + .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); if f.display_kind.is_source_code() { // `FnDef` is anonymous and there's no surface syntax for it. Show it as a @@ -1222,6 +1322,7 @@ impl HirDisplay for Ty { }; f.end_location_link(); + let parameters = convert_args_for_result(interner, args.as_slice()); if parameters.len(Interner) > 0 { let generic_def_id = GenericDefId::from_callable(db, def); let generics = generics(db, generic_def_id); @@ -1280,11 +1381,15 @@ impl HirDisplay for Ty { ret.hir_fmt(f)?; } } - TyKind::Adt(AdtId(def_id), parameters) => { - f.start_location_link((*def_id).into()); + TyKind::Adt(def, parameters) => { + let def_id = match def.def_id() { + SolverDefId::AdtId(id) => id, + _ => unreachable!(), + }; + f.start_location_link(def_id.into()); match f.display_kind { DisplayKind::Diagnostics | DisplayKind::Test => { - let name = match *def_id { + let name = match def_id { hir_def::AdtId::StructId(it) => db.struct_signature(it).name.clone(), hir_def::AdtId::UnionId(it) => db.union_signature(it).name.clone(), hir_def::AdtId::EnumId(it) => db.enum_signature(it).name.clone(), @@ -1294,7 +1399,7 @@ impl HirDisplay for Ty { DisplayKind::SourceCode { target_module_id: module_id, allow_opaque: _ } => { if let Some(path) = find_path::find_path( db, - ItemInNs::Types((*def_id).into()), + ItemInNs::Types(def_id.into()), module_id, PrefixKind::Plain, false, @@ -1316,55 +1421,49 @@ impl HirDisplay for Ty { } f.end_location_link(); - let generic_def = self.as_generic_def(db); - - hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?; + hir_fmt_generics( + f, + convert_args_for_result(interner, parameters.as_slice()).as_slice(Interner), + def.def_id().try_into().ok(), + None, + )?; } - TyKind::AssociatedType(assoc_type_id, parameters) => { - let type_alias = from_assoc_type_id(*assoc_type_id); - let trait_ = match type_alias.lookup(db).container { - ItemContainerId::TraitId(it) => it, - _ => panic!("not an associated type"), + TyKind::Alias(AliasTyKind::Projection, alias_ty) => { + let type_alias = match alias_ty.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), }; - let trait_data = db.trait_signature(trait_); - let type_alias_data = db.type_alias_signature(type_alias); - - // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) - if f.display_kind.is_test() { - f.start_location_link(trait_.into()); - write!(f, "{}", trait_data.name.display(f.db, f.edition()))?; - f.end_location_link(); - write!(f, "::")?; + let parameters = convert_args_for_result(interner, alias_ty.args.as_slice()); - f.start_location_link(type_alias.into()); - write!(f, "{}", type_alias_data.name.display(f.db, f.edition()))?; - f.end_location_link(); - // Note that the generic args for the associated type come before those for the - // trait (including the self type). - hir_fmt_generics(f, parameters.as_slice(Interner), None, None) - } else { - let projection_ty = ProjectionTy { - associated_ty_id: to_assoc_type_id(type_alias), - substitution: parameters.clone(), - }; + let projection_ty = ProjectionTy { + associated_ty_id: to_assoc_type_id(type_alias), + substitution: parameters.clone(), + }; - projection_ty.hir_fmt(f) - }?; + projection_ty.hir_fmt(f)?; } TyKind::Foreign(type_alias) => { - let alias = from_foreign_def_id(*type_alias); + let alias = match type_alias { + SolverDefId::ForeignId(id) => id, + _ => unreachable!(), + }; let type_alias = db.type_alias_signature(alias); f.start_location_link(alias.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); } - TyKind::OpaqueType(opaque_ty_id, parameters) => { + TyKind::Alias(AliasTyKind::Opaque, alias_ty) => { + let opaque_ty_id = match alias_ty.def_id { + SolverDefId::InternedOpaqueTyId(id) => id, + _ => unreachable!(), + }; + let parameters = convert_args_for_result(interner, alias_ty.args.as_slice()); if !f.display_kind.allows_opaque() { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::OpaqueType, )); } - let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into()); + let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id); match impl_trait_id { ImplTraitId::ReturnTypeImplTrait(func, idx) => { let datas = @@ -1376,7 +1475,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(self), + Either::Left(&convert_ty_for_result(interner, *self)), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1391,7 +1490,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(self), + Either::Left(&convert_ty_for_result(interner, *self)), bounds.skip_binders(), SizedByDefault::Sized { anchor: krate }, )?; @@ -1426,6 +1525,11 @@ impl HirDisplay for Ty { } } TyKind::Closure(id, substs) => { + let id = match id { + SolverDefId::InternedClosureId(id) => id, + _ => unreachable!(), + }; + let substs = convert_args_for_result(interner, substs.as_slice()); if f.display_kind.is_source_code() { if !f.display_kind.allows_opaque() { return Err(HirDisplayError::DisplaySourceCodeError( @@ -1435,22 +1539,23 @@ impl HirDisplay for Ty { never!("Only `impl Fn` is valid for displaying closures in source code"); } } + let chalk_id: chalk_ir::ClosureId<_> = id.into(); match f.closure_style { ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"), ClosureStyle::ClosureWithId => { - return write!(f, "{{closure#{:?}}}", id.0.index()); + return write!(f, "{{closure#{:?}}}", chalk_id.0.index()); } ClosureStyle::ClosureWithSubst => { - write!(f, "{{closure#{:?}}}", id.0.index())?; + write!(f, "{{closure#{:?}}}", chalk_id.0.index())?; return hir_fmt_generics(f, substs.as_slice(Interner), None, None); } _ => (), } - let sig = ClosureSubst(substs).sig_ty().callable_sig(db); + let sig = ClosureSubst(&substs).sig_ty().callable_sig(db); if let Some(sig) = sig { - let InternedClosure(def, _) = db.lookup_intern_closure((*id).into()); + let InternedClosure(def, _) = db.lookup_intern_closure(id); let infer = db.infer(def); - let (_, kind) = infer.closure_info(id); + let (_, kind) = infer.closure_info(&chalk_id); match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, ClosureStyle::RANotation => write!(f, "|")?, @@ -1478,7 +1583,11 @@ impl HirDisplay for Ty { } } TyKind::Placeholder(idx) => { - let id = from_placeholder_idx(db, *idx); + let placeholder_index = chalk_ir::PlaceholderIndex { + idx: idx.bound.var.as_usize(), + ui: chalk_ir::UniverseIndex { counter: idx.universe.as_usize() }, + }; + let id = from_placeholder_idx(db, placeholder_index); let generics = generics(db, id.parent); let param_data = &generics[id.local_id]; match param_data { @@ -1501,14 +1610,20 @@ impl HirDisplay for Ty { .map(|pred| pred.clone().substitute(Interner, &substs)) .filter(|wc| match wc.skip_binders() { WhereClause::Implemented(tr) => { - tr.self_type_parameter(Interner) == *self + tr.self_type_parameter(Interner) + == convert_ty_for_result(interner, *self) } WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _, - }) => proj.self_type_parameter(db) == *self, + }) => { + proj.self_type_parameter(db) + == convert_ty_for_result(interner, *self) + } WhereClause::AliasEq(_) => false, - WhereClause::TypeOutlives(to) => to.ty == *self, + WhereClause::TypeOutlives(to) => { + to.ty == convert_ty_for_result(interner, *self) + } WhereClause::LifetimeOutlives(_) => false, }) .collect::>(); @@ -1516,7 +1631,7 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(self), + Either::Left(&convert_ty_for_result(interner, *self)), &bounds, SizedByDefault::Sized { anchor: krate }, )?; @@ -1527,8 +1642,17 @@ impl HirDisplay for Ty { } } } - TyKind::BoundVar(idx) => idx.hir_fmt(f)?, - TyKind::Dyn(dyn_ty) => { + TyKind::Param(_) => write!(f, "{{param}}")?, + TyKind::Bound(debruijn_index, ty) => { + let idx = chalk_ir::BoundVar { + debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), + index: ty.var.as_usize(), + }; + idx.hir_fmt(f)? + } + TyKind::Dynamic(..) => { + let ty = convert_ty_for_result(interner, *self); + let chalk_ir::TyKind::Dyn(dyn_ty) = ty.kind(Interner) else { unreachable!() }; // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation. // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it // more efficient when either of them hits stable. @@ -1544,7 +1668,7 @@ impl HirDisplay for Ty { bounds.push(Binders::empty( Interner, chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: self.clone(), + ty: ty.clone(), lifetime: dyn_ty.lifetime.clone(), }), )); @@ -1553,69 +1677,26 @@ impl HirDisplay for Ty { write_bounds_like_dyn_trait_with_prefix( f, "dyn", - Either::Left(self), + Either::Left(&ty), &bounds, SizedByDefault::NotSized, )?; } - TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?, - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - if !f.display_kind.allows_opaque() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::OpaqueType, - )); - } - let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()); - match impl_trait_id { - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let datas = - db.return_type_impl_traits(func).expect("impl trait id without data"); - let data = - (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - let bounds = data.substitute(Interner, &opaque_ty.substitution); - let krate = func.krate(db); - write_bounds_like_dyn_trait_with_prefix( - f, - "impl", - Either::Left(self), - bounds.skip_binders(), - SizedByDefault::Sized { anchor: krate }, - )?; - } - ImplTraitId::TypeAliasImplTrait(alias, idx) => { - let datas = - db.type_alias_impl_traits(alias).expect("impl trait id without data"); - let data = - (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - let bounds = data.substitute(Interner, &opaque_ty.substitution); - let krate = alias.krate(db); - write_bounds_like_dyn_trait_with_prefix( - f, - "impl", - Either::Left(self), - bounds.skip_binders(), - SizedByDefault::Sized { anchor: krate }, - )?; - } - ImplTraitId::AsyncBlockTypeImplTrait(..) => { - write!(f, "{{async block}}")?; - } - }; - } - TyKind::Error => { + TyKind::Error(_) => { if f.display_kind.is_source_code() { f.write_char('_')?; } else { write!(f, "{{unknown}}")?; } } - TyKind::InferenceVar(..) => write!(f, "_")?, + TyKind::Infer(..) => write!(f, "_")?, TyKind::Coroutine(_, subst) => { if f.display_kind.is_source_code() { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::Coroutine, )); } + let subst = convert_args_for_result(interner, subst.as_slice()); let subst = subst.as_slice(Interner); let a: Option> = subst .get(subst.len() - 3..) @@ -1637,6 +1718,10 @@ impl HirDisplay for Ty { } } TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?, + TyKind::Pat(_, _) => write!(f, "{{pat}}")?, + TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?, + TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?, + TyKind::Alias(_, _) => write!(f, "{{alias}}")?, } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 237cc34d7099b..8bd555f5c08f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -615,7 +615,6 @@ fn receiver_for_self_ty<'db>( }, ); - crate::next_solver::EarlyBinder::bind(receiver_ty).instantiate(interner, args) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 2d0471d7e5545..fb7b5e1c83e4c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -153,7 +153,7 @@ fn layout_of_simd_ty<'db>( return Err(LayoutError::InvalidSimdType); }; - let e_len = try_const_usize(db, &e_len).ok_or(LayoutError::HasErrorConst)? as u64; + let e_len = try_const_usize(db, e_len).ok_or(LayoutError::HasErrorConst)? as u64; let e_ly = db.layout_of_ty_ns(e_ty, env)?; let cx = LayoutCx::new(dl); @@ -272,7 +272,7 @@ pub fn layout_of_ty_ns_query<'db>( cx.calc.univariant(&fields, &ReprOptions::default(), kind)? } TyKind::Array(element, count) => { - let count = try_const_usize(db, &count).ok_or(LayoutError::HasErrorConst)? as u64; + let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; let element = db.layout_of_ty_ns(element, trait_env)?; cx.calc.array_like::<_, _, ()>(&element, Some(count))? } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2b0dc931eaf4a..81894830b5b47 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -90,6 +90,7 @@ use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::SliceLike; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; @@ -100,6 +101,7 @@ use crate::{ display::{DisplayTarget, HirDisplay}, generics::Generics, infer::unify::InferenceTable, + next_solver::{DbInterner, mapping::convert_ty_for_result}, }; pub use autoderef::autoderef; @@ -560,6 +562,27 @@ impl CallableSig { abi: fn_ptr.sig.abi, } } + pub fn from_fn_sig_and_header<'db>( + interner: DbInterner<'db>, + sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys>>, + header: rustc_type_ir::FnHeader>, + ) -> CallableSig { + CallableSig { + // FIXME: what to do about lifetime params? -> return PolyFnSig + params_and_return: Arc::from_iter( + sig.skip_binder() + .inputs_and_output + .iter() + .map(|t| convert_ty_for_result(interner, t)), + ), + is_varargs: header.c_variadic, + safety: match header.safety { + next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, + next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, + }, + abi: header.abi, + } + } pub fn to_fn_ptr(&self) -> FnPointer { FnPointer { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 20cd8626f299b..b50fccb832625 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1290,7 +1290,10 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) .intern(Interner) } -fn convert_const_for_result<'db>(interner: DbInterner<'db>, const_: Const<'db>) -> crate::Const { +pub fn convert_const_for_result<'db>( + interner: DbInterner<'db>, + const_: Const<'db>, +) -> crate::Const { let value: chalk_ir::ConstValue = match const_.kind() { rustc_type_ir::ConstKind::Param(_) => unimplemented!(), rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { @@ -1343,7 +1346,7 @@ fn convert_const_for_result<'db>(interner: DbInterner<'db>, const_: Const<'db>) chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) } -fn convert_region_for_result<'db>(region: Region<'db>) -> crate::Lifetime { +pub fn convert_region_for_result<'db>(region: Region<'db>) -> crate::Lifetime { match region.kind() { rustc_type_ir::RegionKind::ReEarlyParam(early) => unimplemented!(), rustc_type_ir::RegionKind::ReBound(db, bound) => chalk_ir::Lifetime::new( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs index a8fb2ae14f1c3..42c238febf6f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/project/solve_normalize.rs @@ -11,16 +11,25 @@ use rustc_type_ir::{ use crate::next_solver::{ Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Span, Term, Ty, - TyKind, + TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ - InferCtxt, + DbInternerInferExt, InferCtxt, at::At, traits::{Obligation, ObligationCause}, }, util::PlaceholderReplacer, }; +pub fn normalize<'db, T>(interner: DbInterner<'db>, param_env: ParamEnv<'db>, value: T) -> T +where + T: TypeFoldable>, +{ + let infer_ctxt = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let cause = ObligationCause::dummy(); + deeply_normalize(infer_ctxt.at(&cause, param_env), value.clone()).unwrap_or(value) +} + /// Deeply normalize all aliases in `value`. This does not handle inference and expects /// its input to be already fully resolved. pub fn deeply_normalize<'db, T>(at: At<'_, 'db>, value: T) -> Result>> diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs index a4e077ba6359f..d2901f7fc53d2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs @@ -34,6 +34,40 @@ pub fn float_ty_to_string(ty: FloatTy) -> &'static str { } } +pub fn int_ty_to_string_ns(ty: rustc_type_ir::IntTy) -> &'static str { + use rustc_type_ir::IntTy; + match ty { + IntTy::Isize => "isize", + IntTy::I8 => "i8", + IntTy::I16 => "i16", + IntTy::I32 => "i32", + IntTy::I64 => "i64", + IntTy::I128 => "i128", + } +} + +pub fn uint_ty_to_string_ns(ty: rustc_type_ir::UintTy) -> &'static str { + use rustc_type_ir::UintTy; + match ty { + UintTy::Usize => "usize", + UintTy::U8 => "u8", + UintTy::U16 => "u16", + UintTy::U32 => "u32", + UintTy::U64 => "u64", + UintTy::U128 => "u128", + } +} + +pub fn float_ty_to_string_ns(ty: rustc_type_ir::FloatTy) -> &'static str { + use rustc_type_ir::FloatTy; + match ty { + FloatTy::F16 => "f16", + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + FloatTy::F128 => "f128", + } +} + pub(super) fn int_ty_from_builtin(t: BuiltinInt) -> IntTy { match t { BuiltinInt::Isize => IntTy::Isize, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index d98b6602efe8c..1c3da438cb364 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -157,11 +157,13 @@ fn check_impl( }; let range = node.as_ref().original_file_range_rooted(&db); if let Some(expected) = types.remove(&range) { - let actual = if display_source { - ty.display_source_code(&db, def.module(&db), true).unwrap() - } else { - ty.display_test(&db, display_target).to_string() - }; + let actual = salsa::attach(&db, || { + if display_source { + ty.display_source_code(&db, def.module(&db), true).unwrap() + } else { + ty.display_test(&db, display_target).to_string() + } + }); assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); } } @@ -173,11 +175,13 @@ fn check_impl( }; let range = node.as_ref().original_file_range_rooted(&db); if let Some(expected) = types.remove(&range) { - let actual = if display_source { - ty.display_source_code(&db, def.module(&db), true).unwrap() - } else { - ty.display_test(&db, display_target).to_string() - }; + let actual = salsa::attach(&db, || { + if display_source { + ty.display_source_code(&db, def.module(&db), true).unwrap() + } else { + ty.display_test(&db, display_target).to_string() + } + }); assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); } if let Some(expected) = adjustments.remove(&range) { @@ -203,11 +207,13 @@ fn check_impl( continue; }; let range = node.as_ref().original_file_range_rooted(&db); - let actual = format!( - "expected {}, got {}", - mismatch.expected.display_test(&db, display_target), - mismatch.actual.display_test(&db, display_target) - ); + let actual = salsa::attach(&db, || { + format!( + "expected {}, got {}", + mismatch.expected.display_test(&db, display_target), + mismatch.actual.display_test(&db, display_target) + ) + }); match mismatches.remove(&range) { Some(annotation) => assert_eq!(actual, annotation), None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual), @@ -402,7 +408,9 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (def, krate) in defs { let (body, source_map) = db.body_with_source_map(def); let infer = db.infer(def); - infer_def(infer, body, source_map, krate); + salsa::attach(&db, || { + infer_def(infer, body, source_map, krate); + }) } buf.truncate(buf.trim_end().len()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 5893894c33ab7..b001ac1e82ea2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -67,11 +67,13 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec .join(", "), }; let place = capture.display_place(closure.0, db); - let capture_ty = capture - .ty - .skip_binders() - .display_test(db, DisplayTarget::from_crate(db, module.krate())) - .to_string(); + let capture_ty = salsa::attach(db, || { + capture + .ty + .skip_binders() + .display_test(db, DisplayTarget::from_crate(db, module.krate())) + .to_string() + }); let spans = capture .spans() .iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs index 36578545a9f49..11d1a58e5367e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/opaque_types.rs @@ -71,7 +71,7 @@ fn test() { let x = S3.baz(); //^ Binary> let y = x.1.0.bar(); - //^ Unary> + //^ Unary<::Item> } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 212fec4a4e4f4..fd8c641d86eb0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2299,10 +2299,10 @@ trait Foo { } "#, expect![[r#" - 83..86 'bar': Foo::Bar + 83..86 'bar': ::Bar 105..133 '{ ... }': () - 119..120 '_': Foo::Bar - 123..126 'bar': Foo::Bar + 119..120 '_': ::Bar + 123..126 'bar': ::Bar "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 9d72105624a05..a311e579744df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -408,11 +408,11 @@ fn test() { let x: ::Item = 1; // ^ u32 let y: ::Item = u; - // ^ Iterable::Item + // ^ ::Item let z: T::Item = u; - // ^ Iterable::Item + // ^ ::Item let a: ::Item = u; - // ^ Iterable::Item + // ^ ::Item }"#, ); } @@ -454,7 +454,7 @@ impl S { fn test() { let s: S; s.foo(); - // ^^^^^^^ Iterable::Item + // ^^^^^^^ ::Item }"#, ); } @@ -470,7 +470,7 @@ trait Foo { type A; fn test(a: Self::A, _: impl Bar) { a; - //^ Foo::A + //^ ::A } }"#, ); @@ -969,7 +969,7 @@ impl ApplyL for RefMutL { fn test() { let y: as ApplyL>::Out = no_matter; y; -} //^ ApplyL::Out +} //^ ::Out "#, ); } @@ -986,7 +986,7 @@ fn foo(t: T) -> ::Out; fn test(t: T) { let y = foo(t); y; -} //^ ApplyL::Out +} //^ ::Out "#, ); } @@ -1695,7 +1695,7 @@ fn test>(x: T, y: impl Trait) { }"#, expect![[r#" 49..50 't': T - 77..79 '{}': Trait::Type + 77..79 '{}': ::Type 111..112 't': T 122..124 '{}': U 154..155 't': T @@ -2293,7 +2293,7 @@ impl Trait for S2 { }"#, expect![[r#" 40..44 'self': &'? Self - 46..47 'x': Trait::Item + 46..47 'x': ::Item 126..130 'self': &'? S 132..133 'x': u32 147..161 '{ let y = x; }': () @@ -2410,7 +2410,7 @@ trait Trait2 {} fn test() where T: Trait2 { let x: T::Item = no_matter; -} //^^^^^^^^^ Trait::Item +} //^^^^^^^^^ ::Item "#, ); } @@ -2445,7 +2445,7 @@ trait Trait { fn test() where T: Trait { let x: T::Item = no_matter; -} //^^^^^^^^^ Trait::Item +} //^^^^^^^^^ ::Item "#, ); } @@ -2475,7 +2475,7 @@ fn test(t: T) where T: UnificationStoreMut { t.push(x); let y: Key; (x, y); -} //^^^^^^ (UnificationStoreBase::Key, UnificationStoreBase::Key) +} //^^^^^^ (::Key, ::Key) "#, ); } @@ -3488,7 +3488,7 @@ fn foo() { let x = ::boo(); }"#, expect![[r#" - 132..163 '{ ... }': Bar::Output + 132..163 '{ ... }': ::Output 146..153 'loop {}': ! 151..153 '{}': () 306..358 '{ ...o(); }': () @@ -4213,7 +4213,7 @@ fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); //^ &'a T let a = v.get::<()>(); - //^ Trait::Assoc = &'a T>, ()> + //^ = &'a T> as Trait>::Assoc<()> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); @@ -4280,7 +4280,7 @@ where let a = t.get::(); //^ usize let a = t.get::<()>(); - //^ Trait::Assoc + //^ ::Assoc<()> } "#, @@ -4857,29 +4857,29 @@ async fn baz i32>(c: T) { 37..38 'a': T 43..83 '{ ...ait; }': () 43..83 '{ ...ait; }': impl Future - 53..57 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 53..57 'fut1': >::CallRefFuture<'?> 60..61 'a': T - 60..64 'a(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 60..64 'a(0)': >::CallRefFuture<'?> 62..63 '0': u32 - 70..74 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 70..74 'fut1': >::CallRefFuture<'?> 70..80 'fut1.await': i32 124..129 'mut b': T 134..174 '{ ...ait; }': () 134..174 '{ ...ait; }': impl Future - 144..148 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 144..148 'fut2': >::CallRefFuture<'?> 151..152 'b': T - 151..155 'b(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 151..155 'b(0)': >::CallRefFuture<'?> 153..154 '0': u32 - 161..165 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 161..165 'fut2': >::CallRefFuture<'?> 161..171 'fut2.await': i32 216..217 'c': T 222..262 '{ ...ait; }': () 222..262 '{ ...ait; }': impl Future - 232..236 'fut3': AsyncFnOnce::CallOnceFuture + 232..236 'fut3': >::CallOnceFuture 239..240 'c': T - 239..243 'c(0)': AsyncFnOnce::CallOnceFuture + 239..243 'c(0)': >::CallOnceFuture 241..242 '0': u32 - 249..253 'fut3': AsyncFnOnce::CallOnceFuture + 249..253 'fut3': >::CallOnceFuture 249..259 'fut3.await': i32 "#]], ); @@ -4947,7 +4947,7 @@ where "#, expect![[r#" 84..86 'de': D - 135..138 '{ }': Deserializer::Error<'de, D> + 135..138 '{ }': >::Error "#]], ); } @@ -5020,7 +5020,7 @@ fn main() { 294..298 'iter': Box + 'static> 294..310 'iter.i...iter()': Box + 'static> 152..156 'self': &'? mut Box - 177..208 '{ ... }': Option> + 177..208 '{ ... }': Option<::Item> 191..198 'loop {}': ! 196..198 '{}': () "#]], diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 11486ec8d6690..4dde019b50063 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -85,7 +85,9 @@ use hir_ty::{ layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution, mir::{MutBorrowKind, interpret_mir}, - next_solver::{DbInterner, GenericArgs, SolverDefId, infer::InferCtxt}, + next_solver::{ + DbInterner, GenericArgs, SolverDefId, infer::InferCtxt, mapping::ChalkToNextSolver, + }, primitive::UintTy, traits::FnTrait, }; @@ -1814,12 +1816,15 @@ impl Adt { } pub fn layout(self, db: &dyn HirDatabase) -> Result { - db.layout_of_adt( + let env = db.trait_environment(self.into()); + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + db.layout_of_adt_ns( self.into(), TyBuilder::adt(db, self.into()) .fill_with_defaults(db, || TyKind::Error.intern(Interner)) - .build_into_subst(), - db.trait_environment(self.into()), + .build_into_subst() + .to_nextsolver(interner), + env, ) .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 7a8c70f190efc..f03f61d10e5f7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -1,3 +1,4 @@ +use base_db::salsa; use expect_test::{Expect, expect}; use hir::HirDisplay; @@ -13,7 +14,11 @@ fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, let ty = completion_context .expected_type - .map(|t| t.display_test(&db, completion_context.krate.to_display_target(&db)).to_string()) + .map(|t| { + salsa::attach(&db, || { + t.display_test(&db, completion_context.krate.to_display_target(&db)).to_string() + }) + }) .unwrap_or("?".to_owned()); let name = diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index e4c7d42ffe3b1..1f9d10c92b1df 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -912,7 +912,7 @@ pub(super) fn literal( }; let ty = ty.display(sema.db, display_target); - let mut s = format!("```rust\n{ty}\n```\n___\n\n"); + let mut s = salsa::attach(sema.db, || format!("```rust\n{ty}\n```\n___\n\n")); match value { Ok(value) => { let backtick_len = value.chars().filter(|c| *c == '`').count(); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 424890fe370c4..d7d3171664945 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -738,44 +738,46 @@ fn label_of_ty( config: &InlayHintsConfig, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { - let iter_item_type = hint_iterator(sema, famous_defs, ty); - match iter_item_type { - Some((iter_trait, item, ty)) => { - const LABEL_START: &str = "impl "; - const LABEL_ITERATOR: &str = "Iterator"; - const LABEL_MIDDLE: &str = "<"; - const LABEL_ITEM: &str = "Item"; - const LABEL_MIDDLE2: &str = " = "; - const LABEL_END: &str = ">"; - - max_length = max_length.map(|len| { - len.saturating_sub( - LABEL_START.len() - + LABEL_ITERATOR.len() - + LABEL_MIDDLE.len() - + LABEL_MIDDLE2.len() - + LABEL_END.len(), - ) - }); - - label_builder.write_str(LABEL_START)?; - label_builder.start_location_link(ModuleDef::from(iter_trait).into()); - label_builder.write_str(LABEL_ITERATOR)?; - label_builder.end_location_link(); - label_builder.write_str(LABEL_MIDDLE)?; - label_builder.start_location_link(ModuleDef::from(item).into()); - label_builder.write_str(LABEL_ITEM)?; - label_builder.end_location_link(); - label_builder.write_str(LABEL_MIDDLE2)?; - rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?; - label_builder.write_str(LABEL_END)?; - Ok(()) + salsa::attach(sema.db, || { + let iter_item_type = hint_iterator(sema, famous_defs, ty); + match iter_item_type { + Some((iter_trait, item, ty)) => { + const LABEL_START: &str = "impl "; + const LABEL_ITERATOR: &str = "Iterator"; + const LABEL_MIDDLE: &str = "<"; + const LABEL_ITEM: &str = "Item"; + const LABEL_MIDDLE2: &str = " = "; + const LABEL_END: &str = ">"; + + max_length = max_length.map(|len| { + len.saturating_sub( + LABEL_START.len() + + LABEL_ITERATOR.len() + + LABEL_MIDDLE.len() + + LABEL_MIDDLE2.len() + + LABEL_END.len(), + ) + }); + + label_builder.write_str(LABEL_START)?; + label_builder.start_location_link(ModuleDef::from(iter_trait).into()); + label_builder.write_str(LABEL_ITERATOR)?; + label_builder.end_location_link(); + label_builder.write_str(LABEL_MIDDLE)?; + label_builder.start_location_link(ModuleDef::from(item).into()); + label_builder.write_str(LABEL_ITEM)?; + label_builder.end_location_link(); + label_builder.write_str(LABEL_MIDDLE2)?; + rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?; + label_builder.write_str(LABEL_END)?; + Ok(()) + } + None => ty + .display_truncated(sema.db, max_length, display_target) + .with_closure_style(config.closure_style) + .write_to(label_builder), } - None => ty - .display_truncated(sema.db, max_length, display_target) - .with_closure_style(config.closure_style) - .write_to(label_builder), - } + }) } let mut label_builder = InlayHintLabelBuilder { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 39554d777795c..e39a5f8889a2c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -10,7 +10,7 @@ use hir::{ Adjust, Adjustment, AutoBorrow, DisplayTarget, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety, }; -use ide_db::famous_defs::FamousDefs; +use ide_db::{base_db::salsa, famous_defs::FamousDefs}; use ide_db::text_edit::TextEditBuilder; use syntax::ast::{self, AstNode, prec::ExprPrecedence}; @@ -201,13 +201,15 @@ pub(super) fn hints( text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, linked_location: None, tooltip: Some(config.lazy_tooltip(|| { - InlayTooltip::Markdown(format!( - "`{}` → `{}`\n\n**{}**\n\n{}", - source.display(sema.db, display_target), - target.display(sema.db, display_target), - coercion, - detailed_tooltip - )) + salsa::attach(sema.db, || { + InlayTooltip::Markdown(format!( + "`{}` → `{}`\n\n**{}**\n\n{}", + source.display(sema.db, display_target), + target.display(sema.db, display_target), + coercion, + detailed_tooltip + )) + }) })), }; if postfix { &mut post } else { &mut pre }.label.append_part(label); diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 5349ebb7c82a5..1c66473bf9874 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -67,7 +67,7 @@ use ide_db::{ FxHashMap, FxIndexSet, LineIndexDatabase, base_db::{ CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath, - salsa::Cancelled, + salsa::{self, Cancelled}, }, prime_caches, symbol_index, }; @@ -461,7 +461,9 @@ impl Analysis { hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe, ) -> Cancellable> { self.with_db(|db| { - inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher) + salsa::attach(db, || { + inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher) + }) }) } @@ -536,7 +538,7 @@ impl Analysis { config: &HoverConfig, range: FileRange, ) -> Cancellable>> { - self.with_db(|db| hover::hover(db, range, config)) + self.with_db(|db| salsa::attach(db, || hover::hover(db, range, config))) } /// Returns moniker of symbol at position. @@ -544,7 +546,7 @@ impl Analysis { &self, position: FilePosition, ) -> Cancellable>>> { - self.with_db(|db| moniker::moniker(db, position)) + self.with_db(|db| salsa::attach(db, || moniker::moniker(db, position))) } /// Returns URL(s) for the documentation of the symbol under the cursor. @@ -640,7 +642,7 @@ impl Analysis { /// Returns the set of possible targets to run for the current file. pub fn runnables(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| runnables::runnables(db, file_id)) + self.with_db(|db| salsa::attach(db, || runnables::runnables(db, file_id))) } /// Returns the set of tests for the given file position. diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 61b4de0e0e396..1b6a4b726e831 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -10,6 +10,7 @@ use hir::{ }; use ide_db::{ FileId, FileRange, RootDatabase, SymbolKind, + base_db::salsa, defs::Definition, documentation::{Documentation, HasDocs}, }; @@ -377,8 +378,9 @@ where ) .map(|mut res| { res.docs = self.docs(db); - res.description = - Some(self.display(db, self.krate(db).to_display_target(db)).to_string()); + res.description = salsa::attach(db, || { + Some(self.display(db, self.krate(db).to_display_target(db)).to_string()) + }); res.container_name = self.container_name(db); res }), @@ -485,8 +487,9 @@ impl TryToNav for hir::Field { NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map( |mut res| { res.docs = self.docs(db); - res.description = - Some(self.display(db, krate.to_display_target(db)).to_string()); + res.description = salsa::attach(db, || { + Some(self.display(db, krate.to_display_target(db)).to_string()) + }); res }, ) diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 77c84292cf3e9..6d33ddcde0479 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -10,7 +10,7 @@ use hir::{ use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind, - base_db::RootQueryDb, + base_db::{RootQueryDb, salsa}, defs::Definition, documentation::docs_from_attrs, helpers::visit_file_defs, @@ -414,11 +414,13 @@ pub(crate) fn runnable_impl( let ty = def.self_ty(sema.db); let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.generic_parameters(sema.db, display_target).peekable(); - let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))) - } else { - String::new() - }; + let params = salsa::attach(sema.db, || { + if ty_args.peek().is_some() { + format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))) + } else { + String::new() + } + }); let mut test_id = format!("{}{params}", adt_name.display(sema.db, edition)); test_id.retain(|c| c != ' '); let test_id = TestId::Path(test_id); @@ -521,7 +523,9 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { let mut ty_args = ty.generic_parameters(db, display_target).peekable(); format_to!(path, "{}", name.display(db, edition)); if ty_args.peek().is_some() { - format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); + salsa::attach(db, || { + format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); + }); } format_to!(path, "::{}", def_name.display(db, edition)); path.retain(|c| c != ' '); diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 86d02b4098bd2..f45d096ac1904 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -11,6 +11,7 @@ use hir::{ use ide_db::{ FilePosition, FxIndexMap, active_parameter::{callable_for_arg_list, generic_def_for_node}, + base_db::salsa, documentation::{Documentation, HasDocs}, }; use itertools::Itertools; @@ -266,12 +267,12 @@ fn signature_help_for_call( // In that case, fall back to render definitions of the respective parameters. // This is overly conservative: we do not substitute known type vars // (see FIXME in tests::impl_trait) and falling back on any unknowns. - match (p.ty().contains_unknown(), fn_params.as_deref()) { + salsa::attach(db, || match (p.ty().contains_unknown(), fn_params.as_deref()) { (true, Some(fn_params)) => { format_to!(buf, "{}", fn_params[idx].ty().display(db, display_target)) } _ => format_to!(buf, "{}", p.ty().display(db, display_target)), - } + }); res.push_call_param(&buf); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 694ac22e1993b..14b6529c61f8c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -5,7 +5,7 @@ use arrayvec::ArrayVec; use hir::{Crate, Module, Semantics, db::HirDatabase}; use ide_db::{ FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, - base_db::{RootQueryDb, SourceDatabase, VfsPath}, + base_db::{RootQueryDb, SourceDatabase, VfsPath, salsa}, defs::{Definition, IdentClass}, documentation::Documentation, famous_defs::FamousDefs, @@ -227,30 +227,32 @@ impl StaticIndex<'_> { let id = if let Some(it) = self.def_map.get(&def) { *it } else { - let it = self.tokens.insert(TokenStaticData { - documentation: documentation_for_definition(&sema, def, scope_node), - hover: Some(hover_for_definition( - &sema, - file_id, - def, - None, - scope_node, - None, - false, - &hover_config, - edition, - display_target, - )), - definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| { - FileRange { file_id: it.file_id, range: it.focus_or_full_range() } - }), - references: vec![], - moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), - display_name: def - .name(self.db) - .map(|name| name.display(self.db, edition).to_string()), - signature: Some(def.label(self.db, display_target)), - kind: def_to_kind(self.db, def), + let it = salsa::attach(sema.db, || { + self.tokens.insert(TokenStaticData { + documentation: documentation_for_definition(&sema, def, scope_node), + hover: Some(hover_for_definition( + &sema, + file_id, + def, + None, + scope_node, + None, + false, + &hover_config, + edition, + display_target, + )), + definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map( + |it| FileRange { file_id: it.file_id, range: it.focus_or_full_range() }, + ), + references: vec![], + moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), + display_name: def + .name(self.db) + .map(|name| name.display(self.db, edition).to_string()), + signature: Some(def.label(self.db, display_target)), + kind: def_to_kind(self.db, def), + }) }); self.def_map.insert(def, it); it diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 63701a4d15e94..1eb0fd4fd8b76 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -3,6 +3,7 @@ use std::fmt; use hir::{DisplayTarget, Field, HirDisplay, Layout, Semantics, Type}; use ide_db::{ RootDatabase, + base_db::salsa, defs::Definition, helpers::{get_definition, pick_best_token}, }; @@ -141,7 +142,9 @@ pub(crate) fn view_memory_layout( if let Ok(child_layout) = child_ty.layout(db) { nodes.push(MemoryLayoutNode { item_name: field.name(db), - typename: child_ty.display(db, display_target).to_string(), + typename: salsa::attach(db, || { + child_ty.display(db, display_target).to_string() + }), size: child_layout.size(), alignment: child_layout.align(), offset: match *field { @@ -175,7 +178,7 @@ pub(crate) fn view_memory_layout( } } - ty.layout(db) + salsa::attach(db, || ty.layout(db)) .map(|layout| { let item_name = match def { // def is a datatype @@ -188,7 +191,7 @@ pub(crate) fn view_memory_layout( def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()), }; - let typename = ty.display(db, display_target).to_string(); + let typename = salsa::attach(db, || ty.display(db, display_target).to_string()); let mut nodes = vec![MemoryLayoutNode { item_name, From faf0dd978dc16873e22e62acfe8c54fb81fafe36 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Sun, 10 Aug 2025 00:53:11 +0000 Subject: [PATCH 062/251] Deduplicate layout_of_adt --- .../rust-analyzer/crates/hir-ty/src/db.rs | 17 +++--------- .../crates/hir-ty/src/display.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 9 +++---- .../crates/hir-ty/src/layout/adt.rs | 27 +++---------------- src/tools/rust-analyzer/crates/hir/src/lib.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 9 ++++--- 6 files changed, 19 insertions(+), 47 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 7a5daac69922f..161ad31e579b2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -94,11 +94,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::layout::layout_of_adt_query)] #[salsa::cycle(cycle_result = crate::layout::layout_of_adt_cycle_result)] - fn layout_of_adt( - &self, + fn layout_of_adt<'db>( + &'db self, def: AdtId, - subst: Substitution, - env: Arc, + args: crate::next_solver::GenericArgs<'db>, + trait_env: Arc, ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::layout_of_ty_query)] @@ -300,15 +300,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - #[salsa::invoke(crate::layout::layout_of_adt_ns_query)] - #[salsa::cycle(cycle_result = crate::layout::layout_of_adt_ns_cycle_result)] - fn layout_of_adt_ns<'db>( - &'db self, - def: AdtId, - args: crate::next_solver::GenericArgs<'db>, - trait_env: Arc, - ) -> Result, LayoutError>; - #[salsa::invoke(crate::layout::layout_of_ty_ns_query)] #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_ns_cycle_result)] fn layout_of_ty_ns<'db>( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 9f87c37834d77..81bc48eecfc8b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -944,7 +944,7 @@ fn render_const_scalar_inner( SolverDefId::AdtId(def) => def, _ => unreachable!(), }; - let Ok(layout) = f.db.layout_of_adt_ns(def, args, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_adt(def, args, trait_env.clone()) else { return f.write_str(""); }; match def { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index fb7b5e1c83e4c..0a8ec949b7c0a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -31,11 +31,8 @@ use crate::{ }, }; -pub(crate) use self::adt::{layout_of_adt_cycle_result, layout_of_adt_ns_cycle_result}; -pub use self::{ - adt::{layout_of_adt_ns_query, layout_of_adt_query}, - target::target_data_layout_query, -}; +pub(crate) use self::adt::layout_of_adt_cycle_result; +pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; pub(crate) mod adt; pub(crate) mod target; @@ -197,7 +194,7 @@ pub fn layout_of_ty_ns_query<'db>( } _ => {} } - return db.layout_of_adt_ns(def.inner().id, args, trait_env); + return db.layout_of_adt(def.inner().id, args, trait_env); } TyKind::Bool => Layout::scalar( dl, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 2fa01b6b41abc..fefa3f2617439 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -13,23 +13,13 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Substitution, TraitEnvironment, + TraitEnvironment, db::HirDatabase, layout::{Layout, LayoutCx, LayoutError, field_ty}, - next_solver::{DbInterner, GenericArgs, mapping::ChalkToNextSolver}, + next_solver::GenericArgs, }; -pub fn layout_of_adt_query( - db: &dyn HirDatabase, - def: AdtId, - subst: Substitution, - trait_env: Arc, -) -> Result, LayoutError> { - let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); - db.layout_of_adt_ns(def, subst.to_nextsolver(interner), trait_env) -} - -pub fn layout_of_adt_ns_query<'db>( +pub fn layout_of_adt_query<'db>( db: &'db dyn HirDatabase, def: AdtId, args: GenericArgs<'db>, @@ -105,16 +95,7 @@ pub fn layout_of_adt_ns_query<'db>( Ok(Arc::new(result)) } -pub(crate) fn layout_of_adt_cycle_result( - _: &dyn HirDatabase, - _: AdtId, - _: Substitution, - _: Arc, -) -> Result, LayoutError> { - Err(LayoutError::RecursiveTypeWithoutIndirection) -} - -pub(crate) fn layout_of_adt_ns_cycle_result<'db>( +pub(crate) fn layout_of_adt_cycle_result<'db>( _: &'db dyn HirDatabase, _def: AdtId, _args: GenericArgs<'db>, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 4dde019b50063..9accb33368980 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1818,7 +1818,7 @@ impl Adt { pub fn layout(self, db: &dyn HirDatabase) -> Result { let env = db.trait_environment(self.into()); let interner = DbInterner::new_with(db, Some(env.krate), env.block); - db.layout_of_adt_ns( + db.layout_of_adt( self.into(), TyBuilder::adt(db, self.into()) .fill_with_defaults(db, || TyKind::Error.intern(Interner)) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 97886844a9f9e..6c0aa19f57482 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -10,15 +10,17 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::{ - Adt, AssocItem, Crate, DefWithBody, HasSource, HirDisplay, ImportPathConfig, ModuleDef, Name, + Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ImportPathConfig, + ModuleDef, Name, db::{DefDatabase, ExpandDatabase, HirDatabase}, + next_solver::{DbInterner, GenericArgs}, }; use hir_def::{ SyntheticSyntax, expr_store::BodySourceMap, hir::{ExprId, PatId}, }; -use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; +use hir_ty::{Interner, TyExt, TypeFlags}; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RootDatabase, @@ -361,6 +363,7 @@ impl flags::AnalysisStats { let mut all = 0; let mut fail = 0; for &a in adts { + let interner = DbInterner::new_with(db, Some(a.krate(db).base()), None); let generic_params = db.generic_params(a.into()); if generic_params.iter_type_or_consts().next().is_some() || generic_params.iter_lt().next().is_some() @@ -371,7 +374,7 @@ impl flags::AnalysisStats { all += 1; let Err(e) = db.layout_of_adt( hir_def::AdtId::from(a), - Substitution::empty(Interner), + GenericArgs::new_from_iter(interner, []), db.trait_environment(a.into()), ) else { continue; From 1b03009e7c34db88899228fb7a47a655e4b77a3c Mon Sep 17 00:00:00 2001 From: jackh726 Date: Sun, 10 Aug 2025 18:00:40 +0000 Subject: [PATCH 063/251] Convert some of mir/eval to next-solver types --- .../crates/hir-ty/src/consteval/tests.rs | 2 +- .../crates/hir-ty/src/display.rs | 17 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 41 ++- .../rust-analyzer/crates/hir-ty/src/mir.rs | 2 +- .../crates/hir-ty/src/mir/eval.rs | 282 ++++++++++++------ .../crates/hir-ty/src/mir/eval/shim.rs | 25 +- .../crates/hir-ty/src/mir/eval/tests.rs | 2 +- .../crates/hir-ty/src/next_solver/consts.rs | 12 +- .../crates/hir-ty/src/next_solver/mapping.rs | 7 +- 9 files changed, 258 insertions(+), 132 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 22b152fe034a6..299b73a7d6cc4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -76,7 +76,7 @@ fn check_str(#[rust_analyzer::rust_fixture] ra_fixture: &str, answer: &str) { #[track_caller] fn check_answer( #[rust_analyzer::rust_fixture] ra_fixture: &str, - check: impl FnOnce(&[u8], &MemoryMap), + check: impl FnOnce(&[u8], &MemoryMap<'_>), ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 81bc48eecfc8b..5adbea75a67dd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -744,20 +744,20 @@ impl HirDisplay for Const { fn render_const_scalar( f: &mut HirFormatter<'_>, b: &[u8], - memory_map: &MemoryMap, + memory_map: &MemoryMap<'_>, ty: &Ty, ) -> Result<(), HirDisplayError> { let trait_env = TraitEnvironment::empty(f.krate()); let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); let ty = normalize(f.db, trait_env.clone(), ty.clone()); let ty = ty.to_nextsolver(interner); - render_const_scalar_inner(f, b, memory_map, ty, trait_env, interner) + render_const_scalar_inner(f, b, memory_map, ty, trait_env) } fn render_const_scalar_ns( f: &mut HirFormatter<'_>, b: &[u8], - memory_map: &MemoryMap, + memory_map: &MemoryMap<'_>, ty: crate::next_solver::Ty<'_>, ) -> Result<(), HirDisplayError> { let trait_env = TraitEnvironment::empty(f.krate()); @@ -767,16 +767,15 @@ fn render_const_scalar_ns( trait_env.env.to_nextsolver(interner), ty, ); - render_const_scalar_inner(f, b, memory_map, ty, trait_env, interner) + render_const_scalar_inner(f, b, memory_map, ty, trait_env) } fn render_const_scalar_inner( f: &mut HirFormatter<'_>, b: &[u8], - memory_map: &MemoryMap, + memory_map: &MemoryMap<'_>, ty: crate::next_solver::Ty<'_>, trait_env: Arc, - interner: DbInterner<'_>, ) -> Result<(), HirDisplayError> { use rustc_type_ir::TyKind; match ty.kind() { @@ -875,7 +874,7 @@ fn render_const_scalar_inner( let Ok(t) = memory_map.vtable_ty(ty_id) else { return f.write_str(""); }; - let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else { + let Ok(layout) = f.db.layout_of_ty_ns(t, trait_env) else { return f.write_str(""); }; let size = layout.size.bytes_usize(); @@ -883,7 +882,7 @@ fn render_const_scalar_inner( return f.write_str(""); }; f.write_str("&")?; - render_const_scalar_ns(f, bytes, memory_map, t.to_nextsolver(interner)) + render_const_scalar_ns(f, bytes, memory_map, t) } TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id() { SolverDefId::AdtId(hir_def::AdtId::StructId(s)) => { @@ -1052,7 +1051,7 @@ fn render_variant_after_name( layout: &Layout, args: GenericArgs<'_>, b: &[u8], - memory_map: &MemoryMap, + memory_map: &MemoryMap<'_>, ) -> Result<(), HirDisplayError> { let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); match data.shape { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 81894830b5b47..8ce0aeb5532ad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -212,20 +212,20 @@ pub(crate) type ProgramClause = chalk_ir::ProgramClause; /// the necessary bits of memory of the const eval session to keep the constant /// meaningful. #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub enum MemoryMap { +pub enum MemoryMap<'db> { #[default] Empty, Simple(Box<[u8]>), - Complex(Box), + Complex(Box>), } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct ComplexMemoryMap { +pub struct ComplexMemoryMap<'db> { memory: IndexMap, FxBuildHasher>, - vtable: VTableMap, + vtable: VTableMap<'db>, } -impl ComplexMemoryMap { +impl ComplexMemoryMap<'_> { fn insert(&mut self, addr: usize, val: Box<[u8]>) { match self.memory.entry(addr) { Entry::Occupied(mut e) => { @@ -240,8 +240,8 @@ impl ComplexMemoryMap { } } -impl MemoryMap { - pub fn vtable_ty(&self, id: usize) -> Result<&Ty, MirEvalError> { +impl<'db> MemoryMap<'db> { + pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError> { match self { MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), MemoryMap::Complex(cm) => cm.vtable.ty(id), @@ -291,10 +291,11 @@ impl MemoryMap { } } +// FIXME(next-solver): /// A concrete constant value #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstScalar { - Bytes(Box<[u8]>, MemoryMap), + Bytes(Box<[u8]>, MemoryMap<'static>), // FIXME: this is a hack to get around chalk not being able to represent unevaluatable // constants UnevaluatedConst(GeneralConstId, Substitution), @@ -315,6 +316,30 @@ impl Hash for ConstScalar { } } +/// A concrete constant value +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ConstScalarNs<'db> { + Bytes(Box<[u8]>, MemoryMap<'db>), + // FIXME: this is a hack to get around chalk not being able to represent unevaluatable + // constants + UnevaluatedConst(GeneralConstId, Substitution), + /// Case of an unknown value that rustc might know but we don't + // FIXME: this is a hack to get around chalk not being able to represent unevaluatable + // constants + // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 + // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 + Unknown, +} + +impl Hash for ConstScalarNs<'_> { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + if let ConstScalarNs::Bytes(b, _) = self { + b.hash(state) + } + } +} + /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option { generics::generics(db, id.parent).type_or_const_param_idx(id) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 482b420279c90..8c48a16537a2e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -107,7 +107,7 @@ pub enum OperandKind { } impl Operand { - fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap, ty: Ty) -> Self { + fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'static>, ty: Ty) -> Self { Operand { kind: OperandKind::Constant(intern_const_scalar( ConstScalar::Bytes(data, memory_map), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index dfb8ae704b996..d0ae92961efc0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -25,21 +25,26 @@ use rustc_apfloat::{ ieee::{Half as f16, Quad as f128}, }; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; use span::FileId; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{ - AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, - Interner, MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, + AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, Interner, + MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, consteval::{ConstEvalError, intern_const_scalar, try_const_usize}, + consteval_nextsolver, db::{HirDatabase, InternedClosure}, display::{ClosureStyle, DisplayTarget, HirDisplay}, infer::PointerCast, layout::{Layout, LayoutError, RustcEnumVariantIdx}, - mapping::from_chalk, method_resolution::{is_dyn_method, lookup_impl_const}, + next_solver::{ + Ctor, DbInterner, SolverDefId, + mapping::{ChalkToNextSolver, convert_args_for_result, convert_ty_for_result}, + }, static_lifetime, traits::FnTrait, utils::{ClosureSubst, detect_variant_from_bytes}, @@ -78,31 +83,31 @@ macro_rules! not_supported { } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct VTableMap { - ty_to_id: FxHashMap, - id_to_ty: Vec, +pub struct VTableMap<'db> { + ty_to_id: FxHashMap, usize>, + id_to_ty: Vec>, } -impl VTableMap { +impl<'db> VTableMap<'db> { const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id. - fn id(&mut self, ty: Ty) -> usize { + fn id(&mut self, ty: crate::next_solver::Ty<'db>) -> usize { if let Some(it) = self.ty_to_id.get(&ty) { return *it; } let id = self.id_to_ty.len() + VTableMap::OFFSET; - self.id_to_ty.push(ty.clone()); + self.id_to_ty.push(ty); self.ty_to_id.insert(ty, id); id } - pub(crate) fn ty(&self, id: usize) -> Result<&Ty> { + pub(crate) fn ty(&self, id: usize) -> Result> { id.checked_sub(VTableMap::OFFSET) - .and_then(|id| self.id_to_ty.get(id)) + .and_then(|id| self.id_to_ty.get(id).copied()) .ok_or(MirEvalError::InvalidVTableId(id)) } - fn ty_of_bytes(&self, bytes: &[u8]) -> Result<&Ty> { + fn ty_of_bytes(&self, bytes: &[u8]) -> Result> { let id = from_bytes!(usize, bytes); self.ty(id) } @@ -170,12 +175,12 @@ pub struct Evaluator<'a> { /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the /// time of use. - vtable_map: VTableMap, + vtable_map: VTableMap<'a>, thread_local_storage: TlsData, random_state: oorandom::Rand64, stdout: Vec, stderr: Vec, - layout_cache: RefCell>>, + layout_cache: RefCell, Arc>>, projected_ty_cache: RefCell>, not_special_fn_cache: RefCell>, mir_or_dyn_index_cache: RefCell>, @@ -224,7 +229,7 @@ impl Interval { Self { addr, size } } - fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { memory.read_memory(self.addr, self.size) } @@ -242,7 +247,7 @@ impl Interval { } impl IntervalAndTy { - fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { memory.read_memory(self.interval.addr, self.interval.size) } @@ -269,7 +274,7 @@ impl From for IntervalOrOwned { } impl IntervalOrOwned { - fn get<'a>(&'a self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&'a self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { Ok(match self { IntervalOrOwned::Owned(o) => o, IntervalOrOwned::Borrowed(b) => b.get(memory)?, @@ -608,7 +613,13 @@ pub fn interpret_mir( memory_map.vtable.shrink_to_fit(); MemoryMap::Complex(Box::new(memory_map)) }; - Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)) + // SAFETY: will never use this without a db + Ok(intern_const_scalar( + ConstScalar::Bytes(bytes, unsafe { + std::mem::transmute::, MemoryMap<'static>>(memory_map) + }), + ty, + )) })(); Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr })) } @@ -618,7 +629,7 @@ const EXECUTION_LIMIT: usize = 100_000; #[cfg(not(test))] const EXECUTION_LIMIT: usize = 10_000_000; -impl Evaluator<'_> { +impl<'db> Evaluator<'db> { pub fn new( db: &dyn HirDatabase, owner: DefWithBodyId, @@ -719,6 +730,7 @@ impl Evaluator<'_> { p: &Place, locals: &'a Locals, ) -> Result<(Address, Ty, Option)> { + let interner = DbInterner::new_with(self.db, None, None); let mut addr = locals.ptr[p.local].addr; let mut ty: Ty = locals.body.locals[p.local].ty.clone(); let mut metadata: Option = None; // locals are always sized @@ -791,19 +803,19 @@ impl Evaluator<'_> { addr = addr.offset(ty_size * (from as usize)); } &ProjectionElem::ClosureField(f) => { - let layout = self.layout(&prev_ty)?; + let layout = self.layout(prev_ty.to_nextsolver(interner))?; let offset = layout.fields.offset(f).bytes_usize(); addr = addr.offset(offset); metadata = None; } ProjectionElem::Field(Either::Right(f)) => { - let layout = self.layout(&prev_ty)?; + let layout = self.layout(prev_ty.to_nextsolver(interner))?; let offset = layout.fields.offset(f.index as usize).bytes_usize(); addr = addr.offset(offset); metadata = None; // tuple field is always sized FIXME: This is wrong, the tail can be unsized } ProjectionElem::Field(Either::Left(f)) => { - let layout = self.layout(&prev_ty)?; + let layout = self.layout(prev_ty.to_nextsolver(interner))?; let variant_layout = match &layout.variants { Variants::Single { .. } | Variants::Empty => &layout, Variants::Multiple { variants, .. } => { @@ -835,20 +847,28 @@ impl Evaluator<'_> { Ok((addr, ty, metadata)) } - fn layout(&self, ty: &Ty) -> Result> { - if let Some(x) = self.layout_cache.borrow().get(ty) { + fn layout(&self, ty: crate::next_solver::Ty<'db>) -> Result> { + if let Some(x) = self.layout_cache.borrow().get(&ty) { return Ok(x.clone()); } + let interner = DbInterner::new_with(self.db, None, None); let r = self .db - .layout_of_ty(ty.clone(), self.trait_env.clone()) - .map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?; - self.layout_cache.borrow_mut().insert(ty.clone(), r.clone()); + .layout_of_ty_ns(ty, self.trait_env.clone()) + .map_err(|e| MirEvalError::LayoutError(e, convert_ty_for_result(interner, ty)))?; + self.layout_cache.borrow_mut().insert(ty, r.clone()); Ok(r) } fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result> { - self.layout(&TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner)) + let interner = DbInterner::new_with(self.db, None, None); + self.layout(crate::next_solver::Ty::new( + interner, + rustc_type_ir::TyKind::Adt( + crate::next_solver::AdtDef::new(adt, interner), + subst.to_nextsolver(interner), + ), + )) } fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result { @@ -952,7 +972,7 @@ impl Evaluator<'_> { )? } TyKind::FnDef(def, generic_args) => self.exec_fn_def( - *def, + CallableDefId::from_chalk(self.db, *def), generic_args, destination_interval, &args, @@ -1113,6 +1133,7 @@ impl Evaluator<'_> { } fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result { + let interner = DbInterner::new_with(self.db, None, None); use IntervalOrOwned::*; Ok(match r { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), @@ -1436,7 +1457,7 @@ impl Evaluator<'_> { Owned(r) } AggregateKind::Tuple(ty) => { - let layout = self.layout(ty)?; + let layout = self.layout(ty.to_nextsolver(interner))?; Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1467,7 +1488,7 @@ impl Evaluator<'_> { )?) } AggregateKind::Closure(ty) => { - let layout = self.layout(ty)?; + let layout = self.layout(ty.to_nextsolver(interner))?; Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1484,6 +1505,8 @@ impl Evaluator<'_> { if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = ¤t_ty.kind(Interner) { + let interner = DbInterner::new_with(self.db, None, None); + let current_ty = current_ty.to_nextsolver(interner); let id = self.vtable_map.id(current_ty); let ptr_size = self.ptr_size(); Owned(id.to_le_bytes()[0..ptr_size].to_vec()) @@ -1623,7 +1646,8 @@ impl Evaluator<'_> { } fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result { - let layout = self.layout(&ty)?; + let interner = DbInterner::new_with(self.db, None, None); + let layout = self.layout(ty.to_nextsolver(interner))?; let &TyKind::Adt(chalk_ir::AdtId(AdtId::EnumId(e)), _) = ty.kind(Interner) else { return Ok(0); }; @@ -1732,6 +1756,8 @@ impl Evaluator<'_> { } }, TyKind::Dyn(_) => { + let interner = DbInterner::new_with(self.db, None, None); + let current_ty = current_ty.to_nextsolver(interner); let vtable = self.vtable_map.id(current_ty); let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; @@ -1777,6 +1803,7 @@ impl Evaluator<'_> { subst: Substitution, locals: &Locals, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { + let interner = DbInterner::new_with(self.db, None, None); let adt = it.adt_id(self.db); if let DefWithBodyId::VariantId(f) = locals.body.owner && let VariantId::EnumVariantId(it) = it @@ -1786,7 +1813,11 @@ impl Evaluator<'_> { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy layout let i = self.const_eval_discriminant(it)?; - return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); + return Ok(( + 16, + self.layout(crate::next_solver::Ty::new_tup(interner, &[]))?, + Some((0, 16, i)), + )); } let layout = self.layout_adt(adt, subst)?; Ok(match &layout.variants { @@ -1885,6 +1916,7 @@ impl Evaluator<'_> { #[allow(clippy::double_parens)] fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result { + let interner = DbInterner::new_with(self.db, None, None); let ConstData { ty, value: chalk_ir::ConstValue::Concrete(c) } = &konst.data(Interner) else { not_supported!("evaluating non concrete constant"); @@ -1945,7 +1977,7 @@ impl Evaluator<'_> { MemoryMap::Complex(cm) => cm.vtable.ty_of_bytes(bytes), }, addr, - ty, + ty.to_nextsolver(interner), locals, )?; Ok(Interval::new(addr, size)) @@ -2048,7 +2080,8 @@ impl Evaluator<'_> { } fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result> { - if let Some(layout) = self.layout_cache.borrow().get(ty) { + let interner = DbInterner::new_with(self.db, None, None); + if let Some(layout) = self.layout_cache.borrow().get(&ty.to_nextsolver(interner)) { return Ok(layout .is_sized() .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); @@ -2061,7 +2094,7 @@ impl Evaluator<'_> { // infinite sized type errors) we use a dummy size return Ok(Some((16, 16))); } - let layout = self.layout(ty); + let layout = self.layout(ty.to_nextsolver(interner)); if self.assert_placeholder_ty_is_unused && matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _))) { @@ -2129,15 +2162,16 @@ impl Evaluator<'_> { bytes: &[u8], ty: &Ty, locals: &Locals, - ) -> Result { - fn rec( - this: &Evaluator<'_>, + ) -> Result> { + fn rec<'db>( + this: &Evaluator<'db>, bytes: &[u8], ty: &Ty, locals: &Locals, - mm: &mut ComplexMemoryMap, + mm: &mut ComplexMemoryMap<'db>, stack_depth_limit: usize, ) -> Result<()> { + let interner = DbInterner::new_with(this.db, None, None); if stack_depth_limit.checked_sub(1).is_none() { return Err(MirEvalError::StackOverflow); } @@ -2158,13 +2192,14 @@ impl Evaluator<'_> { let element_size = match t.kind(Interner) { TyKind::Str => 1, TyKind::Slice(t) => { - check_inner = Some(t); + check_inner = Some(t.clone()); this.size_of_sized(t, locals, "slice inner type")? } TyKind::Dyn(_) => { let t = this.vtable_map.ty_of_bytes(meta)?; - check_inner = Some(t); - this.size_of_sized(t, locals, "dyn concrete type")? + let t = convert_ty_for_result(interner, t); + check_inner = Some(t.clone()); + this.size_of_sized(&t, locals, "dyn concrete type")? } _ => return Ok(()), }; @@ -2176,7 +2211,7 @@ impl Evaluator<'_> { let addr = Address::from_bytes(addr)?; let b = this.read_memory(addr, size)?; mm.insert(addr.to_usize(), b.into()); - if let Some(ty) = check_inner { + if let Some(ty) = &check_inner { for i in 0..count { let offset = element_size * i; rec( @@ -2211,11 +2246,11 @@ impl Evaluator<'_> { } } TyKind::Tuple(_, subst) => { - let layout = this.layout(ty)?; + let layout = this.layout(ty.to_nextsolver(interner))?; for (id, ty) in subst.iter(Interner).enumerate() { let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument let offset = layout.fields.offset(id).bytes_usize(); - let size = this.layout(ty)?.size.bytes_usize(); + let size = this.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2229,7 +2264,7 @@ impl Evaluator<'_> { TyKind::Adt(adt, subst) => match adt.0 { AdtId::StructId(s) => { let data = s.fields(this.db); - let layout = this.layout(ty)?; + let layout = this.layout(ty.to_nextsolver(interner))?; let field_types = this.db.field_types(s.into()); for (f, _) in data.fields().iter() { let offset = layout @@ -2237,7 +2272,7 @@ impl Evaluator<'_> { .offset(u32::from(f.into_raw()) as usize) .bytes_usize(); let ty = &field_types[f].clone().substitute(Interner, subst); - let size = this.layout(ty)?.size.bytes_usize(); + let size = this.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2249,7 +2284,7 @@ impl Evaluator<'_> { } } AdtId::EnumId(e) => { - let layout = this.layout(ty)?; + let layout = this.layout(ty.to_nextsolver(interner))?; if let Some((v, l)) = detect_variant_from_bytes( &layout, this.db, @@ -2263,7 +2298,8 @@ impl Evaluator<'_> { let offset = l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize(); let ty = &field_types[f].clone().substitute(Interner, subst); - let size = this.layout(ty)?.size.bytes_usize(); + let size = + this.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2290,20 +2326,26 @@ impl Evaluator<'_> { Ok(mm) } - fn patch_addresses<'vtable>( + fn patch_addresses( &mut self, patch_map: &FxHashMap, - ty_of_bytes: impl Fn(&[u8]) -> Result<&'vtable Ty> + Copy, + ty_of_bytes: impl Fn(&[u8]) -> Result> + Copy, addr: Address, - ty: &Ty, + ty: crate::next_solver::Ty<'db>, locals: &Locals, ) -> Result<()> { + let interner = DbInterner::new_with(self.db, None, None); // FIXME: support indirect references let layout = self.layout(ty)?; - let my_size = self.size_of_sized(ty, locals, "value to patch address")?; - match ty.kind(Interner) { - TyKind::Ref(_, _, t) => { - let size = self.size_align_of(t, locals)?; + let my_size = self.size_of_sized( + &convert_ty_for_result(interner, ty), + locals, + "value to patch address", + )?; + use rustc_type_ir::TyKind; + match ty.kind() { + TyKind::Ref(_, t, _) => { + let size = self.size_align_of(&convert_ty_for_result(interner, t), locals)?; match size { Some(_) => { let current = from_bytes!(usize, self.read_memory(addr, my_size)?); @@ -2319,27 +2361,27 @@ impl Evaluator<'_> { } } } - TyKind::Function(_) => { - let ty = ty_of_bytes(self.read_memory(addr, my_size)?)?.clone(); + TyKind::FnPtr(_, _) => { + let ty = ty_of_bytes(self.read_memory(addr, my_size)?)?; let new_id = self.vtable_map.id(ty); self.write_memory(addr, &new_id.to_le_bytes())?; } - TyKind::Adt(id, subst) => match id.0 { - AdtId::StructId(s) => { - for (i, (_, ty)) in self.db.field_types(s.into()).iter().enumerate() { + TyKind::Adt(id, args) => match id.def_id() { + SolverDefId::AdtId(AdtId::StructId(s)) => { + for (i, (_, ty)) in self.db.field_types_ns(s.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); - let ty = ty.clone().substitute(Interner, subst); + let ty = ty.instantiate(interner, args); self.patch_addresses( patch_map, ty_of_bytes, addr.offset(offset), - &ty, + ty, locals, )?; } } - AdtId::UnionId(_) => (), - AdtId::EnumId(e) => { + SolverDefId::AdtId(AdtId::UnionId(_)) => (), + SolverDefId::AdtId(AdtId::EnumId(e)) => { if let Some((ev, layout)) = detect_variant_from_bytes( &layout, self.db, @@ -2347,33 +2389,37 @@ impl Evaluator<'_> { self.read_memory(addr, layout.size.bytes_usize())?, e, ) { - for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() { + for (i, (_, ty)) in self.db.field_types_ns(ev.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); - let ty = ty.clone().substitute(Interner, subst); + let ty = ty.instantiate(interner, args); self.patch_addresses( patch_map, ty_of_bytes, addr.offset(offset), - &ty, + ty, locals, )?; } } } + _ => unreachable!(), }, - TyKind::Tuple(_, subst) => { - for (id, ty) in subst.iter(Interner).enumerate() { - let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument + TyKind::Tuple(tys) => { + for (id, ty) in tys.iter().enumerate() { let offset = layout.fields.offset(id).bytes_usize(); self.patch_addresses(patch_map, ty_of_bytes, addr.offset(offset), ty, locals)?; } } TyKind::Array(inner, len) => { - let len = match try_const_usize(self.db, len) { + let len = match consteval_nextsolver::try_const_usize(self.db, len) { Some(it) => it as usize, None => not_supported!("non evaluatable array len in patching addresses"), }; - let size = self.size_of_sized(inner, locals, "inner of array")?; + let size = self.size_of_sized( + &convert_ty_for_result(interner, inner), + locals, + "inner of array", + )?; for i in 0..len { self.patch_addresses( patch_map, @@ -2384,11 +2430,13 @@ impl Evaluator<'_> { )?; } } - TyKind::AssociatedType(_, _) - | TyKind::Scalar(_) + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) | TyKind::Slice(_) - | TyKind::Raw(_, _) - | TyKind::OpaqueType(_, _) + | TyKind::RawPtr(_, _) | TyKind::FnDef(_, _) | TyKind::Str | TyKind::Never @@ -2396,12 +2444,16 @@ impl Evaluator<'_> { | TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) | TyKind::Foreign(_) - | TyKind::Error + | TyKind::Error(_) | TyKind::Placeholder(_) - | TyKind::Dyn(_) - | TyKind::Alias(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => (), + | TyKind::Dynamic(_, _, _) + | TyKind::Alias(_, _) + | TyKind::Bound(_, _) + | TyKind::Infer(_) + | TyKind::Pat(_, _) + | TyKind::Param(_) + | TyKind::UnsafeBinder(_) + | TyKind::CoroutineClosure(_, _) => (), } Ok(()) } @@ -2416,13 +2468,41 @@ impl Evaluator<'_> { span: MirSpan, ) -> Result> { let id = from_bytes!(usize, bytes.get(self)?); - let next_ty = self.vtable_map.ty(id)?.clone(); - match next_ty.kind(Interner) { + let next_ty = self.vtable_map.ty(id)?; + let interner = DbInterner::new_with(self.db, None, None); + use rustc_type_ir::TyKind; + match next_ty.kind() { TyKind::FnDef(def, generic_args) => { - self.exec_fn_def(*def, generic_args, destination, args, locals, target_bb, span) + let def = match def { + SolverDefId::FunctionId(id) => CallableDefId::FunctionId(id), + SolverDefId::Ctor(Ctor::Struct(s)) => CallableDefId::StructId(s), + SolverDefId::Ctor(Ctor::Enum(e)) => CallableDefId::EnumVariantId(e), + _ => unreachable!(), + }; + self.exec_fn_def( + def, + &convert_args_for_result(interner, generic_args.as_slice()), + destination, + args, + locals, + target_bb, + span, + ) } - TyKind::Closure(id, subst) => { - self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span) + TyKind::Closure(id, generic_args) => { + let id = match id { + SolverDefId::InternedClosureId(id) => id, + _ => unreachable!(), + }; + self.exec_closure( + id.into(), + bytes.slice(0..0), + &convert_args_for_result(interner, generic_args.as_slice()), + destination, + args, + locals, + span, + ) } _ => Err(MirEvalError::InternalError("function pointer to non function".into())), } @@ -2469,7 +2549,7 @@ impl Evaluator<'_> { fn exec_fn_def( &mut self, - def: FnDefId, + def: CallableDefId, generic_args: &Substitution, destination: Interval, args: &[IntervalAndTy], @@ -2477,7 +2557,6 @@ impl Evaluator<'_> { target_bb: Option, span: MirSpan, ) -> Result> { - let def: CallableDefId = from_chalk(self.db, def); let generic_args = generic_args.clone(); match def { CallableDefId::FunctionId(def) => { @@ -2574,6 +2653,7 @@ impl Evaluator<'_> { target_bb: Option, span: MirSpan, ) -> Result> { + let interner = DbInterner::new_with(self.db, None, None); if self.detect_and_exec_special_function( def, args, @@ -2600,6 +2680,7 @@ impl Evaluator<'_> { .vtable_map .ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?; let mut args_for_target = args.to_vec(); + let ty = convert_ty_for_result(interner, ty); args_for_target[0] = IntervalAndTy { interval: args_for_target[0].interval.slice(0..self.ptr_size()), ty: ty.clone(), @@ -2672,6 +2753,7 @@ impl Evaluator<'_> { target_bb: Option, span: MirSpan, ) -> Result> { + let interner = DbInterner::new_with(self.db, None, None); let func = args .first() .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?; @@ -2683,15 +2765,21 @@ impl Evaluator<'_> { let id = from_bytes!(usize, &func_data.get(self)?[self.ptr_size()..self.ptr_size() * 2]); func_data = func_data.slice(0..self.ptr_size()); - func_ty = self.vtable_map.ty(id)?.clone(); + func_ty = convert_ty_for_result(interner, self.vtable_map.ty(id)?); } let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?; func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size }; } match &func_ty.kind(Interner) { - TyKind::FnDef(def, subst) => { - self.exec_fn_def(*def, subst, destination, &args[1..], locals, target_bb, span) - } + TyKind::FnDef(def, subst) => self.exec_fn_def( + CallableDefId::from_chalk(self.db, *def), + subst, + destination, + &args[1..], + locals, + target_bb, + span, + ), TyKind::Function(_) => { self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span) } @@ -2714,7 +2802,7 @@ impl Evaluator<'_> { Substitution::from_iter(Interner, args.iter().map(|it| it.ty.clone())), ) .intern(Interner); - let layout = self.layout(&ty)?; + let layout = self.layout(ty.to_nextsolver(interner))?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -2901,6 +2989,7 @@ pub fn render_const_using_debug_impl( owner: DefWithBodyId, c: &Const, ) -> Result { + let interner = DbInterner::new_with(db, None, None); let mut evaluator = Evaluator::new(db, owner, false, None)?; let locals = &Locals { ptr: ArenaMap::new(), @@ -2933,7 +3022,8 @@ pub fn render_const_using_debug_impl( CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db), Substitution::from1(Interner, c.data(Interner).ty.clone()), ) - .intern(Interner)); + .intern(Interner) + .to_nextsolver(interner)); evaluator.write_memory(a2.offset(evaluator.ptr_size()), &debug_fmt_fn_ptr.to_le_bytes())?; // a3 = ::core::fmt::Arguments::new_v1(a1, a2) // FIXME: similarly, we should call function here, not directly working with memory. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index bb4c963a8ae15..e27d334d2a991 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -23,6 +23,10 @@ use crate::{ LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution, Ty, TyBuilder, TyExt, pad16, }, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, convert_ty_for_result}, + }, }; mod simd; @@ -171,6 +175,7 @@ impl Evaluator<'_> { destination: Interval, span: MirSpan, ) -> Result<()> { + let interner = DbInterner::new_with(self.db, None, None); match self_ty.kind(Interner) { TyKind::Function(_) => { let [arg] = args else { @@ -188,7 +193,7 @@ impl Evaluator<'_> { let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure((*id).into()); let infer = self.db.infer(closure_owner); let (captures, _) = infer.closure_info(id); - let layout = self.layout(&self_ty)?; + let layout = self.layout(self_ty.to_nextsolver(interner))?; let ty_iter = captures.iter().map(|c| c.ty(subst)); self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?; } @@ -197,7 +202,7 @@ impl Evaluator<'_> { not_supported!("wrong arg count for clone"); }; let addr = Address::from_bytes(arg.get(self)?)?; - let layout = self.layout(&self_ty)?; + let layout = self.layout(self_ty.to_nextsolver(interner))?; let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone()); self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?; } @@ -226,8 +231,9 @@ impl Evaluator<'_> { destination: Interval, span: MirSpan, ) -> Result<()> { + let interner = DbInterner::new_with(self.db, None, None); for (i, ty) in ty_iter.enumerate() { - let size = self.layout(&ty)?.size.bytes_usize(); + let size = self.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?; let arg = IntervalAndTy { interval: Interval { addr: tmp, size: self.ptr_size() }, @@ -592,6 +598,7 @@ impl Evaluator<'_> { span: MirSpan, needs_override: bool, ) -> Result { + let interner = DbInterner::new_with(self.db, None, None); if let Some(name) = name.strip_prefix("atomic_") { return self .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span) @@ -769,7 +776,7 @@ impl Evaluator<'_> { "align_of generic arg is not provided".into(), )); }; - let align = self.layout(ty)?.align.abi.bytes(); + let align = self.layout(ty.to_nextsolver(interner))?.align.abi.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { @@ -1025,7 +1032,7 @@ impl Evaluator<'_> { let is_overflow = u128overflow || ans.to_le_bytes()[op_size..].iter().any(|&it| it != 0 && it != 255); let is_overflow = vec![u8::from(is_overflow)]; - let layout = self.layout(&result_ty)?; + let layout = self.layout(result_ty.to_nextsolver(interner))?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1249,7 +1256,7 @@ impl Evaluator<'_> { "const_eval_select arg[0] is not a tuple".into(), )); }; - let layout = self.layout(&tuple.ty)?; + let layout = self.layout(tuple.ty.to_nextsolver(interner))?; for (i, field) in fields.iter(Interner).enumerate() { let field = field.assert_ty_ref(Interner).clone(); let offset = layout.fields.offset(i).bytes_usize(); @@ -1408,6 +1415,7 @@ impl Evaluator<'_> { metadata: Interval, locals: &Locals, ) -> Result<(usize, usize)> { + let interner = DbInterner::new_with(self.db, None, None); Ok(match ty.kind(Interner) { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), TyKind::Slice(inner) => { @@ -1416,7 +1424,7 @@ impl Evaluator<'_> { (size * len, align) } TyKind::Dyn(_) => self.size_align_of_sized( - self.vtable_map.ty_of_bytes(metadata.get(self)?)?, + &convert_ty_for_result(interner, self.vtable_map.ty_of_bytes(metadata.get(self)?)?), locals, "dyn concrete type", )?, @@ -1463,6 +1471,7 @@ impl Evaluator<'_> { locals: &Locals, _span: MirSpan, ) -> Result<()> { + let interner = DbInterner::new_with(self.db, None, None); // We are a single threaded runtime with no UB checking and no optimization, so // we can implement atomic intrinsics as normal functions. @@ -1560,7 +1569,7 @@ impl Evaluator<'_> { Substitution::from_iter(Interner, [ty.clone(), TyBuilder::bool()]), ) .intern(Interner); - let layout = self.layout(&result_ty)?; + let layout = self.layout(result_ty.to_nextsolver(interner))?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, 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 eb5af58f2ea18..5a56d99fbaa29 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 @@ -37,7 +37,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), ) .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; - let (result, output) = interpret_mir(db, body, false, None)?; + let (result, output) = salsa::attach(db, || interpret_mir(db, body, false, None))?; result?; Ok((output.stdout().into_owned(), output.stderr().into_owned())) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 5698ff290f748..ce581cfad4b26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -103,7 +103,7 @@ pub struct ValueConst<'db> { } impl<'db> ValueConst<'db> { - pub fn new(ty: Ty<'db>, bytes: ConstBytes) -> Self { + pub fn new(ty: Ty<'db>, bytes: ConstBytes<'db>) -> Self { let value = Valtree::new(bytes); ValueConst { ty, value } } @@ -141,9 +141,9 @@ impl<'db> rustc_type_ir::TypeFoldable> for ValueConst<'db> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConstBytes(pub Box<[u8]>, pub MemoryMap); +pub struct ConstBytes<'db>(pub Box<[u8]>, pub MemoryMap<'db>); -impl Hash for ConstBytes { +impl Hash for ConstBytes<'_> { fn hash(&self, state: &mut H) { self.0.hash(state) } @@ -152,11 +152,11 @@ impl Hash for ConstBytes { #[salsa::interned(constructor = new_, debug)] pub struct Valtree<'db> { #[returns(ref)] - bytes_: ConstBytes, + bytes_: ConstBytes<'db>, } impl<'db> Valtree<'db> { - pub fn new(bytes: ConstBytes) -> Self { + pub fn new(bytes: ConstBytes<'db>) -> Self { salsa::with_attached_database(|db| unsafe { // SAFETY: ¯\_(ツ)_/¯ std::mem::transmute(Valtree::new_(db, bytes)) @@ -164,7 +164,7 @@ impl<'db> Valtree<'db> { .unwrap() } - pub fn inner(&self) -> &ConstBytes { + pub fn inner(&self) -> &ConstBytes<'db> { salsa::with_attached_database(|db| { let inner = self.bytes_(db); // SAFETY: The caller already has access to a `Valtree<'db>`, so borrowchecking will diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index b50fccb832625..5fefb04a5e768 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -21,7 +21,7 @@ use rustc_type_ir::{ use salsa::plumbing::AsId; use crate::{ - ConcreteConst, ConstScalar, ImplTraitId, Interner, + ConcreteConst, ConstScalar, ImplTraitId, Interner, MemoryMap, db::{ HirDatabase, InternedClosureId, InternedCoroutineId, InternedOpaqueTyId, InternedTypeOrConstParamId, @@ -1328,7 +1328,10 @@ pub fn convert_const_for_result<'db>( rustc_type_ir::ConstKind::Value(value_const) => { let bytes = value_const.value.inner(); let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Bytes(bytes.0.clone(), bytes.1.clone()), + // SAFETY: we will never actually use this without a database + interned: ConstScalar::Bytes(bytes.0.clone(), unsafe { + std::mem::transmute::, MemoryMap<'static>>(bytes.1.clone()) + }), }); return chalk_ir::ConstData { ty: convert_ty_for_result(interner, value_const.ty), From 73a5134722d362299bdecbd8418b4728f918a23e Mon Sep 17 00:00:00 2001 From: jackh726 Date: Mon, 11 Aug 2025 02:34:53 +0000 Subject: [PATCH 064/251] Change direct_super_traits to use generic_predicates_for_param_ns --- .../rust-analyzer/crates/hir-ty/src/utils.rs | 43 +++++++++++++------ src/tools/rust-analyzer/crates/hir/src/lib.rs | 16 ++++--- .../rust-analyzer/crates/ide/src/hover.rs | 12 +++--- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 +- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 209ec7926e825..092d4e3a8d9e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -4,10 +4,7 @@ use std::{cell::LazyCell, iter}; use base_db::Crate; -use chalk_ir::{ - DebruijnIndex, - fold::{FallibleTypeFolder, Shift}, -}; +use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder}; use hir_def::{ EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, db::DefDatabase, @@ -20,6 +17,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use span::Edition; use stdx::never; @@ -31,6 +29,11 @@ use crate::{ db::HirDatabase, layout::{Layout, TagEncoding}, mir::pad16, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, convert_args_for_result}, + }, + to_chalk_trait_id, }; pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator + '_ { @@ -191,25 +194,37 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut( } fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) { + let interner = DbInterner::new_with(db, None, None); let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); let trait_self = match generic_params.trait_self_param() { Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, None => return, }; - db.generic_predicates_for_param(trait_self.parent, trait_self, None) + let trait_ref_args: crate::next_solver::GenericArgs<'_> = + trait_ref.substitution.to_nextsolver(interner); + db.generic_predicates_for_param_ns(trait_self.parent, trait_self, None) .iter() .filter_map(|pred| { - pred.as_ref().filter_map(|pred| match pred.skip_binders() { - // FIXME: how to correctly handle higher-ranked bounds here? - WhereClause::Implemented(tr) => Some( - tr.clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("FIXME unexpected higher-ranked trait bound"), - ), + let pred = pred.kind(); + // FIXME: how to correctly handle higher-ranked bounds here? + let pred = pred.no_bound_vars().expect("FIXME unexpected higher-ranked trait bound"); + match pred { + rustc_type_ir::ClauseKind::Trait(t) => { + let t = + rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args); + let trait_id = match t.def_id() { + crate::next_solver::SolverDefId::TraitId(id) => to_chalk_trait_id(id), + _ => unreachable!(), + }; + + let substitution = + convert_args_for_result(interner, t.trait_ref.args.as_slice()); + let tr = chalk_ir::TraitRef { trait_id, substitution }; + Some(tr) + } _ => None, - }) + } }) - .map(|pred| pred.substitute(Interner, &trait_ref.substitution)) .for_each(cb); } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 9accb33368980..18c3ea05614a8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -86,7 +86,8 @@ use hir_ty::{ method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - DbInterner, GenericArgs, SolverDefId, infer::InferCtxt, mapping::ChalkToNextSolver, + ClauseKind, DbInterner, GenericArgs, SolverDefId, infer::InferCtxt, + mapping::ChalkToNextSolver, }, primitive::UintTy, traits::FnTrait, @@ -114,6 +115,7 @@ pub use crate::{ VisibleTraits, }, }; +use rustc_type_ir::inherent::IntoKind; // Be careful with these re-exports. // @@ -4245,11 +4247,15 @@ impl TypeParam { /// parameter, not additional bounds that might be added e.g. by a method if /// the parameter comes from an impl! pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec { - db.generic_predicates_for_param(self.id.parent(), self.id.into(), None) + db.generic_predicates_for_param_ns(self.id.parent(), self.id.into(), None) .iter() - .filter_map(|pred| match &pred.skip_binders().skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) + .filter_map(|pred| match &pred.kind().skip_binder() { + ClauseKind::Trait(trait_ref) => { + let trait_ = match trait_ref.def_id() { + SolverDefId::TraitId(t) => t, + _ => unreachable!(), + }; + Some(Trait::from(trait_)) } _ => None, }) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index a48fe43e80803..fc45dc3faf40f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -581,11 +581,13 @@ fn goto_type_action_for_def( }); } - if let Ok(generic_def) = GenericDef::try_from(def) { - generic_def.type_or_const_params(db).into_iter().for_each(|it| { - walk_and_push_ty(db, &it.ty(db), &mut push_new_def); - }); - } + salsa::attach(db, || { + if let Ok(generic_def) = GenericDef::try_from(def) { + generic_def.type_or_const_params(db).into_iter().for_each(|it| { + walk_and_push_ty(db, &it.ty(db), &mut push_new_def); + }); + } + }); let ty = match def { Definition::Local(it) => Some(it.ty(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 1c66473bf9874..2afdf18b83685 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -674,7 +674,9 @@ impl Analysis { position: FilePosition, ) -> Cancellable>> { self.with_db(|db| { - highlight_related::highlight_related(&Semantics::new(db), config, position) + salsa::attach(db, || { + highlight_related::highlight_related(&Semantics::new(db), config, position) + }) }) } From 418f419d60240e7ed24953cab9089027fa666be4 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Mon, 11 Aug 2025 04:12:43 +0000 Subject: [PATCH 065/251] Cleanup assoc_type_shorthand_candidates --- .../rust-analyzer/crates/hir/src/semantics.rs | 21 ++++++++++--------- .../ide-completion/src/completions/expr.rs | 3 +-- .../ide-completion/src/completions/type.rs | 3 +-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index b43165fd8ad70..6af0c2c3c56fb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2288,18 +2288,19 @@ impl<'db> SemanticsScope<'db> { /// Iterates over associated types that may be specified after the given path (using /// `Ty::Assoc` syntax). - pub fn assoc_type_shorthand_candidates( + pub fn assoc_type_shorthand_candidates( &self, resolution: &PathResolution, - mut cb: impl FnMut(&Name, TypeAlias) -> Option, - ) -> Option { - let def = self.resolver.generic_def()?; - hir_ty::associated_type_shorthand_candidates( - self.db, - def, - resolution.in_type_ns()?, - |name, id| cb(name, id.into()), - ) + mut cb: impl FnMut(TypeAlias), + ) { + let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns()) + else { + return; + }; + hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| { + cb(id.into()); + None::<()> + }); } pub fn generic_def(&self) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index a84927f6e2c0f..1972f166134a4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -140,9 +140,8 @@ pub(crate) fn complete_expr_path( Qualified::With { resolution: None, .. } => {} Qualified::With { resolution: Some(resolution), .. } => { // Add associated types on type parameters and `Self`. - ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| { + ctx.scope.assoc_type_shorthand_candidates(resolution, |alias| { acc.add_type_alias(ctx, alias); - None::<()> }); match resolution { hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index fc27cbd65a1ee..3112462cda4e8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -77,9 +77,8 @@ pub(crate) fn complete_type_path( Qualified::With { resolution: None, .. } => {} Qualified::With { resolution: Some(resolution), .. } => { // Add associated types on type parameters and `Self`. - ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| { + ctx.scope.assoc_type_shorthand_candidates(resolution, |alias| { acc.add_type_alias(ctx, alias); - None::<()> }); match resolution { From 064f1c7c8321547e114d576f07ecdf0b1bee97e1 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Mon, 11 Aug 2025 05:19:44 +0000 Subject: [PATCH 066/251] Switch associated_type_shorthand_candidates to lower_nextsolver --- .../crates/hir-ty/src/dyn_compatibility.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 3 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 9 - .../crates/hir-ty/src/lower_nextsolver.rs | 133 +++++++++++++- .../hir-ty/src/lower_nextsolver/path.rs | 163 ++++-------------- .../hir-ty/src/next_solver/generic_arg.rs | 19 +- .../rust-analyzer/crates/hir/src/semantics.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 17 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 6 +- 9 files changed, 197 insertions(+), 159 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 8bd555f5c08f3..48c0c81b47815 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -564,7 +564,7 @@ fn receiver_is_dispatchable<'db>( // U: Trait let trait_def_id = SolverDefId::TraitId(trait_); let args = GenericArgs::for_item(interner, trait_def_id, |name, index, kind, _| { - if index == 0 { unsized_self_ty.into() } else { mk_param(index, name, kind) } + if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) } }); let trait_predicate = crate::next_solver::TraitRef::new_from_args(interner, trait_def_id, args); @@ -611,7 +611,7 @@ fn receiver_for_self_ty<'db>( interner, SolverDefId::FunctionId(func), |name, index, kind, _| { - if index == 0 { self_ty.into() } else { mk_param(index, name, kind) } + if index == 0 { self_ty.into() } else { mk_param(interner, index, name, kind) } }, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 8ce0aeb5532ad..2f8eb627462b7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -118,8 +118,9 @@ pub use infer::{ pub use interner::Interner; pub use lower::{ ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext, - ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*, + ValueTyDefId, diagnostics::*, }; +pub use lower_nextsolver::associated_type_shorthand_candidates; pub use mapping::{ ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, 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 065d2ea084070..098c62ba97a29 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -804,15 +804,6 @@ pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableD } } -pub fn associated_type_shorthand_candidates( - db: &dyn HirDatabase, - def: GenericDefId, - res: TypeNs, - mut cb: impl FnMut(&Name, TypeAliasId) -> Option, -) -> Option { - named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id)) -} - fn named_associated_type_shorthand_candidates( db: &dyn HirDatabase, // If the type parameter is defined in an impl and we're in a method, there diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 24bda43ca634f..15c675be58199 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -12,14 +12,14 @@ pub(crate) mod path; use std::{ cell::OnceCell, iter, mem, - ops::{self, Not as _}, + ops::{self, Deref, Not as _}, }; use base_db::Crate; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TypeAliasId, + GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, expr_store::{ ExpressionStore, @@ -49,6 +49,7 @@ use rustc_type_ir::{ inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, }; use salsa::plumbing::AsId; +use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; @@ -1607,3 +1608,131 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>( Some((t.skip_binder(), assoc_type)) }) } + +pub fn associated_type_shorthand_candidates( + db: &dyn HirDatabase, + def: GenericDefId, + res: TypeNs, + mut cb: impl FnMut(&Name, TypeAliasId) -> bool, +) -> Option { + let interner = DbInterner::new_with(db, None, None); + named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| { + cb(name, id).then_some(id) + }) +} + +#[tracing::instrument(skip(interner, check_alias))] +fn named_associated_type_shorthand_candidates<'db, R>( + interner: DbInterner<'db>, + // If the type parameter is defined in an impl and we're in a method, there + // might be additional where clauses to consider + def: GenericDefId, + res: TypeNs, + assoc_name: Option, + mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option, +) -> Option { + let db = interner.db; + let mut search = |t: TraitRef<'db>| -> Option { + let trait_id = match t.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let mut checked_traits = FxHashSet::default(); + let mut check_trait = |trait_id: TraitId| { + let name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_id, ?name); + if !checked_traits.insert(trait_id) { + return None; + } + let data = trait_id.trait_items(db); + + tracing::debug!(?data.items); + for (name, assoc_id) in &data.items { + if let &AssocItemId::TypeAliasId(alias) = assoc_id + && let Some(ty) = check_alias(name, t, alias) + { + return Some(ty); + } + } + None + }; + let mut stack: SmallVec<[_; 4]> = smallvec![trait_id]; + while let Some(trait_def_id) = stack.pop() { + if let Some(alias) = check_trait(trait_def_id) { + return Some(alias); + } + for pred in generic_predicates_filtered_by( + db, + GenericDefId::TraitId(trait_def_id), + PredicateFilter::SelfTrait, + |pred| pred == GenericDefId::TraitId(trait_def_id), + ) + .0 + .deref() + { + tracing::debug!(?pred); + let trait_id = match pred.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(), + _ => continue, + }; + let trait_id = match trait_id { + SolverDefId::TraitId(trait_id) => trait_id, + _ => continue, + }; + stack.push(trait_id); + } + tracing::debug!(?stack); + } + + None + }; + + match res { + TypeNs::SelfType(impl_id) => { + let trait_ref = db.impl_trait_ns(impl_id)?; + + // we're _in_ the impl -- the binders get added back later. Correct, + // but it would be nice to make this more explicit + search(trait_ref.skip_binder()) + } + TypeNs::GenericParam(param_id) => { + // Handle `Self::Type` referring to own associated type in trait definitions + // This *must* be done first to avoid cycles with + // `generic_predicates_for_param`, but not sure that it's sufficient, + // see FIXME in `search`. + if let GenericDefId::TraitId(trait_id) = param_id.parent() { + let trait_name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_name); + let trait_generics = generics(db, trait_id.into()); + tracing::debug!(?trait_generics); + if trait_generics[param_id.local_id()].is_trait_self() { + let args = crate::next_solver::GenericArgs::identity_for_item( + interner, + trait_id.into(), + ); + let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); + tracing::debug!(?args, ?trait_ref); + return search(trait_ref); + } + } + + let predicates = + db.generic_predicates_for_param_ns(def, param_id.into(), assoc_name.clone()); + predicates + .iter() + .find_map(|pred| match (*pred).kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), + _ => None, + }) + .and_then(|trait_predicate| { + let trait_ref = trait_predicate.trait_ref; + assert!( + !trait_ref.has_escaping_bound_vars(), + "FIXME unexpected higher-ranked trait bound" + ); + search(trait_ref) + }) + } + _ => None, + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index df67b2c59b512..e3efb38306408 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -4,7 +4,7 @@ use std::ops::Deref; use either::Either; use hir_def::{ - AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, + AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, builtin_type::BuiltinType, expr_store::{ ExpressionStore, HygieneId, @@ -17,6 +17,7 @@ use hir_def::{ signatures::TraitFlags, type_ref::{TypeRef, TypeRefId}, }; +use hir_expand::name::Name; use intern::sym; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -33,7 +34,10 @@ use crate::{ db::HirDatabase, generics::{Generics, generics}, lower::PathDiagnosticCallbackData, - lower_nextsolver::{LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by}, + lower_nextsolver::{ + LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by, + named_associated_type_shorthand_candidates, + }, next_solver::{ AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate, Region, SolverDefId, TraitRef, Ty, @@ -501,137 +505,40 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let Some(res) = res else { return Ty::new_error(self.ctx.interner, ErrorGuaranteed); }; - let segment = self.current_or_prev_segment; - let assoc_name = segment.name; let db = self.ctx.db; let def = self.ctx.def; - let mut search = |t: TraitRef<'db>| { - let trait_id = match t.def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - let mut checked_traits = FxHashSet::default(); - let mut check_trait = |trait_id: TraitId| { - let name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_id, ?name); - if !checked_traits.insert(trait_id) { - return None; - } - let data = trait_id.trait_items(db); - - tracing::debug!(?data.items); - for (name, assoc_id) in &data.items { - if let &AssocItemId::TypeAliasId(alias) = assoc_id { - if name != assoc_name { - continue; - } - - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`t.substitution`). - let substs = self.substs_from_path_segment(alias.into(), false, None, true); - - let substs = crate::next_solver::GenericArgs::new_from_iter( - interner, - t.args.iter().chain(substs.iter().skip(t.args.len())), - ); - - return Some(Ty::new_alias( - interner, - AliasTyKind::Projection, - AliasTy::new(interner, alias.into(), substs), - )); - } - } - None - }; - let mut stack: SmallVec<[_; 4]> = smallvec![trait_id]; - while let Some(trait_def_id) = stack.pop() { - if let Some(alias) = check_trait(trait_def_id) { - return alias; - } - for pred in generic_predicates_filtered_by( - db, - GenericDefId::TraitId(trait_def_id), - PredicateFilter::SelfTrait, - |pred| pred == GenericDefId::TraitId(trait_def_id), - ) - .0 - .deref() - { - tracing::debug!(?pred); - let trait_id = match pred.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(), - _ => continue, - }; - let trait_id = match trait_id { - SolverDefId::TraitId(trait_id) => trait_id, - _ => continue, - }; - stack.push(trait_id); - } - tracing::debug!(?stack); + let segment = self.current_or_prev_segment; + let assoc_name = segment.name; + let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| { + if name != assoc_name { + return None; } - Ty::new_error(interner, ErrorGuaranteed) + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`t.substitution`). + let substs = self.substs_from_path_segment(associated_ty.into(), false, None, true); + + let substs = crate::next_solver::GenericArgs::new_from_iter( + interner, + t.args.iter().chain(substs.iter().skip(t.args.len())), + ); + + Some(Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy::new(interner, associated_ty.into(), substs), + )) }; - - match res { - TypeNs::SelfType(impl_id) => { - let trait_ref = db.impl_trait_ns(impl_id); - let Some(trait_ref) = trait_ref else { - return Ty::new_error(interner, ErrorGuaranteed); - }; - - // we're _in_ the impl -- the binders get added back later. Correct, - // but it would be nice to make this more explicit - search(trait_ref.skip_binder()) - } - TypeNs::GenericParam(param_id) => { - // Handle `Self::Type` referring to own associated type in trait definitions - // This *must* be done first to avoid cycles with - // `generic_predicates_for_param`, but not sure that it's sufficient, - // see FIXME in `search`. - if let GenericDefId::TraitId(trait_id) = param_id.parent() { - let trait_name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_name); - let trait_generics = generics(db, trait_id.into()); - tracing::debug!(?trait_generics); - if trait_generics[param_id.local_id()].is_trait_self() { - let args = crate::next_solver::GenericArgs::identity_for_item( - interner, - trait_id.into(), - ); - let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); - tracing::debug!(?args, ?trait_ref); - return search(trait_ref); - } - } - - let predicates = db.generic_predicates_for_param_ns( - def, - param_id.into(), - Some(segment.name.clone()), - ); - predicates - .iter() - .find_map(|pred| match (*pred).kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), - _ => None, - }) - .map(|trait_predicate| { - let trait_ref = trait_predicate.trait_ref; - assert!( - !trait_ref.has_escaping_bound_vars(), - "FIXME unexpected higher-ranked trait bound" - ); - search(trait_ref) - }) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) - } - _ => Ty::new_error(interner, ErrorGuaranteed), - } + named_associated_type_shorthand_candidates( + interner, + def, + res, + Some(assoc_name.clone()), + check_alias, + ) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) } fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 85a79923a7295..046b4303c3261 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -263,7 +263,9 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< interner: DbInterner<'db>, def_id: as rustc_type_ir::Interner>::DefId, ) -> as rustc_type_ir::Interner>::GenericArgs { - Self::for_item(interner, def_id, |name, index, kind, _| mk_param(index, name, kind)) + Self::for_item(interner, def_id, |name, index, kind, _| { + mk_param(interner, index, name, kind) + }) } fn extend_with_error( @@ -383,16 +385,19 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< } } -pub fn mk_param<'db>(index: u32, name: &Symbol, kind: GenericParamDefKind) -> GenericArg<'db> { +pub fn mk_param<'db>( + interner: DbInterner<'db>, + index: u32, + name: &Symbol, + kind: GenericParamDefKind, +) -> GenericArg<'db> { let name = name.clone(); match kind { GenericParamDefKind::Lifetime => { - Region::new_early_param(DbInterner::conjure(), EarlyParamRegion { index }).into() - } - GenericParamDefKind::Type => Ty::new_param(DbInterner::conjure(), index, name).into(), - GenericParamDefKind::Const => { - Const::new_param(DbInterner::conjure(), ParamConst { index }).into() + Region::new_early_param(interner, EarlyParamRegion { index }).into() } + GenericParamDefKind::Type => Ty::new_param(interner, index, name).into(), + GenericParamDefKind::Const => Const::new_param(interner, ParamConst { index }).into(), } } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 6af0c2c3c56fb..fa239a28f7bcd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2299,7 +2299,7 @@ impl<'db> SemanticsScope<'db> { }; hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| { cb(id.into()); - None::<()> + false }); } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 126392af4619a..e3070c5f74ce2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -14,6 +14,7 @@ use crate::{ db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; +use base_db::salsa; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, @@ -1593,12 +1594,14 @@ fn resolve_hir_path_( Some(unresolved) => resolver .generic_def() .and_then(|def| { - hir_ty::associated_type_shorthand_candidates( - db, - def, - res.in_type_ns()?, - |name, id| (name == unresolved.name).then_some(id), - ) + salsa::attach(db, || { + hir_ty::associated_type_shorthand_candidates( + db, + def, + res.in_type_ns()?, + |name, _| name == unresolved.name, + ) + }) }) .map(TypeAlias::from) .map(Into::into) @@ -1746,7 +1749,7 @@ fn resolve_hir_path_qualifier( db, def, res.in_type_ns()?, - |name, id| (name == unresolved.name).then_some(id), + |name, _| name == unresolved.name, ) }) .map(TypeAlias::from) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 2afdf18b83685..e491c9214b437 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -528,7 +528,9 @@ impl Analysis { let search_scope = AssertUnwindSafe(search_scope); self.with_db(|db| { let _ = &search_scope; - references::find_all_refs(&Semantics::new(db), position, search_scope.0) + salsa::attach(db, || { + references::find_all_refs(&Semantics::new(db), position, search_scope.0) + }) }) } @@ -574,7 +576,7 @@ impl Analysis { &self, position: FilePosition, ) -> Cancellable>>> { - self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) + self.with_db(|db| salsa::attach(db, || call_hierarchy::call_hierarchy(db, position))) } /// Computes incoming calls for the given file position. From d10e5d10fe08b3b19e72891b6069c8eee0754e37 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 12 Aug 2025 06:07:02 +0000 Subject: [PATCH 067/251] Convert more of dyn_compatibility to next-solver --- .../crates/hir-ty/src/dyn_compatibility.rs | 187 ++++-------------- .../crates/hir-ty/src/lower_nextsolver.rs | 96 ++++++++- 2 files changed, 130 insertions(+), 153 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 48c0c81b47815..54d78dea3d3b6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -2,11 +2,7 @@ use std::ops::ControlFlow; -use chalk_ir::{ - DebruijnIndex, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; -use chalk_solve::rust_ir::InlineBound; +use chalk_ir::DebruijnIndex; use hir_def::{ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, lang_item::LangItem, signatures::TraitFlags, @@ -21,14 +17,14 @@ use rustc_type_ir::{ use smallvec::SmallVec; use crate::{ - AliasEq, AliasTy, Binders, BoundVar, ImplTraitId, Interner, ProjectionTyExt, Ty, TyKind, - WhereClause, all_super_traits, + ImplTraitId, Interner, TyKind, WhereClause, all_super_traits, db::{HirDatabase, InternedOpaqueTyId}, - from_assoc_type_id, from_chalk_trait_id, + from_chalk_trait_id, generics::trait_self_param_idx, + lower_nextsolver::associated_ty_item_bounds, next_solver::{ - Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TypingMode, - infer::DbInternerInferExt, mk_param, + Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, + TypingMode, infer::DbInternerInferExt, mk_param, }, traits::next_trait_solve_in_ctxt, utils::elaborate_clause_supertraits, @@ -165,7 +161,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b // but we don't have good way to render such locations. // So, just return single boolean value for existence of such `Self` reference fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { - db.generic_predicates(trait_.into()) + db.generic_predicates_ns(trait_.into()) .iter() .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No)) } @@ -177,37 +173,18 @@ fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { .items .iter() .filter_map(|(_, it)| match *it { - AssocItemId::TypeAliasId(id) => { - let assoc_ty_data = db.associated_ty_data(id); - Some(assoc_ty_data) - } + AssocItemId::TypeAliasId(id) => Some(associated_ty_item_bounds(db, id)), _ => None, }) - .any(|assoc_ty_data| { - assoc_ty_data.binders.skip_binders().bounds.iter().any(|bound| { - let def = from_assoc_type_id(assoc_ty_data.id).into(); - match bound.skip_binders() { - InlineBound::TraitBound(it) => it.args_no_self.iter().any(|arg| { - contains_illegal_self_type_reference( - db, - def, - trait_, - arg, - DebruijnIndex::ONE, - AllowSelfProjection::Yes, - ) - }), - InlineBound::AliasEqBound(it) => it.parameters.iter().any(|arg| { - contains_illegal_self_type_reference( - db, - def, - trait_, - arg, - DebruijnIndex::ONE, - AllowSelfProjection::Yes, - ) - }), - } + .any(|bounds| { + bounds.skip_binder().iter().any(|pred| match pred.skip_binder() { + rustc_type_ir::ExistentialPredicate::Trait(it) => it.args.iter().any(|arg| { + contains_illegal_self_type_reference(db, trait_, &arg, AllowSelfProjection::Yes) + }), + rustc_type_ir::ExistentialPredicate::Projection(it) => it.args.iter().any(|arg| { + contains_illegal_self_type_reference(db, trait_, &arg, AllowSelfProjection::Yes) + }), + rustc_type_ir::ExistentialPredicate::AutoTrait(_) => false, }) }) } @@ -218,120 +195,26 @@ enum AllowSelfProjection { No, } -fn predicate_references_self( - db: &dyn HirDatabase, +fn predicate_references_self<'db>( + db: &'db dyn HirDatabase, trait_: TraitId, - predicate: &Binders>, + predicate: &Clause<'db>, allow_self_projection: AllowSelfProjection, ) -> bool { - match predicate.skip_binders().skip_binders() { - WhereClause::Implemented(trait_ref) => { - trait_ref.substitution.iter(Interner).skip(1).any(|arg| { - contains_illegal_self_type_reference( - db, - trait_.into(), - trait_, - arg, - DebruijnIndex::ONE, - allow_self_projection, - ) - }) - } - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => { - proj.substitution.iter(Interner).skip(1).any(|arg| { - contains_illegal_self_type_reference( - db, - trait_.into(), - trait_, - arg, - DebruijnIndex::ONE, - allow_self_projection, - ) + match predicate.kind().skip_binder() { + ClauseKind::Trait(trait_pred) => trait_pred.trait_ref.args.iter().skip(1).any(|arg| { + contains_illegal_self_type_reference(db, trait_, &arg, allow_self_projection) + }), + ClauseKind::Projection(proj_pred) => { + proj_pred.projection_term.args.iter().skip(1).any(|arg| { + contains_illegal_self_type_reference(db, trait_, &arg, allow_self_projection) }) } _ => false, } } -fn contains_illegal_self_type_reference>( - db: &dyn HirDatabase, - def: GenericDefId, - trait_: TraitId, - t: &T, - outer_binder: DebruijnIndex, - allow_self_projection: AllowSelfProjection, -) -> bool { - let Some(trait_self_param_idx) = trait_self_param_idx(db, def) else { - return false; - }; - struct IllegalSelfTypeVisitor<'a> { - db: &'a dyn HirDatabase, - trait_: TraitId, - super_traits: Option>, - trait_self_param_idx: usize, - allow_self_projection: AllowSelfProjection, - } - impl TypeVisitor for IllegalSelfTypeVisitor<'_> { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { - match ty.kind(Interner) { - TyKind::BoundVar(BoundVar { debruijn, index }) => { - if *debruijn == outer_binder && *index == self.trait_self_param_idx { - ControlFlow::Break(()) - } else { - ty.super_visit_with(self.as_dyn(), outer_binder) - } - } - TyKind::Alias(AliasTy::Projection(proj)) => match self.allow_self_projection { - AllowSelfProjection::Yes => { - let trait_ = proj.trait_(self.db); - if self.super_traits.is_none() { - self.super_traits = Some(all_super_traits(self.db, self.trait_)); - } - if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) { - ControlFlow::Continue(()) - } else { - ty.super_visit_with(self.as_dyn(), outer_binder) - } - } - AllowSelfProjection::No => ty.super_visit_with(self.as_dyn(), outer_binder), - }, - _ => ty.super_visit_with(self.as_dyn(), outer_binder), - } - } - - fn visit_const( - &mut self, - constant: &chalk_ir::Const, - outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow { - constant.data(Interner).ty.super_visit_with(self.as_dyn(), outer_binder) - } - } - - let mut visitor = IllegalSelfTypeVisitor { - db, - trait_, - super_traits: None, - trait_self_param_idx, - allow_self_projection, - }; - t.visit_with(visitor.as_dyn(), outer_binder).is_break() -} - -fn contains_illegal_self_type_reference_ns< - 'db, - T: rustc_type_ir::TypeVisitable>, ->( +fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable>>( db: &'db dyn HirDatabase, trait_: TraitId, t: &T, @@ -440,13 +323,17 @@ where } let sig = db.callable_item_signature_ns(func.into()); - if sig.skip_binder().inputs().iter().skip(1).any(|ty| { - contains_illegal_self_type_reference_ns(db, trait_, &ty, AllowSelfProjection::Yes) - }) { + if sig + .skip_binder() + .inputs() + .iter() + .skip(1) + .any(|ty| contains_illegal_self_type_reference(db, trait_, &ty, AllowSelfProjection::Yes)) + { cb(MethodViolationCode::ReferencesSelfInput)?; } - if contains_illegal_self_type_reference_ns( + if contains_illegal_self_type_reference( db, trait_, &sig.skip_binder().output(), @@ -496,7 +383,7 @@ where continue; } - if contains_illegal_self_type_reference_ns(db, trait_, &pred, AllowSelfProjection::Yes) { + if contains_illegal_self_type_reference(db, trait_, &pred, AllowSelfProjection::Yes) { cb(MethodViolationCode::WhereClauseReferencesSelf)?; break; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 15c675be58199..2777869bd48e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -62,9 +62,10 @@ use crate::{ lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics}, next_solver::{ AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, - BoundVarKind, BoundVarKinds, Clause, Const, DbInterner, EarlyBinder, EarlyParamRegion, - ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, - TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind, mapping::ChalkToNextSolver, + BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder, + EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, + TraitPredicate, TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind, + mapping::ChalkToNextSolver, }, }; @@ -1593,6 +1594,95 @@ fn fn_sig_for_enum_variant_constructor<'db>( })) } +pub(crate) fn associated_ty_item_bounds<'db>( + db: &'db dyn HirDatabase, + type_alias: TypeAliasId, +) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { + let trait_ = match type_alias.lookup(db).container { + ItemContainerId::TraitId(t) => t, + _ => panic!("associated type not in trait"), + }; + + let type_alias_data = db.type_alias_signature(type_alias); + let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + type_alias.into(), + LifetimeElisionKind::AnonymousReportError, + ); + // FIXME: we should never create non-existential predicates in the first place + // For now, use an error type so we don't run into dummy binder issues + let self_ty = Ty::new_error(interner, ErrorGuaranteed); + + let mut bounds = Vec::new(); + for bound in &type_alias_data.bounds { + ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| { + if let Some(bound) = pred + .kind() + .map_bound(|c| match c { + rustc_type_ir::ClauseKind::Trait(t) => { + let id = t.def_id(); + let id = match id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + let is_auto = db.trait_signature(id).flags.contains(TraitFlags::AUTO); + if is_auto { + Some(ExistentialPredicate::AutoTrait(t.def_id())) + } else { + Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args( + interner, + t.def_id(), + GenericArgs::new_from_iter( + interner, + t.trait_ref.args.iter().skip(1), + ), + ))) + } + } + rustc_type_ir::ClauseKind::Projection(p) => Some( + ExistentialPredicate::Projection(ExistentialProjection::new_from_args( + interner, + p.def_id(), + GenericArgs::new_from_iter( + interner, + p.projection_term.args.iter().skip(1), + ), + p.term, + )), + ), + rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => None, + rustc_type_ir::ClauseKind::RegionOutlives(_) + | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) + | rustc_type_ir::ClauseKind::WellFormed(_) + | rustc_type_ir::ClauseKind::ConstEvaluatable(_) + | rustc_type_ir::ClauseKind::HostEffect(_) + | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), + }) + .transpose() + { + bounds.push(bound); + } + }); + } + + if !ctx.unsized_types.contains(&self_ty) { + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new( + interner, + SolverDefId::TraitId(trait_), + [] as [crate::next_solver::GenericArg<'_>; 0], + ))); + bounds.push(sized_clause); + bounds.shrink_to_fit(); + } + + EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds)) +} + pub(crate) fn associated_type_by_name_including_super_traits<'db>( db: &'db dyn HirDatabase, trait_ref: TraitRef<'db>, From cd0e0957bff2fca7f46b87477b46ba1e21535494 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 12 Aug 2025 20:46:19 +0000 Subject: [PATCH 068/251] Switch generics_require_sized_self to next solver --- .../crates/hir-ty/src/dyn_compatibility.rs | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 54d78dea3d3b6..be8e23f7ceb15 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -2,7 +2,6 @@ use std::ops::ControlFlow; -use chalk_ir::DebruijnIndex; use hir_def::{ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, lang_item::LangItem, signatures::TraitFlags, @@ -11,23 +10,20 @@ use intern::Symbol; use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _, - Upcast, + Upcast, elaborate, inherent::{IntoKind, SliceLike}, }; use smallvec::SmallVec; use crate::{ - ImplTraitId, Interner, TyKind, WhereClause, all_super_traits, + ImplTraitId, all_super_traits, db::{HirDatabase, InternedOpaqueTyId}, - from_chalk_trait_id, - generics::trait_self_param_idx, lower_nextsolver::associated_ty_item_bounds, next_solver::{ Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TypingMode, infer::DbInternerInferExt, mk_param, }, traits::next_trait_solve_in_ctxt, - utils::elaborate_clause_supertraits, }; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -133,27 +129,23 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b return false; }; - let Some(trait_self_param_idx) = trait_self_param_idx(db, def) else { - return false; - }; - - let predicates = &*db.generic_predicates(def); - let predicates = predicates.iter().map(|p| p.skip_binders().skip_binders().clone()); - elaborate_clause_supertraits(db, predicates).any(|pred| match pred { - WhereClause::Implemented(trait_ref) => { - if from_chalk_trait_id(trait_ref.trait_id) == sized - && let TyKind::BoundVar(it) = - *trait_ref.self_type_parameter(Interner).kind(Interner) - { - // Since `generic_predicates` is `Binder>`, the `DebrujinIndex` of - // self-parameter is `1` - return it - .index_if_bound_at(DebruijnIndex::ONE) - .is_some_and(|idx| idx == trait_self_param_idx); + let interner = DbInterner::new_with(db, Some(krate), None); + let predicates = db.generic_predicates_ns(def); + elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| { + match pred.kind().skip_binder() { + ClauseKind::Trait(trait_pred) => { + if SolverDefId::TraitId(sized) == trait_pred.def_id() + && let rustc_type_ir::TyKind::Param(param_ty) = + trait_pred.trait_ref.self_ty().kind() + && param_ty.index == 0 + { + true + } else { + false + } } - false + _ => false, } - _ => false, }) } From 00856fc250be4a8e9da6630f0ee23120486418e8 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 12 Aug 2025 21:45:03 +0000 Subject: [PATCH 069/251] Remove all_super_traits in dyn_compatibility --- .../crates/hir-ty/src/dyn_compatibility.rs | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index be8e23f7ceb15..b0c61c29db0b5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -16,7 +16,7 @@ use rustc_type_ir::{ use smallvec::SmallVec; use crate::{ - ImplTraitId, all_super_traits, + ImplTraitId, db::{HirDatabase, InternedOpaqueTyId}, lower_nextsolver::associated_ty_item_bounds, next_solver::{ @@ -53,13 +53,22 @@ pub fn dyn_compatibility( db: &dyn HirDatabase, trait_: TraitId, ) -> Option { - for super_trait in all_super_traits(db, trait_).into_iter().skip(1).rev() { - if db.dyn_compatibility_of_trait(super_trait).is_some() { - return Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait)); + let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); + for super_trait in elaborate::supertrait_def_ids(interner, SolverDefId::TraitId(trait_)) { + let super_trait = match super_trait { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + if let Some(v) = db.dyn_compatibility_of_trait(super_trait) { + return if super_trait == trait_ { + Some(v) + } else { + Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait)) + }; } } - db.dyn_compatibility_of_trait(trait_) + None } pub fn dyn_compatibility_with_callback( @@ -70,7 +79,13 @@ pub fn dyn_compatibility_with_callback( where F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>, { - for super_trait in all_super_traits(db, trait_).into_iter().skip(1).rev() { + let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None); + for super_trait in elaborate::supertrait_def_ids(interner, SolverDefId::TraitId(trait_)).skip(1) + { + let super_trait = match super_trait { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; if db.dyn_compatibility_of_trait(super_trait).is_some() { cb(DynCompatibilityViolation::HasNonCompatibleSuperTrait(trait_))?; } @@ -225,6 +240,7 @@ fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable as rustc_type_ir::Interner>::Ty, ) -> Self::Result { + let interner = DbInterner::new_with(self.db, None, None); match ty.kind() { rustc_type_ir::TyKind::Param(param) if param.index == 0 => ControlFlow::Break(()), rustc_type_ir::TyKind::Param(_) => ControlFlow::Continue(()), @@ -238,7 +254,17 @@ fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable unreachable!(), }; if self.super_traits.is_none() { - self.super_traits = Some(all_super_traits(self.db, self.trait_)); + self.super_traits = Some( + elaborate::supertrait_def_ids( + interner, + SolverDefId::TraitId(self.trait_), + ) + .map(|super_trait| match super_trait { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }) + .collect(), + ) } if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) { ControlFlow::Continue(()) From f92ca612a8bbb71159fbfc11510b5ce393534c2e Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 12 Aug 2025 22:21:48 +0000 Subject: [PATCH 070/251] Replace layout_of_ty with layout_of_ty_ns --- .../crates/hir-ty/src/consteval.rs | 13 ++++++-- .../crates/hir-ty/src/consteval_nextsolver.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 14 +++----- .../crates/hir-ty/src/display.rs | 15 +++++---- .../rust-analyzer/crates/hir-ty/src/layout.rs | 32 ++++--------------- .../crates/hir-ty/src/layout/adt.rs | 2 +- .../crates/hir-ty/src/layout/tests.rs | 23 ++++++++----- .../crates/hir-ty/src/mir/eval.rs | 2 +- .../crates/hir-ty/src/mir/lower.rs | 9 ++++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 ++-- .../rust-analyzer/crates/ide/src/hover.rs | 26 ++++++++------- .../crates/ide/src/view_memory_layout.rs | 4 +-- 12 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index f30ec839a0096..abf97f3d0e302 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -15,8 +15,14 @@ use triomphe::Arc; use crate::{ Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, db::HirDatabase, display::DisplayTarget, generics::Generics, - infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx, + TraitEnvironment, Ty, TyBuilder, + db::HirDatabase, + display::DisplayTarget, + generics::Generics, + infer::InferenceContext, + lower::ParamLoweringMode, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, + to_placeholder_idx, }; use super::mir::{MirEvalError, MirLowerError, interpret_mir, lower_to_mir, pad16}; @@ -157,7 +163,8 @@ pub fn intern_const_ref( ty: Ty, krate: Crate, ) -> Const { - let layout = || db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate)); + let interner = DbInterner::new_with(db, Some(krate), None); + let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate)); let bytes = match value { LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index cdf861290ab92..00fc4e5610dce 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -92,7 +92,7 @@ pub fn intern_const_ref<'a>( krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_with(db, Some(krate), None); - let layout = db.layout_of_ty_ns(ty, TraitEnvironment::empty(krate)); + let layout = db.layout_of_ty(ty, TraitEnvironment::empty(krate)); let kind = match value { LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 161ad31e579b2..9affd3b48c587 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -103,7 +103,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::layout::layout_of_ty_query)] #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_cycle_result)] - fn layout_of_ty(&self, ty: Ty, env: Arc) -> Result, LayoutError>; + fn layout_of_ty<'db>( + &'db self, + ty: crate::next_solver::Ty<'db>, + env: Arc, + ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: Crate) -> Result, Arc>; @@ -300,14 +304,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - #[salsa::invoke(crate::layout::layout_of_ty_ns_query)] - #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_ns_cycle_result)] - fn layout_of_ty_ns<'db>( - &'db self, - ty: crate::next_solver::Ty<'db>, - env: Arc, - ) -> Result, LayoutError>; - #[salsa::invoke(crate::lower_nextsolver::ty_query)] #[salsa::transparent] fn ty_ns<'db>( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 5adbea75a67dd..cdf6085b65348 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -840,7 +840,7 @@ fn render_const_scalar_inner( TyKind::Slice(ty) => { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); - let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else { return f.write_str(""); }; let size_one = layout.size.bytes_usize(); @@ -874,7 +874,7 @@ fn render_const_scalar_inner( let Ok(t) = memory_map.vtable_ty(ty_id) else { return f.write_str(""); }; - let Ok(layout) = f.db.layout_of_ty_ns(t, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(t, trait_env) else { return f.write_str(""); }; let size = layout.size.bytes_usize(); @@ -905,7 +905,7 @@ fn render_const_scalar_inner( return f.write_str(""); } }); - let Ok(layout) = f.db.layout_of_ty_ns(t, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(t, trait_env) else { return f.write_str(""); }; let size = layout.size.bytes_usize(); @@ -917,7 +917,7 @@ fn render_const_scalar_inner( } }, TyKind::Tuple(tys) => { - let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { return f.write_str(""); }; f.write_str("(")?; @@ -929,7 +929,7 @@ fn render_const_scalar_inner( f.write_str(", ")?; } let offset = layout.fields.offset(id).bytes_usize(); - let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { f.write_str("")?; continue; }; @@ -1006,7 +1006,7 @@ fn render_const_scalar_inner( let Some(len) = consteval_nextsolver::try_const_usize(f.db, len) else { return f.write_str(""); }; - let Ok(layout) = f.db.layout_of_ty_ns(ty, trait_env) else { + let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else { return f.write_str(""); }; let size_one = layout.size.bytes_usize(); @@ -1061,7 +1061,8 @@ fn render_variant_after_name( let ty = field_types[id] .clone() .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); - let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else { + let Ok(layout) = f.db.layout_of_ty(ty.to_nextsolver(interner), trait_env.clone()) + else { return f.write_str(""); }; let size = layout.size.bytes_usize(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 0a8ec949b7c0a..e2ee8935a8855 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -151,23 +151,13 @@ fn layout_of_simd_ty<'db>( }; let e_len = try_const_usize(db, e_len).ok_or(LayoutError::HasErrorConst)? as u64; - let e_ly = db.layout_of_ty_ns(e_ty, env)?; + let e_ly = db.layout_of_ty(e_ty, env)?; let cx = LayoutCx::new(dl); Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) } -pub fn layout_of_ty_query( - db: &dyn HirDatabase, - ty: crate::Ty, - trait_env: Arc, -) -> Result, LayoutError> { - let krate = trait_env.krate; - let interner = DbInterner::new_with(db, Some(krate), trait_env.block); - db.layout_of_ty_ns(ty.to_nextsolver(interner), trait_env) -} - -pub fn layout_of_ty_ns_query<'db>( +pub fn layout_of_ty_query<'db>( db: &'db dyn HirDatabase, ty: Ty<'db>, trait_env: Arc, @@ -262,7 +252,7 @@ pub fn layout_of_ty_ns_query<'db>( let fields = tys .iter() - .map(|k| db.layout_of_ty_ns(k, trait_env.clone())) + .map(|k| db.layout_of_ty(k, trait_env.clone())) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); @@ -270,11 +260,11 @@ pub fn layout_of_ty_ns_query<'db>( } TyKind::Array(element, count) => { let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; - let element = db.layout_of_ty_ns(element, trait_env)?; + let element = db.layout_of_ty(element, trait_env)?; cx.calc.array_like::<_, _, ()>(&element, Some(count))? } TyKind::Slice(element) => { - let element = db.layout_of_ty_ns(element, trait_env)?; + let element = db.layout_of_ty(element, trait_env)?; cx.calc.array_like::<_, _, ()>(&element, None)? } TyKind::Str => { @@ -346,7 +336,7 @@ pub fn layout_of_ty_ns_query<'db>( let ty = convert_binder_to_early_binder(interner, it.ty.to_nextsolver(interner)) .instantiate(interner, args); - db.layout_of_ty_ns(ty, trait_env.clone()) + db.layout_of_ty(ty, trait_env.clone()) }) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); @@ -376,15 +366,7 @@ pub fn layout_of_ty_ns_query<'db>( Ok(Arc::new(result)) } -pub(crate) fn layout_of_ty_cycle_result( - _: &dyn HirDatabase, - _: crate::Ty, - _: Arc, -) -> Result, LayoutError> { - Err(LayoutError::RecursiveTypeWithoutIndirection) -} - -pub(crate) fn layout_of_ty_ns_cycle_result<'db>( +pub(crate) fn layout_of_ty_cycle_result<'db>( _: &dyn HirDatabase, _: Ty<'db>, _: Arc, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index fefa3f2617439..9a746ca888589 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -34,7 +34,7 @@ pub fn layout_of_adt_query<'db>( let handle_variant = |def: VariantId, var: &VariantFields| { var.fields() .iter() - .map(|(fd, _)| db.layout_of_ty_ns(field_ty(db, def, fd, &args), trait_env.clone())) + .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &args), trait_env.clone())) .collect::, _>>() }; let (variants, repr, is_special_no_niche) = match def { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 93f2e123dca58..90de7e5ca633d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -11,6 +11,7 @@ use crate::{ Interner, Substitution, db::HirDatabase, layout::{Layout, LayoutError}, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, setup_tracing, test_db::TestDB, }; @@ -85,13 +86,16 @@ fn eval_goal( db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner)) } }; - db.layout_of_ty( - goal_ty, - db.trait_environment(match adt_or_type_alias_id { - Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), - Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), - }), - ) + salsa::attach(&db, || { + let interner = DbInterner::new_with(&db, None, None); + db.layout_of_ty( + goal_ty.to_nextsolver(interner), + db.trait_environment(match adt_or_type_alias_id { + Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), + Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), + }), + ) + }) } /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait` @@ -128,7 +132,10 @@ fn eval_expr( .0; let infer = db.infer(function_id.into()); let goal_ty = infer.type_of_binding[b].clone(); - db.layout_of_ty(goal_ty, db.trait_environment(function_id.into())) + salsa::attach(&db, || { + let interner = DbInterner::new_with(&db, None, None); + db.layout_of_ty(goal_ty.to_nextsolver(interner), db.trait_environment(function_id.into())) + }) } #[track_caller] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index d0ae92961efc0..9deaa4ac5a6b5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -854,7 +854,7 @@ impl<'db> Evaluator<'db> { let interner = DbInterner::new_with(self.db, None, None); let r = self .db - .layout_of_ty_ns(ty, self.trait_env.clone()) + .layout_of_ty(ty, self.trait_env.clone()) .map_err(|e| MirEvalError::LayoutError(e, convert_ty_for_result(interner, ty)))?; self.layout_cache.borrow_mut().insert(ty, r.clone()); Ok(r) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 0bb8e6fe79d65..052be11e433f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -43,6 +43,7 @@ use crate::{ Terminator, TerminatorKind, TupleFieldId, Ty, UnOp, VariantId, intern_const_scalar, return_slot, }, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, static_lifetime, traits::FnTrait, utils::ClosureSubst, @@ -1411,8 +1412,12 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { - let size = - || self.db.layout_of_ty(ty.clone(), self.env.clone()).map(|it| it.size.bytes_usize()); + let interner = DbInterner::new_with(self.db, None, None); + let size = || { + self.db + .layout_of_ty(ty.to_nextsolver(interner), self.env.clone()) + .map(|it| it.size.bytes_usize()) + }; const USIZE_SIZE: usize = size_of::(); let bytes: Box<[_]> = match l { hir_def::hir::Literal::String(b) => { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 18c3ea05614a8..e423d2c07c159 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1389,8 +1389,9 @@ impl Field { } pub fn layout(&self, db: &dyn HirDatabase) -> Result { + let interner = DbInterner::new_with(db, None, None); db.layout_of_ty( - self.ty(db).ty, + self.ty(db).ty.to_nextsolver(interner), db.trait_environment(match hir_def::VariantId::from(self.parent) { hir_def::VariantId::EnumVariantId(id) => { GenericDefId::AdtId(id.lookup(db).parent.into()) @@ -5906,7 +5907,8 @@ impl<'db> Type<'db> { } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result { - db.layout_of_ty(self.ty.clone(), self.env.clone()) + let interner = DbInterner::new_with(db, None, None); + db.layout_of_ty(self.ty.to_nextsolver(interner), self.env.clone()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index fc45dc3faf40f..b0ef83e0501b3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -137,18 +137,20 @@ pub(crate) fn hover( let edition = sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT); let display_target = sema.first_crate(file_id)?.to_display_target(db); - let mut res = if range.is_empty() { - hover_offset( - sema, - FilePosition { file_id, offset: range.start() }, - file, - config, - edition, - display_target, - ) - } else { - hover_ranged(sema, frange, file, config, edition, display_target) - }?; + let mut res = salsa::attach(sema.db, || { + if range.is_empty() { + hover_offset( + sema, + FilePosition { file_id, offset: range.start() }, + file, + config, + edition, + display_target, + ) + } else { + hover_ranged(sema, frange, file, config, edition, display_target) + } + })?; if let HoverDocFormat::PlainText = config.format { res.info.markup = remove_markdown(res.info.markup.as_str()).into(); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 1eb0fd4fd8b76..950f3f6c64706 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -139,7 +139,7 @@ pub(crate) fn view_memory_layout( nodes[parent_idx].children_len = fields.len() as u64; for (field, child_ty) in fields.iter() { - if let Ok(child_layout) = child_ty.layout(db) { + if let Ok(child_layout) = salsa::attach(db, || child_ty.layout(db)) { nodes.push(MemoryLayoutNode { item_name: field.name(db), typename: salsa::attach(db, || { @@ -172,7 +172,7 @@ pub(crate) fn view_memory_layout( } for (i, (_, child_ty)) in fields.iter().enumerate() { - if let Ok(child_layout) = child_ty.layout(db) { + if let Ok(child_layout) = salsa::attach(db, || child_ty.layout(db)) { read_layout(nodes, db, child_ty, &child_layout, children_start + i, display_target); } } From 05bc1818dac760fac07c9c6d562977cd9b51dab1 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 03:13:45 +0000 Subject: [PATCH 071/251] Switch TraitRef in hir::TraitRef to next solver --- .../crates/hir-ty/src/display.rs | 238 ++++++++++++++++-- .../hir-ty/src/next_solver/generic_arg.rs | 23 ++ .../crates/hir-ty/src/next_solver/mapping.rs | 25 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 43 ++-- 4 files changed, 288 insertions(+), 41 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index cdf6085b65348..ae0113fcbd7f0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -11,8 +11,8 @@ use base_db::Crate; use chalk_ir::{BoundVar, Safety, TyKind}; use either::Either; use hir_def::{ - GenericDefId, HasModule, ImportPathConfig, LocalFieldId, Lookup, ModuleDefId, ModuleId, - TraitId, + GeneralConstId, GenericDefId, HasModule, ImportPathConfig, LocalFieldId, Lookup, ModuleDefId, + ModuleId, TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -38,7 +38,7 @@ use rustc_apfloat::{ }; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, + AliasTyKind, RegionKind, inherent::{AdtDef, IntoKind, SliceLike}, }; use smallvec::SmallVec; @@ -61,8 +61,9 @@ use crate::{ next_solver::{ BoundExistentialPredicate, Ctor, DbInterner, GenericArgs, SolverDefId, mapping::{ - ChalkToNextSolver, convert_args_for_result, convert_const_for_result, - convert_region_for_result, convert_ty_for_result, + ChalkToNextSolver, bound_var_to_lifetime_idx, bound_var_to_type_or_const_param_idx, + convert_args_for_result, convert_const_for_result, convert_region_for_result, + convert_ty_for_result, }, }, primitive, to_assoc_type_id, @@ -715,28 +716,56 @@ impl HirDisplay for GenericArg { } } +impl<'db> HirDisplay for crate::next_solver::GenericArg<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + match self.kind() { + rustc_type_ir::GenericArgKind::Type(ty) => ty.hir_fmt(f), + rustc_type_ir::GenericArgKind::Lifetime(lt) => lt.hir_fmt(f), + rustc_type_ir::GenericArgKind::Const(c) => c.hir_fmt(f), + } + } +} + impl HirDisplay for Const { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let data = self.interned(); - match &data.value { - ConstValue::BoundVar(idx) => idx.hir_fmt(f), - ConstValue::InferenceVar(..) => write!(f, "#c#"), - ConstValue::Placeholder(idx) => { - let id = from_placeholder_idx(f.db, *idx); + let c = self.to_nextsolver(DbInterner::new_with(f.db, None, None)); + c.hir_fmt(f) + } +} + +impl<'db> HirDisplay for crate::next_solver::Const<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + match self.kind() { + rustc_type_ir::ConstKind::Bound(db, bound_const) => { + write!(f, "?{}.{}", db.as_u32(), bound_const.as_u32()) + } + rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"), + rustc_type_ir::ConstKind::Placeholder(idx) => { + let id = bound_var_to_type_or_const_param_idx(f.db, idx.bound); let generics = generics(f.db, id.parent); let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; Ok(()) } - ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(b, m) => render_const_scalar(f, b, m, &data.ty), - ConstScalar::UnevaluatedConst(c, parameters) => { - write!(f, "{}", c.name(f.db))?; - hir_fmt_generics(f, parameters.as_slice(Interner), c.generic_def(f.db), None)?; - Ok(()) - } - ConstScalar::Unknown => f.write_char('_'), - }, + rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns( + f, + &const_bytes.value.inner().0, + &const_bytes.value.inner().1, + const_bytes.ty, + ), + rustc_type_ir::ConstKind::Unevaluated(unev) => { + let c = match unev.def { + SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), + SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), + _ => unreachable!(), + }; + write!(f, "{}", c.name(f.db))?; + hir_fmt_generics_ns(f, unev.args.as_slice(), c.generic_def(f.db), None)?; + Ok(()) + } + rustc_type_ir::ConstKind::Error(..) => f.write_char('_'), + rustc_type_ir::ConstKind::Expr(..) => write!(f, ""), + rustc_type_ir::ConstKind::Param(_) => write!(f, ""), } } } @@ -1748,6 +1777,27 @@ fn hir_fmt_generics( Ok(()) } +fn hir_fmt_generics_ns<'db>( + f: &mut HirFormatter<'_>, + parameters: &[crate::next_solver::GenericArg<'db>], + generic_def: Option, + self_: Option>, +) -> Result<(), HirDisplayError> { + if parameters.is_empty() { + return Ok(()); + } + + let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters); + + if !parameters_to_write.is_empty() { + write!(f, "<")?; + hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?; + write!(f, ">")?; + } + + Ok(()) +} + fn generic_args_sans_defaults<'ga>( f: &mut HirFormatter<'_>, generic_def: Option, @@ -1803,6 +1853,87 @@ fn generic_args_sans_defaults<'ga>( } } +fn hir_fmt_generic_args<'db>( + f: &mut HirFormatter<'_>, + parameters: &[crate::next_solver::GenericArg<'db>], + generic_def: Option, + self_: Option>, +) -> Result<(), HirDisplayError> { + if parameters.is_empty() { + return Ok(()); + } + + let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters); + + if !parameters_to_write.is_empty() { + write!(f, "<")?; + hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?; + write!(f, ">")?; + } + + Ok(()) +} + +fn generic_args_sans_defaults_ns<'ga, 'db>( + f: &mut HirFormatter<'_>, + generic_def: Option, + parameters: &'ga [crate::next_solver::GenericArg<'db>], +) -> &'ga [crate::next_solver::GenericArg<'db>] { + let interner = DbInterner::new_with(f.db, Some(f.krate()), None); + if f.display_kind.is_source_code() || f.omit_verbose_types() { + match generic_def + .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) + .filter(|it| !it.is_empty()) + { + None => parameters, + Some(default_parameters) => { + let should_show = |arg: &crate::next_solver::GenericArg<'db>, i: usize| { + let is_err = |arg: &crate::next_solver::GenericArg<'db>| match arg.kind() { + rustc_type_ir::GenericArgKind::Lifetime(it) => { + matches!(it.kind(), RegionKind::ReError(..)) + } + rustc_type_ir::GenericArgKind::Type(it) => { + matches!(it.kind(), rustc_type_ir::TyKind::Error(..)) + } + rustc_type_ir::GenericArgKind::Const(it) => { + matches!(it.kind(), rustc_type_ir::ConstKind::Error(..),) + } + }; + // if the arg is error like, render it to inform the user + if is_err(arg) { + return true; + } + // otherwise, if the arg is equal to the param default, hide it (unless the + // default is an error which can happen for the trait Self type) + match default_parameters.get(i) { + None => true, + Some(default_parameter) => { + // !is_err(default_parameter.skip_binders()) + // && + arg != &default_parameter + .clone() + .substitute( + Interner, + &convert_args_for_result(interner, ¶meters[..i]), + ) + .to_nextsolver(interner) + } + } + }; + let mut default_from = 0; + for (i, parameter) in parameters.iter().enumerate() { + if should_show(parameter, i) { + default_from = i + 1; + } + } + ¶meters[0..default_from] + } + } + } else { + parameters + } +} + fn hir_fmt_generic_arguments( f: &mut HirFormatter<'_>, parameters: &[GenericArg], @@ -1827,6 +1958,30 @@ fn hir_fmt_generic_arguments( Ok(()) } +fn hir_fmt_generic_arguments_ns<'db>( + f: &mut HirFormatter<'_>, + parameters: &[crate::next_solver::GenericArg<'db>], + self_: Option>, +) -> Result<(), HirDisplayError> { + let mut first = true; + let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some()); + + let (ty_or_const, lifetimes) = match lifetime_offset { + Some(offset) => parameters.split_at(offset), + None => (parameters, &[][..]), + }; + for generic_arg in lifetimes.iter().chain(ty_or_const) { + if !mem::take(&mut first) { + write!(f, ", ")?; + } + match self_ { + self_ @ Some(_) if generic_arg.ty() == self_ => write!(f, "Self")?, + _ => generic_arg.hir_fmt(f)?, + } + } + Ok(()) +} + impl HirDisplay for CallableSig { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let CallableSig { params_and_return: _, is_varargs, safety, abi: _ } = *self; @@ -2067,6 +2222,20 @@ impl HirDisplay for TraitRef { } } +impl<'db> HirDisplay for crate::next_solver::TraitRef<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + let trait_ = match self.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; + f.start_location_link(trait_.into()); + write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; + f.end_location_link(); + let substs = self.args.as_slice(); + hir_fmt_generic_args(f, &substs[1..], None, substs[0].ty()) + } +} + impl HirDisplay for WhereClause { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { if f.should_truncate() { @@ -2147,6 +2316,35 @@ impl HirDisplay for LifetimeData { } } +impl<'db> HirDisplay for crate::next_solver::Region<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + match self.kind() { + rustc_type_ir::RegionKind::RePlaceholder(idx) => { + let id = bound_var_to_lifetime_idx(f.db, idx.bound.var); + let generics = generics(f.db, id.parent); + let param_data = &generics[id.local_id]; + write!(f, "{}", param_data.name.display(f.db, f.edition()))?; + Ok(()) + } + rustc_type_ir::RegionKind::ReBound(db, idx) => { + write!(f, "?{}.{}", db.as_u32(), idx.var.as_u32()) + } + rustc_type_ir::RegionKind::ReVar(_) => write!(f, "_"), + rustc_type_ir::RegionKind::ReStatic => write!(f, "'static"), + rustc_type_ir::RegionKind::ReError(..) => { + if cfg!(test) { + write!(f, "'?") + } else { + write!(f, "'_") + } + } + rustc_type_ir::RegionKind::ReErased => write!(f, "'"), + rustc_type_ir::RegionKind::ReEarlyParam(_) => write!(f, ""), + rustc_type_ir::RegionKind::ReLateParam(_) => write!(f, ""), + } + } +} + impl HirDisplay for DomainGoal { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 046b4303c3261..834f4e3765ee8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -35,6 +35,29 @@ impl<'db> std::fmt::Debug for GenericArg<'db> { } } +impl<'db> GenericArg<'db> { + pub fn ty(self) -> Option> { + match self.kind() { + GenericArgKind::Type(ty) => Some(ty), + _ => None, + } + } + + pub fn expect_ty(self) -> Ty<'db> { + match self.kind() { + GenericArgKind::Type(ty) => ty, + _ => panic!("Expected ty, got {:?}", self), + } + } + + pub fn region(self) -> Option> { + match self.kind() { + GenericArgKind::Lifetime(r) => Some(r), + _ => None, + } + } +} + impl<'db> From> for GenericArg<'db> { fn from(value: Term<'db>) -> Self { match value { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 5fefb04a5e768..cad51fd85f55a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -18,13 +18,14 @@ use rustc_type_ir::{ shift_vars, solve::Goal, }; -use salsa::plumbing::AsId; +use salsa::plumbing::FromId; +use salsa::{Id, plumbing::AsId}; use crate::{ ConcreteConst, ConstScalar, ImplTraitId, Interner, MemoryMap, db::{ - HirDatabase, InternedClosureId, InternedCoroutineId, InternedOpaqueTyId, - InternedTypeOrConstParamId, + HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId, + InternedOpaqueTyId, InternedTypeOrConstParamId, }, from_assoc_type_id, from_chalk_trait_id, mapping::ToChalk, @@ -55,6 +56,24 @@ pub fn to_placeholder_idx( } } +pub fn bound_var_to_type_or_const_param_idx( + db: &dyn HirDatabase, + var: rustc_type_ir::BoundVar, +) -> TypeOrConstParamId { + // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. + let interned_id = InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(var.as_u32()) }); + interned_id.loc(db) +} + +pub fn bound_var_to_lifetime_idx( + db: &dyn HirDatabase, + var: rustc_type_ir::BoundVar, +) -> LifetimeParamId { + // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. + let interned_id = InternedLifetimeParamId::from_id(unsafe { Id::from_index(var.as_u32()) }); + interned_id.loc(db) +} + pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable>>( interner: DbInterner<'db>, binder: rustc_type_ir::Binder, T>, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index e423d2c07c159..46a0f584c0131 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -115,7 +115,7 @@ pub use crate::{ VisibleTraits, }, }; -use rustc_type_ir::inherent::IntoKind; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; // Be careful with these re-exports. // @@ -4513,14 +4513,20 @@ impl Impl { } pub fn trait_(self, db: &dyn HirDatabase) -> Option { - let trait_ref = db.impl_trait(self.id)?; - let id = trait_ref.skip_binders().hir_trait_id(); + let trait_ref = db.impl_trait_ns(self.id)?; + let id = trait_ref.skip_binder().def_id; + let id = match id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; Some(Trait { id }) } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { + let interner = DbInterner::new_with(db, None, None); let substs = TyBuilder::placeholder_subst(db, self.id); - let trait_ref = db.impl_trait(self.id)?.substitute(Interner, &substs); + let trait_ref = + db.impl_trait(self.id)?.substitute(Interner, &substs).to_nextsolver(interner); let resolver = self.id.resolver(db); Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) } @@ -4589,7 +4595,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { env: Arc, - trait_ref: hir_ty::TraitRef, + trait_ref: hir_ty::next_solver::TraitRef<'db>, _pd: PhantomCovariantLifetime<'db>, } @@ -4597,7 +4603,7 @@ impl<'db> TraitRef<'db> { pub(crate) fn new_with_resolver( db: &'db dyn HirDatabase, resolver: &Resolver<'_>, - trait_ref: hir_ty::TraitRef, + trait_ref: hir_ty::next_solver::TraitRef<'db>, ) -> Self { let env = resolver .generic_def() @@ -4606,25 +4612,26 @@ impl<'db> TraitRef<'db> { } pub fn trait_(&self) -> Trait { - let id = self.trait_ref.hir_trait_id(); + let id = match self.trait_ref.def_id { + SolverDefId::TraitId(id) => id, + _ => unreachable!(), + }; Trait { id } } - pub fn self_ty(&self) -> Type<'_> { - let ty = self.trait_ref.self_type_parameter(Interner); - Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } + pub fn self_ty(&self) -> TypeNs<'_> { + let ty = self.trait_ref.self_ty(); + TypeNs { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } } /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the /// first argument is the `Self` type. - pub fn get_type_argument(&self, idx: usize) -> Option> { - self.trait_ref - .substitution - .as_slice(Interner) - .get(idx) - .and_then(|arg| arg.ty(Interner)) - .cloned() - .map(|ty| Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }) + pub fn get_type_argument(&self, idx: usize) -> Option> { + self.trait_ref.args.as_slice().get(idx).and_then(|arg| arg.ty()).map(|ty| TypeNs { + env: self.env.clone(), + ty, + _pd: PhantomCovariantLifetime::new(), + }) } } From 49f166029f6956c6422b73bfa52f416cd2be12f0 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 03:35:01 +0000 Subject: [PATCH 072/251] Use impl_trait_ns in Impl::trait_ref --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 46a0f584c0131..ff7d116dcce3e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4523,10 +4523,7 @@ impl Impl { } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { - let interner = DbInterner::new_with(db, None, None); - let substs = TyBuilder::placeholder_subst(db, self.id); - let trait_ref = - db.impl_trait(self.id)?.substitute(Interner, &substs).to_nextsolver(interner); + let trait_ref = db.impl_trait_ns(self.id)?.instantiate_identity(); let resolver = self.id.resolver(db); Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) } From e5d320fd6c28b5099389e0a34a688e8d37d90f4b Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 13 Aug 2025 04:23:00 +0000 Subject: [PATCH 073/251] Remove a bunch of stuff from chalk_db --- .../crates/hir-ty/src/chalk_db.rs | 425 +----------------- .../rust-analyzer/crates/hir-ty/src/db.rs | 29 -- .../crates/hir-ty/src/diagnostics/expr.rs | 7 +- .../crates/hir-ty/src/infer/cast.rs | 12 +- .../crates/hir-ty/src/infer/closure.rs | 26 +- .../crates/hir-ty/src/mapping.rs | 19 - src/tools/rust-analyzer/crates/hir/src/lib.rs | 75 +++- 7 files changed, 80 insertions(+), 513 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index f523a5e8bfa05..546991cf6571e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -1,44 +1,13 @@ //! The implementation of `RustIrDatabase` for Chalk, which provides information //! about the code that Chalk needs. -use std::sync::Arc; +use hir_def::{CallableDefId, GenericDefId}; -use tracing::debug; - -use chalk_ir::{cast::Caster, fold::shift::Shift}; -use chalk_solve::rust_ir::{self, WellKnownTrait}; - -use base_db::Crate; -use hir_def::{ - AssocItemId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, - VariantId, - lang_item::LangItem, - signatures::{ImplFlags, StructFlags, TraitFlags}, -}; - -use crate::{ - AliasEq, AliasTy, DebruijnIndex, Interner, ProjectionTyExt, QuantifiedWhereClause, - Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, - db::HirDatabase, - from_assoc_type_id, from_chalk_trait_id, - generics::generics, - lower::LifetimeElisionKind, - make_binders, - mapping::{ToChalk, TypeAliasAsValue, from_chalk}, - to_assoc_type_id, to_chalk_trait_id, -}; - -pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; -pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum; -pub(crate) type AdtDatum = chalk_solve::rust_ir::AdtDatum; -pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum; +use crate::{Interner, Substitution, db::HirDatabase, mapping::from_chalk}; pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; pub(crate) type TraitId = chalk_ir::TraitId; pub(crate) type AdtId = chalk_ir::AdtId; pub(crate) type ImplId = chalk_ir::ImplId; -pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId; -pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue; -pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum; pub(crate) type Variances = chalk_ir::Variances; impl chalk_ir::UnificationDatabase for &dyn HirDatabase { @@ -54,340 +23,6 @@ impl chalk_ir::UnificationDatabase for &dyn HirDatabase { } } -pub(crate) fn associated_ty_data_query( - db: &dyn HirDatabase, - type_alias: TypeAliasId, -) -> Arc { - debug!("associated_ty_data {:?}", type_alias); - let trait_ = match type_alias.lookup(db).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - - // Lower bounds -- we could/should maybe move this to a separate query in `lower` - let type_alias_data = db.type_alias_signature(type_alias); - let generic_params = generics(db, type_alias.into()); - let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); - let mut ctx = crate::TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - type_alias.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); - - let trait_subst = TyBuilder::subst_for_def(db, trait_, None) - .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0) - .build(); - let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst)) - .fill_with_bound_vars( - crate::DebruijnIndex::INNERMOST, - generic_params.parent_generics().map_or(0, |it| it.len()), - ) - .build(); - let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner); - - let mut bounds = Vec::new(); - for bound in &type_alias_data.bounds { - ctx.lower_type_bound(bound, self_ty.clone(), false).for_each(|pred| { - if let Some(pred) = generic_predicate_to_inline_bound(db, &pred, &self_ty) { - bounds.push(pred); - } - }); - } - - if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = - LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id); - let sized_bound = sized_trait.into_iter().map(|sized_trait| { - let trait_bound = - rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() }; - let inline_bound = rust_ir::InlineBound::TraitBound(trait_bound); - chalk_ir::Binders::empty(Interner, inline_bound) - }); - bounds.extend(sized_bound); - bounds.shrink_to_fit(); - } - - // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed. - // (rust-analyzer#9052) - // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); - let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] }; - let datum = AssociatedTyDatum { - trait_id: to_chalk_trait_id(trait_), - id: to_assoc_type_id(type_alias), - name: type_alias, - binders: make_binders(db, &generic_params, bound_data), - }; - Arc::new(datum) -} - -pub(crate) fn trait_datum_query( - db: &dyn HirDatabase, - krate: Crate, - trait_id: TraitId, -) -> Arc { - debug!("trait_datum {:?}", trait_id); - let trait_ = from_chalk_trait_id(trait_id); - let trait_data = db.trait_signature(trait_); - debug!("trait {:?} = {:?}", trait_id, trait_data.name); - let generic_params = generics(db, trait_.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let flags = rust_ir::TraitFlags { - auto: trait_data.flags.contains(TraitFlags::AUTO), - upstream: trait_.lookup(db).container.krate() != krate, - non_enumerable: true, - coinductive: false, // only relevant for Chalk testing - // FIXME: set these flags correctly - marker: false, - fundamental: trait_data.flags.contains(TraitFlags::FUNDAMENTAL), - }; - let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); - let associated_ty_ids = - trait_.trait_items(db).associated_types().map(to_assoc_type_id).collect(); - let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; - let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item); - let trait_datum = TraitDatum { - id: trait_id, - binders: make_binders(db, &generic_params, trait_datum_bound), - flags, - associated_ty_ids, - well_known, - }; - Arc::new(trait_datum) -} - -fn well_known_trait_from_lang_item(item: LangItem) -> Option { - Some(match item { - LangItem::Clone => WellKnownTrait::Clone, - LangItem::CoerceUnsized => WellKnownTrait::CoerceUnsized, - LangItem::Copy => WellKnownTrait::Copy, - LangItem::DiscriminantKind => WellKnownTrait::DiscriminantKind, - LangItem::DispatchFromDyn => WellKnownTrait::DispatchFromDyn, - LangItem::Drop => WellKnownTrait::Drop, - LangItem::Fn => WellKnownTrait::Fn, - LangItem::FnMut => WellKnownTrait::FnMut, - LangItem::FnOnce => WellKnownTrait::FnOnce, - LangItem::AsyncFn => WellKnownTrait::AsyncFn, - LangItem::AsyncFnMut => WellKnownTrait::AsyncFnMut, - LangItem::AsyncFnOnce => WellKnownTrait::AsyncFnOnce, - LangItem::Coroutine => WellKnownTrait::Coroutine, - LangItem::Sized => WellKnownTrait::Sized, - LangItem::Unpin => WellKnownTrait::Unpin, - LangItem::Unsize => WellKnownTrait::Unsize, - LangItem::Tuple => WellKnownTrait::Tuple, - LangItem::PointeeTrait => WellKnownTrait::Pointee, - LangItem::FnPtrTrait => WellKnownTrait::FnPtr, - LangItem::Future => WellKnownTrait::Future, - _ => return None, - }) -} - -pub(crate) fn adt_datum_query( - db: &dyn HirDatabase, - krate: Crate, - chalk_ir::AdtId(adt_id): AdtId, -) -> Arc { - debug!("adt_datum {:?}", adt_id); - let generic_params = generics(db, adt_id.into()); - let bound_vars_subst = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let where_clauses = convert_where_clauses(db, adt_id.into(), &bound_vars_subst); - - let (fundamental, phantom_data) = match adt_id { - hir_def::AdtId::StructId(s) => { - let flags = db.struct_signature(s).flags; - (flags.contains(StructFlags::FUNDAMENTAL), flags.contains(StructFlags::IS_PHANTOM_DATA)) - } - // FIXME set fundamental flags correctly - hir_def::AdtId::UnionId(_) => (false, false), - hir_def::AdtId::EnumId(_) => (false, false), - }; - let flags = rust_ir::AdtFlags { - upstream: adt_id.module(db).krate() != krate, - fundamental, - phantom_data, - }; - - // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it - let _variant_id_to_fields = |id: VariantId| { - let variant_data = &id.fields(db); - let fields = if variant_data.fields().is_empty() { - vec![] - } else { - let field_types = db.field_types(id); - variant_data - .fields() - .iter() - .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst)) - .filter(|it| !it.contains_unknown()) - .collect() - }; - rust_ir::AdtVariantDatum { fields } - }; - let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] }; - - let (kind, variants) = match adt_id { - hir_def::AdtId::StructId(id) => { - (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())]) - } - hir_def::AdtId::EnumId(id) => { - let variants = id - .enum_variants(db) - .variants - .iter() - .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) - .collect(); - (rust_ir::AdtKind::Enum, variants) - } - hir_def::AdtId::UnionId(id) => { - (rust_ir::AdtKind::Union, vec![variant_id_to_fields(id.into())]) - } - }; - - let struct_datum_bound = rust_ir::AdtDatumBound { variants, where_clauses }; - let struct_datum = AdtDatum { - kind, - id: chalk_ir::AdtId(adt_id), - binders: make_binders(db, &generic_params, struct_datum_bound), - flags, - }; - Arc::new(struct_datum) -} - -pub(crate) fn impl_datum_query( - db: &dyn HirDatabase, - krate: Crate, - impl_id: ImplId, -) -> Arc { - let _p = tracing::info_span!("impl_datum_query").entered(); - debug!("impl_datum {:?}", impl_id); - let impl_: hir_def::ImplId = from_chalk(db, impl_id); - impl_def_datum(db, krate, impl_) -} - -fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) -> Arc { - let trait_ref = db - .impl_trait(impl_id) - // ImplIds for impls where the trait ref can't be resolved should never reach Chalk - .expect("invalid impl passed to Chalk") - .into_value_and_skipped_binders() - .0; - let impl_data = db.impl_signature(impl_id); - - let generic_params = generics(db, impl_id.into()); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let trait_ = trait_ref.hir_trait_id(); - let impl_type = if impl_id.lookup(db).container.krate() == krate { - rust_ir::ImplType::Local - } else { - rust_ir::ImplType::External - }; - let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); - let negative = impl_data.flags.contains(ImplFlags::NEGATIVE); - let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; - - let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; - let trait_data = trait_.trait_items(db); - let associated_ty_value_ids = impl_id - .impl_items(db) - .items - .iter() - .filter_map(|(_, item)| match item { - AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), - _ => None, - }) - .filter(|&type_alias| { - // don't include associated types that don't exist in the trait - let name = &db.type_alias_signature(type_alias).name; - trait_data.associated_type_by_name(name).is_some() - }) - .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db)) - .collect(); - debug!("impl_datum: {:?}", impl_datum_bound); - let impl_datum = ImplDatum { - binders: make_binders(db, &generic_params, impl_datum_bound), - impl_type, - polarity, - associated_ty_value_ids, - }; - Arc::new(impl_datum) -} - -pub(crate) fn associated_ty_value_query( - db: &dyn HirDatabase, - krate: Crate, - id: AssociatedTyValueId, -) -> Arc { - let type_alias: TypeAliasAsValue = from_chalk(db, id); - type_alias_associated_ty_value(db, krate, type_alias.0) -} - -fn type_alias_associated_ty_value( - db: &dyn HirDatabase, - _krate: Crate, - type_alias: TypeAliasId, -) -> Arc { - let type_alias_data = db.type_alias_signature(type_alias); - let impl_id = match type_alias.lookup(db).container { - ItemContainerId::ImplId(it) => it, - _ => panic!("assoc ty value should be in impl"), - }; - - let trait_ref = db - .impl_trait(impl_id) - .expect("assoc ty value should not exist") - .into_value_and_skipped_binders() - .0; // we don't return any assoc ty values if the impl'd trait can't be resolved - - let assoc_ty = trait_ref - .hir_trait_id() - .trait_items(db) - .associated_type_by_name(&type_alias_data.name) - .expect("assoc ty value should not exist"); // validated when building the impl data as well - let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders(); - let value_bound = rust_ir::AssociatedTyValueBound { ty }; - let value = rust_ir::AssociatedTyValue { - impl_id: impl_id.to_chalk(db), - associated_ty_id: to_assoc_type_id(assoc_ty), - value: chalk_ir::Binders::new(binders, value_bound), - }; - Arc::new(value) -} - -pub(crate) fn fn_def_datum_query( - db: &dyn HirDatabase, - callable_def: CallableDefId, -) -> Arc { - let generic_def = GenericDefId::from_callable(db, callable_def); - let generic_params = generics(db, generic_def); - let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders(); - let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let where_clauses = convert_where_clauses(db, generic_def, &bound_vars); - let bound = rust_ir::FnDefDatumBound { - // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway - inputs_and_output: chalk_ir::Binders::empty( - Interner, - rust_ir::FnDefInputsAndOutputDatum { - argument_types: sig.params().to_vec(), - return_type: sig.ret().clone(), - } - .shifted_in(Interner), - ), - where_clauses, - }; - let datum = FnDefDatum { - id: callable_def.to_chalk(db), - sig: chalk_ir::FnSig { - abi: sig.abi, - safety: chalk_ir::Safety::Safe, - variadic: sig.is_varargs, - }, - binders: chalk_ir::Binders::new(binders, bound), - }; - Arc::new(datum) -} - pub(crate) fn fn_def_variance_query( db: &dyn HirDatabase, callable_def: CallableDefId, @@ -431,59 +66,3 @@ pub(super) fn convert_where_clauses( .map(|pred| pred.substitute(Interner, substs)) .collect() } - -pub(super) fn generic_predicate_to_inline_bound( - db: &dyn HirDatabase, - pred: &QuantifiedWhereClause, - self_ty: &Ty, -) -> Option>> { - // An InlineBound is like a GenericPredicate, except the self type is left out. - // We don't have a special type for this, but Chalk does. - let self_ty_shifted_in = self_ty.clone().shifted_in_from(Interner, DebruijnIndex::ONE); - let (pred, binders) = pred.as_ref().into_value_and_skipped_binders(); - match pred { - WhereClause::Implemented(trait_ref) => { - if trait_ref.self_type_parameter(Interner) != self_ty_shifted_in { - // we can only convert predicates back to type bounds if they - // have the expected self type - return None; - } - let args_no_self = trait_ref.substitution.as_slice(Interner)[1..] - .iter() - .cloned() - .casted(Interner) - .collect(); - let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; - Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) - } - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { - let generics = generics(db, from_assoc_type_id(projection_ty.associated_ty_id).into()); - let parent_len = generics.parent_generics().map_or(0, |g| g.len_self()); - let (trait_args, assoc_args) = - projection_ty.substitution.as_slice(Interner).split_at(parent_len); - let (self_ty, args_no_self) = - trait_args.split_first().expect("projection without trait self type"); - if self_ty.assert_ty_ref(Interner) != &self_ty_shifted_in { - return None; - } - - let args_no_self = args_no_self.iter().cloned().casted(Interner).collect(); - let parameters = assoc_args.to_vec(); - - let alias_eq_bound = rust_ir::AliasEqBound { - value: ty.clone(), - trait_bound: rust_ir::TraitBound { - trait_id: to_chalk_trait_id(projection_ty.trait_(db)), - args_no_self, - }, - associated_ty_id: projection_ty.associated_ty_id, - parameters, - }; - Some(chalk_ir::Binders::new( - binders, - rust_ir::InlineBound::AliasEqBound(alias_eq_bound), - )) - } - _ => None, - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 9affd3b48c587..97754f47233b2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -1,8 +1,6 @@ //! The home of `HirDatabase`, which is the Salsa database containing all the //! type inference-related queries. -use std::sync; - use base_db::Crate; use hir_def::{ AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, @@ -240,26 +238,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::interned] fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId; - #[salsa::invoke(chalk_db::associated_ty_data_query)] - fn associated_ty_data(&self, id: TypeAliasId) -> sync::Arc; - - #[salsa::invoke(chalk_db::trait_datum_query)] - fn trait_datum( - &self, - krate: Crate, - trait_id: chalk_db::TraitId, - ) -> sync::Arc; - - #[salsa::invoke(chalk_db::adt_datum_query)] - fn adt_datum(&self, krate: Crate, struct_id: chalk_db::AdtId) -> sync::Arc; - - #[salsa::invoke(chalk_db::impl_datum_query)] - fn impl_datum(&self, krate: Crate, impl_id: chalk_db::ImplId) - -> sync::Arc; - - #[salsa::invoke(chalk_db::fn_def_datum_query)] - fn fn_def_datum(&self, fn_def_id: CallableDefId) -> sync::Arc; - #[salsa::invoke(chalk_db::fn_def_variance_query)] fn fn_def_variance(&self, fn_def_id: CallableDefId) -> chalk_db::Variances; @@ -274,13 +252,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { )] fn variances_of(&self, def: GenericDefId) -> Option>; - #[salsa::invoke(chalk_db::associated_ty_value_query)] - fn associated_ty_value( - &self, - krate: Crate, - id: chalk_db::AssociatedTyValueId, - ) -> sync::Arc; - #[salsa::invoke(crate::traits::normalize_projection_query)] #[salsa::transparent] fn normalize_projection( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index b26bd2b8fa9c4..403ea05a4f53c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -5,7 +5,6 @@ use std::fmt; use base_db::Crate; -use chalk_solve::rust_ir::AdtKind; use either::Either; use hir_def::{ AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup, @@ -300,11 +299,7 @@ impl ExprValidator { value_or_partial.is_none_or(|v| !matches!(v, ValueNs::StaticId(_))) } Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) { - TyKind::Adt(adt, ..) - if db.adt_datum(self.owner.krate(db), *adt).kind == AdtKind::Union => - { - false - } + TyKind::Adt(adt, ..) if matches!(adt.0, AdtId::UnionId(_)) => false, _ => self.is_known_valid_scrutinee(*expr, db), }, Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index f0a4167f8e250..09b983a580d97 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -1,12 +1,12 @@ //! Type cast logic. Basically coercion + additional casts. use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy}; -use hir_def::{AdtId, hir::ExprId}; +use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags}; use stdx::never; use crate::{ Adjustment, Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, - QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, + QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause, from_chalk_trait_id, infer::{coerce::CoerceNever, unify::InferenceTable}, }; @@ -290,10 +290,12 @@ impl CastCheck { return Ok(()); } let src_principal = - table.db.trait_datum(table.trait_env.krate, src_principal); + table.db.trait_signature(from_chalk_trait_id(src_principal)); let dst_principal = - table.db.trait_datum(table.trait_env.krate, dst_principal); - if src_principal.is_auto_trait() && dst_principal.is_auto_trait() { + table.db.trait_signature(from_chalk_trait_id(dst_principal)); + if src_principal.flags.contains(TraitFlags::AUTO) + && dst_principal.flags.contains(TraitFlags::AUTO) + { Ok(()) } else { Err(CastError::DifferingKinds) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index d8fc20e8741cd..38ac2e1170773 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -9,7 +9,6 @@ use chalk_ir::{ visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, }; use either::Either; -use hir_def::Lookup; use hir_def::{ DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, expr_store::path::Path, @@ -22,6 +21,7 @@ use hir_def::{ resolver::ValueNs, type_ref::TypeRefId, }; +use hir_def::{ItemContainerId, Lookup, TraitId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; @@ -30,16 +30,16 @@ use stdx::{format_to, never}; use syntax::utils::is_raw_identifier; use crate::{ - Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, - DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTy, ProjectionTyExt, - Substitution, Ty, TyBuilder, TyExt, WhereClause, + Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ClosureId, DynTy, DynTyExt, FnAbi, + FnPointer, FnSig, Interner, OpaqueTy, ProjectionTy, ProjectionTyExt, Substitution, Ty, + TyBuilder, TyExt, WhereClause, db::{HirDatabase, InternedClosure, InternedCoroutine}, error_lifetime, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx, generics::Generics, infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever}, make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, - to_assoc_type_id, to_chalk_trait_id, + to_assoc_type_id, traits::FnTrait, utils::{self, elaborate_clause_supertraits}, }; @@ -321,10 +321,8 @@ impl InferenceContext<'_> { fn deduce_sig_from_dyn_ty(&self, dyn_ty: &DynTy) -> Option { // Search for a predicate like `<$self as FnX>::Output == Ret` - let fn_traits: SmallVec<[ChalkTraitId; 3]> = - utils::fn_traits(self.db, self.owner.module(self.db).krate()) - .map(to_chalk_trait_id) - .collect(); + let fn_traits: SmallVec<[TraitId; 3]> = + utils::fn_traits(self.db, self.owner.module(self.db).krate()).collect(); let self_ty = self.result.standard_types.unknown.clone(); let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]); @@ -333,9 +331,13 @@ impl InferenceContext<'_> { if let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) = bound.skip_binders() { - let assoc_data = - self.db.associated_ty_data(from_assoc_type_id(projection.associated_ty_id)); - if !fn_traits.contains(&assoc_data.trait_id) { + let trait_ = + match from_assoc_type_id(projection.associated_ty_id).lookup(self.db).container + { + ItemContainerId::TraitId(t) => t, + _ => panic!("associated type not in trait"), + }; + if !fn_traits.contains(&trait_) { return None; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs index 9d3d2044c43e4..448fbdf673655 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs @@ -3,8 +3,6 @@ //! Chalk (in both directions); plus some helper functions for more specialized //! conversions. -use chalk_solve::rust_ir; - use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId}; use salsa::{ Id, @@ -54,23 +52,6 @@ impl ToChalk for CallableDefId { } } -pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId); - -impl ToChalk for TypeAliasAsValue { - type Chalk = chalk_db::AssociatedTyValueId; - - fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::AssociatedTyValueId { - rust_ir::AssociatedTyValueId(self.0.as_id()) - } - - fn from_chalk( - _db: &dyn HirDatabase, - assoc_ty_value_id: chalk_db::AssociatedTyValueId, - ) -> TypeAliasAsValue { - TypeAliasAsValue(TypeAliasId::from_id(assoc_ty_value_id.0)) - } -} - impl From for crate::db::InternedOpaqueTyId { fn from(id: OpaqueTyId) -> Self { FromId::from_id(id.0) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ff7d116dcce3e..f03f542e5bce3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -66,7 +66,7 @@ use hir_def::{ }, per_ns::PerNs, resolver::{HasResolver, Resolver}, - signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, + signatures::{ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, src::HasSource as _, visibility::visibility_from_ast, }; @@ -4945,42 +4945,79 @@ impl<'db> Type<'db> { } pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { - return go(db, self.env.krate, &self.ty); + return go(db, &self.ty); - fn go(db: &dyn HirDatabase, krate: base_db::Crate, ty: &Ty) -> bool { + fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { + match adt_id { + hir_def::AdtId::StructId(s) => { + let flags = db.struct_signature(s).flags; + flags.contains(StructFlags::IS_PHANTOM_DATA) + } + hir_def::AdtId::UnionId(_) => false, + hir_def::AdtId::EnumId(_) => false, + } + } + + fn go(db: &dyn HirDatabase, ty: &Ty) -> bool { match ty.kind(Interner) { // Reference itself TyKind::Ref(_, _, _) => true, // For non-phantom_data adts we check variants/fields as well as generic parameters - TyKind::Adt(adt_id, substitution) - if !db.adt_datum(krate, *adt_id).flags.phantom_data => - { - let adt_datum = &db.adt_datum(krate, *adt_id); - let adt_datum_bound = - adt_datum.binders.clone().substitute(Interner, substitution); - adt_datum_bound - .variants + TyKind::Adt(adt_id, substitution) if !is_phantom_data(db, adt_id.0) => { + let _variant_id_to_fields = |id: VariantId| { + let variant_data = &id.fields(db); + if variant_data.fields().is_empty() { + vec![] + } else { + let field_types = db.field_types(id); + variant_data + .fields() + .iter() + .map(|(idx, _)| { + field_types[idx].clone().substitute(Interner, substitution) + }) + .filter(|it| !it.contains_unknown()) + .collect() + } + }; + let variant_id_to_fields = |_: VariantId| vec![]; + + let variants = match adt_id.0 { + hir_def::AdtId::StructId(id) => { + vec![variant_id_to_fields(id.into())] + } + hir_def::AdtId::EnumId(id) => id + .enum_variants(db) + .variants + .iter() + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) + .collect(), + hir_def::AdtId::UnionId(id) => { + vec![variant_id_to_fields(id.into())] + } + }; + + variants .into_iter() - .flat_map(|variant| variant.fields.into_iter()) - .any(|ty| go(db, krate, &ty)) + .flat_map(|variant| variant.into_iter()) + .any(|ty| go(db, &ty)) || substitution .iter(Interner) .filter_map(|x| x.ty(Interner)) - .any(|ty| go(db, krate, ty)) + .any(|ty| go(db, ty)) } // And for `PhantomData`, we check `T`. TyKind::Adt(_, substitution) | TyKind::Tuple(_, substitution) | TyKind::OpaqueType(_, substitution) | TyKind::AssociatedType(_, substitution) - | TyKind::FnDef(_, substitution) => substitution - .iter(Interner) - .filter_map(|x| x.ty(Interner)) - .any(|ty| go(db, krate, ty)), + | TyKind::FnDef(_, substitution) => { + substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty)) + } // For `[T]` or `*T` we check `T` - TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, krate, ty), + TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, ty), // Consider everything else as not reference _ => false, From 5c893461719c3d4da1201a0080b60f1ca95c5c88 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 04:36:53 +0000 Subject: [PATCH 074/251] Add new_empty_tuple --- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 9deaa4ac5a6b5..c60ace85be124 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -25,7 +25,7 @@ use rustc_apfloat::{ ieee::{Half as f16, Quad as f128}, }; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use span::FileId; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; @@ -1815,7 +1815,7 @@ impl<'db> Evaluator<'db> { let i = self.const_eval_discriminant(it)?; return Ok(( 16, - self.layout(crate::next_solver::Ty::new_tup(interner, &[]))?, + self.layout(crate::next_solver::Ty::new_empty_tuple(interner))?, Some((0, 16, i)), )); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 0c0fe686b77d1..5ffae981a6094 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -9,6 +9,7 @@ use rustc_type_ir::{ WithCachedTypeInfo, inherent::{ AdtDef, BoundVarLike, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, SliceLike, + Ty as _, }, relate::Relate, solve::SizedTraitKind, @@ -107,6 +108,10 @@ impl<'db> Ty<'db> { Ty::new_infer(interner, InferTy::FreshFloatTy(n)) } + pub fn new_empty_tuple(interner: DbInterner<'db>) -> Self { + Ty::new_tup(interner, &[]) + } + /// Returns the `Size` for primitive types (bool, uint, int, char, float). pub fn primitive_size(self, interner: DbInterner<'db>) -> Size { match self.kind() { From 0e2b63cd875e0496b3a2da237282e02333b632ee Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 04:38:50 +0000 Subject: [PATCH 075/251] Update fixme --- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2f8eb627462b7..7fdfb205721ec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -292,7 +292,7 @@ impl<'db> MemoryMap<'db> { } } -// FIXME(next-solver): +// FIXME(next-solver): add a lifetime to this /// A concrete constant value #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstScalar { From 3e41e85b2761bbe21169e7dd72cb959fb63a31fa Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 04:41:23 +0000 Subject: [PATCH 076/251] Add fixme to associated_ty_item_bounds --- src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 2777869bd48e5..99411e4ab138c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1594,6 +1594,7 @@ fn fn_sig_for_enum_variant_constructor<'db>( })) } +// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way pub(crate) fn associated_ty_item_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, From 058a398f9fd11783aa62691bfb4b029c1a3d313c Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 04:50:21 +0000 Subject: [PATCH 077/251] Add FIXME in named_associated_type_shorthand_candidates --- src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 99411e4ab138c..7a2bd37bce6d4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1782,6 +1782,9 @@ fn named_associated_type_shorthand_candidates<'db, R>( TypeNs::SelfType(impl_id) => { let trait_ref = db.impl_trait_ns(impl_id)?; + // FIXME(next-solver): same method in `lower` checks for impl or not + // Is that needed here? + // we're _in_ the impl -- the binders get added back later. Correct, // but it would be nice to make this more explicit search(trait_ref.skip_binder()) From 3486a2c3e735d51750e1127607eefcf0496a4d00 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 04:52:12 +0000 Subject: [PATCH 078/251] Remove fixme comment --- src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 7a2bd37bce6d4..ce953fdcb8298 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1793,7 +1793,6 @@ fn named_associated_type_shorthand_candidates<'db, R>( // Handle `Self::Type` referring to own associated type in trait definitions // This *must* be done first to avoid cycles with // `generic_predicates_for_param`, but not sure that it's sufficient, - // see FIXME in `search`. if let GenericDefId::TraitId(trait_id) = param_id.parent() { let trait_name = &db.trait_signature(trait_id).name; tracing::debug!(?trait_name); From b9d225b6d8dff5eaccf8bac4ab969ab1fe98ea6d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 16 Aug 2025 16:26:30 +0200 Subject: [PATCH 079/251] Auto-attach database in `Analysis` calls --- .../hir-ty/src/next_solver/generic_arg.rs | 2 +- .../crates/ide-assists/src/lib.rs | 9 +-- .../crates/ide-assists/src/tests.rs | 17 ++++- .../crates/ide-completion/src/lib.rs | 5 +- .../crates/ide-completion/src/tests.rs | 6 +- .../crates/ide-diagnostics/src/lib.rs | 12 ++- .../crates/ide-diagnostics/src/tests.rs | 75 ++++++++++++------- .../crates/ide/src/goto_definition.rs | 4 +- .../rust-analyzer/crates/ide/src/hover.rs | 43 +++++------ .../crates/ide/src/hover/render.rs | 5 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 57 +++++++++----- .../crates/parser/src/lexed_str.rs | 3 +- 12 files changed, 137 insertions(+), 101 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 834f4e3765ee8..76186e374608e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -46,7 +46,7 @@ impl<'db> GenericArg<'db> { pub fn expect_ty(self) -> Ty<'db> { match self.kind() { GenericArgKind::Type(ty) => ty, - _ => panic!("Expected ty, got {:?}", self), + _ => panic!("Expected ty, got {self:?}"), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 5008f97447b76..4682c04732389 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -67,7 +67,7 @@ mod tests; pub mod utils; use hir::Semantics; -use ide_db::{EditionedFileId, RootDatabase, base_db::salsa}; +use ide_db::{EditionedFileId, RootDatabase}; use syntax::{Edition, TextRange}; pub(crate) use crate::assist_context::{AssistContext, Assists}; @@ -93,11 +93,8 @@ pub fn assists( .unwrap_or_else(|| EditionedFileId::new(db, range.file_id, Edition::CURRENT)); let ctx = AssistContext::new(sema, config, hir::FileRange { file_id, range: range.range }); let mut acc = Assists::new(&ctx, resolve); - // the handlers may invoke trait solving related things which accesses salsa structs outside queries - salsa::attach(db, || { - handlers::all().iter().for_each(|handler| { - handler(&mut acc, &ctx); - }); + handlers::all().iter().for_each(|handler| { + handler(&mut acc, &ctx); }); acc.finish() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index f4daabfe915d7..c7c322a15e541 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -1,7 +1,7 @@ mod generated; use expect_test::expect; -use hir::{Semantics, setup_tracing}; +use hir::{Semantics, db::HirDatabase, setup_tracing}; use ide_db::{ EditionedFileId, FileRange, RootDatabase, SnippetCap, assists::ExprFillDefaultMode, @@ -16,7 +16,7 @@ use test_utils::{assert_eq_text, extract_offset}; use crate::{ Assist, AssistConfig, AssistContext, AssistKind, AssistResolveStrategy, Assists, SingleResolve, - assists, handlers::Handler, + handlers::Handler, }; pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { @@ -103,6 +103,18 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { prefer_self_ty: false, }; +fn assists( + db: &RootDatabase, + config: &AssistConfig, + resolve: AssistResolveStrategy, + range: ide_db::FileRange, +) -> Vec { + salsa::attach(db, || { + HirDatabase::zalsa_register_downcaster(db); + crate::assists(db, config, resolve, range) + }) +} + pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) { RootDatabase::with_single_file(text) } @@ -320,6 +332,7 @@ fn check_with_config( }; let mut acc = Assists::new(&ctx, resolve); salsa::attach(&db, || { + HirDatabase::zalsa_register_downcaster(&db); handler(&mut acc, &ctx); }); let mut res = acc.finish(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 1a4c97e70b4ae..a70a1138d2f42 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -10,7 +10,6 @@ mod snippet; #[cfg(test)] mod tests; -use base_db::salsa; use ide_db::{ FilePosition, FxHashSet, RootDatabase, imports::insert_use::{self, ImportScope}, @@ -229,7 +228,7 @@ pub fn completions( { let acc = &mut completions; - salsa::attach(db, || match analysis { + match analysis { CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx), CompletionAnalysis::NameRef(name_ref_ctx) => { completions::complete_name_ref(acc, ctx, name_ref_ctx) @@ -257,7 +256,7 @@ pub fn completions( ); } CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (), - }) + } } Some(completions.into()) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 4b3b271ca20ef..809a26bf5de47 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -24,7 +24,7 @@ mod type_pos; mod use_tree; mod visibility; -use base_db::SourceDatabase; +use base_db::{SourceDatabase, salsa}; use expect_test::Expect; use hir::{PrefixKind, setup_tracing}; use ide_db::{ @@ -243,7 +243,7 @@ pub(crate) fn check_edit_with_config( let ra_fixture_after = trim_indent(ra_fixture_after); let (db, position) = position(ra_fixture_before); let completions: Vec = - crate::completions(&db, &config, position, None).unwrap(); + salsa::attach(&db, || crate::completions(&db, &config, position, None).unwrap()); let (completion,) = completions .iter() .filter(|it| it.lookup() == what) @@ -306,7 +306,7 @@ pub(crate) fn get_all_items( trigger_character: Option, ) -> Vec { let (db, position) = position(code); - let res = crate::completions(&db, &config, position, trigger_character) + let res = salsa::attach(&db, || crate::completions(&db, &config, position, trigger_character)) .map_or_else(Vec::default, Into::into); // validate res.iter().for_each(|it| { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index a4eb3d47d708b..a1db92641f5ee 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -92,7 +92,7 @@ use hir::{ use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode}, - base_db::{ReleaseChannel, RootQueryDb as _, salsa}, + base_db::{ReleaseChannel, RootQueryDb as _}, generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup}, imports::insert_use::InsertUseConfig, label::Label, @@ -537,12 +537,10 @@ pub fn full_diagnostics( resolve: &AssistResolveStrategy, file_id: FileId, ) -> Vec { - salsa::attach(db, || { - let mut res = syntax_diagnostics(db, config, file_id); - let sema = semantic_diagnostics(db, config, resolve, file_id); - res.extend(sema); - res - }) + let mut res = syntax_diagnostics(db, config, file_id); + let sema = semantic_diagnostics(db, config, resolve, file_id); + res.extend(sema); + res } /// Returns whether to keep this diagnostic (or remove it). diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index c3cc5a08b56b5..1839ab1c58c1e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -6,7 +6,7 @@ use hir::setup_tracing; use ide_db::{ LineIndexDatabase, RootDatabase, assists::{AssistResolveStrategy, ExprFillDefaultMode}, - base_db::SourceDatabase, + base_db::{SourceDatabase, salsa}, }; use itertools::Itertools; use stdx::trim_indent; @@ -74,14 +74,16 @@ fn check_nth_fix_with_config( let after = trim_indent(ra_fixture_after); let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let diagnostic = super::full_diagnostics( - &db, - &config, - &AssistResolveStrategy::All, - file_position.file_id.file_id(&db), - ) - .pop() - .expect("no diagnostics"); + let diagnostic = salsa::attach(&db, || { + super::full_diagnostics( + &db, + &config, + &AssistResolveStrategy::All, + file_position.file_id.file_id(&db), + ) + .pop() + .expect("no diagnostics") + }); let fix = &diagnostic .fixes .unwrap_or_else(|| panic!("{:?} diagnostic misses fixes", diagnostic.code))[nth]; @@ -127,12 +129,14 @@ pub(crate) fn check_has_fix( let (db, file_position) = RootDatabase::with_position(ra_fixture_before); let mut conf = DiagnosticsConfig::test_sample(); conf.expr_fill_default = ExprFillDefaultMode::Default; - let fix = super::full_diagnostics( - &db, - &conf, - &AssistResolveStrategy::All, - file_position.file_id.file_id(&db), - ) + let fix = salsa::attach(&db, || { + super::full_diagnostics( + &db, + &conf, + &AssistResolveStrategy::All, + file_position.file_id.file_id(&db), + ) + }) .into_iter() .find(|d| { d.fixes @@ -166,12 +170,14 @@ pub(crate) fn check_has_fix( /// Checks that there's a diagnostic *without* fix at `$0`. pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); - let diagnostic = super::full_diagnostics( - &db, - &DiagnosticsConfig::test_sample(), - &AssistResolveStrategy::All, - file_position.file_id.file_id(&db), - ) + let diagnostic = salsa::attach(&db, || { + super::full_diagnostics( + &db, + &DiagnosticsConfig::test_sample(), + &AssistResolveStrategy::All, + file_position.file_id.file_id(&db), + ) + }) .pop() .unwrap(); assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {diagnostic:?}"); @@ -206,7 +212,13 @@ pub(crate) fn check_diagnostics_with_config( .iter() .copied() .flat_map(|file_id| { - super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id.file_id(&db)) + salsa::attach(&db, || { + super::full_diagnostics( + &db, + &config, + &AssistResolveStrategy::All, + file_id.file_id(&db), + ) .into_iter() .map(|d| { let mut annotation = String::new(); @@ -224,6 +236,7 @@ pub(crate) fn check_diagnostics_with_config( annotation.push_str(&d.message); (d.range, annotation) }) + }) }) .map(|(diagnostic, annotation)| (diagnostic.file_id, (diagnostic.range, annotation))) .into_group_map(); @@ -275,15 +288,19 @@ fn test_disabled_diagnostics() { let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); let file_id = file_id.file_id(&db); - let diagnostics = super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); + let diagnostics = salsa::attach(&db, || { + super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id) + }); assert!(diagnostics.is_empty()); - let diagnostics = super::full_diagnostics( - &db, - &DiagnosticsConfig::test_sample(), - &AssistResolveStrategy::All, - file_id, - ); + let diagnostics = salsa::attach(&db, || { + super::full_diagnostics( + &db, + &DiagnosticsConfig::test_sample(), + &AssistResolveStrategy::All, + file_id, + ) + }); assert!(!diagnostics.is_empty()); } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 633feec622cd9..f768d4b68f469 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -10,7 +10,7 @@ use hir::{ }; use ide_db::{ RootDatabase, SymbolKind, - base_db::{AnchoredPath, SourceDatabase, salsa}, + base_db::{AnchoredPath, SourceDatabase}, defs::{Definition, IdentClass}, famous_defs::FamousDefs, helpers::pick_best_token, @@ -108,7 +108,7 @@ pub(crate) fn goto_definition( } Some( - salsa::attach(sema.db, || IdentClass::classify_node(sema, &parent))? + IdentClass::classify_node(sema, &parent)? .definitions() .into_iter() .flat_map(|(def, _)| { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index b0ef83e0501b3..44c98a43f6944 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -12,7 +12,6 @@ use hir::{ }; use ide_db::{ FileRange, FxIndexSet, Ranker, RootDatabase, - base_db::salsa, defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, @@ -137,20 +136,18 @@ pub(crate) fn hover( let edition = sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT); let display_target = sema.first_crate(file_id)?.to_display_target(db); - let mut res = salsa::attach(sema.db, || { - if range.is_empty() { - hover_offset( - sema, - FilePosition { file_id, offset: range.start() }, - file, - config, - edition, - display_target, - ) - } else { - hover_ranged(sema, frange, file, config, edition, display_target) - } - })?; + let mut res = if range.is_empty() { + hover_offset( + sema, + FilePosition { file_id, offset: range.start() }, + file, + config, + edition, + display_target, + ) + } else { + hover_ranged(sema, frange, file, config, edition, display_target) + }?; if let HoverDocFormat::PlainText = config.format { res.info.markup = remove_markdown(res.info.markup.as_str()).into(); @@ -293,7 +290,7 @@ fn hover_offset( .into_iter() .unique_by(|&((def, _), _, _, _)| def) .map(|((def, subst), macro_arm, hovered_definition, node)| { - salsa::attach(sema.db, || hover_for_definition( + hover_for_definition( sema, file_id, def, @@ -304,7 +301,7 @@ fn hover_offset( config, edition, display_target, - )) + ) }) .collect::>(), ) @@ -583,13 +580,11 @@ fn goto_type_action_for_def( }); } - salsa::attach(db, || { - if let Ok(generic_def) = GenericDef::try_from(def) { - generic_def.type_or_const_params(db).into_iter().for_each(|it| { - walk_and_push_ty(db, &it.ty(db), &mut push_new_def); - }); - } - }); + if let Ok(generic_def) = GenericDef::try_from(def) { + generic_def.type_or_const_params(db).into_iter().for_each(|it| { + walk_and_push_ty(db, &it.ty(db), &mut push_new_def); + }); + } let ty = match def { Definition::Local(it) => Some(it.ty(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 1f9d10c92b1df..290ee80984edc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -10,7 +10,6 @@ use hir::{ }; use ide_db::{ RootDatabase, - base_db::salsa, defs::Definition, documentation::{DocsRangeMap, HasDocs}, famous_defs::FamousDefs, @@ -45,7 +44,7 @@ pub(super) fn type_info_of( Either::Left(expr) => sema.type_of_expr(expr)?, Either::Right(pat) => sema.type_of_pat(pat)?, }; - salsa::attach(sema.db, || type_info(sema, _config, ty_info, edition, display_target)) + type_info(sema, _config, ty_info, edition, display_target) } pub(super) fn closure_expr( @@ -912,7 +911,7 @@ pub(super) fn literal( }; let ty = ty.display(sema.db, display_target); - let mut s = salsa::attach(sema.db, || format!("```rust\n{ty}\n```\n___\n\n")); + let mut s = format!("```rust\n{ty}\n```\n___\n\n"); match value { Ok(value) => { let backtick_len = value.chars().filter(|c| *c == '`').count(); diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index e491c9214b437..874e04702e241 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -62,7 +62,7 @@ use std::panic::{AssertUnwindSafe, UnwindSafe}; use cfg::CfgOptions; use fetch_crates::CrateInfo; -use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym}; +use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, db::HirDatabase, sym}; use ide_db::{ FxHashMap, FxIndexSet, LineIndexDatabase, base_db::{ @@ -478,10 +478,12 @@ impl Analysis { /// Fuzzy searches for a symbol. pub fn symbol_search(&self, query: Query, limit: usize) -> Cancellable> { - self.with_db(|db| { - symbol_index::world_symbols(db, query) - .into_iter() // xx: should we make this a par iter? - .filter_map(|s| s.try_to_nav(db)) + // `world_symbols` currently clones the database to run stuff in parallel, which will make any query panic + // if we were to attach it here. + Cancelled::catch(|| { + symbol_index::world_symbols(&self.db, query) + .into_iter() + .filter_map(|s| s.try_to_nav(&self.db)) .take(limit) .map(UpmappingResult::call_site) .collect::>() @@ -660,15 +662,6 @@ impl Analysis { }) } - /// Computes syntax highlighting for the given file - pub fn highlight( - &self, - highlight_config: HighlightConfig, - file_id: FileId, - ) -> Cancellable> { - self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None)) - } - /// Computes all ranges to highlight for a given item in a file. pub fn highlight_related( &self, @@ -682,20 +675,42 @@ impl Analysis { }) } + /// Computes syntax highlighting for the given file + pub fn highlight( + &self, + highlight_config: HighlightConfig, + file_id: FileId, + ) -> Cancellable> { + // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database + // highlighting instead sets up the attach hook where neceesary for the trait solver + Cancelled::catch(|| { + syntax_highlighting::highlight(&self.db, highlight_config, file_id, None) + }) + } + /// Computes syntax highlighting for the given file range. pub fn highlight_range( &self, highlight_config: HighlightConfig, frange: FileRange, ) -> Cancellable> { - self.with_db(|db| { - syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range)) + // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database + // highlighting instead sets up the attach hook where neceesary for the trait solver + Cancelled::catch(|| { + syntax_highlighting::highlight( + &self.db, + highlight_config, + frange.file_id, + Some(frange.range), + ) }) } /// Computes syntax highlighting for the given file. pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { - self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow)) + // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database + // highlighting instead sets up the attach hook where neceesary for the trait solver + Cancelled::catch(|| syntax_highlighting::highlight_as_html(&self.db, file_id, rainbow)) } /// Computes completions at the given position. @@ -873,8 +888,12 @@ impl Analysis { where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - let snap = self.db.clone(); - Cancelled::catch(|| f(&snap)) + salsa::attach(&self.db, || { + // the trait solver code may invoke `as_view` outside of queries, + // so technically we might run into a panic in salsa if the downcaster has not yet been registered. + HirDatabase::zalsa_register_downcaster(&self.db); + Cancelled::catch(|| f(&self.db)) + }) } } diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index dcf397142cac0..edc3f406a67e8 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -289,8 +289,7 @@ impl<'a> Converter<'a> { let error_msg = if has_unterminated { format!( - "unknown literal prefix `{}` (note: check for unterminated string literal)", - token_text + "unknown literal prefix `{token_text}` (note: check for unterminated string literal)" ) } else { "unknown literal prefix".to_owned() From 8eaa4ad7a4cf371114f9e26a92b41cd3fc25e27e Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 10:31:57 +0200 Subject: [PATCH 080/251] user facing code should use not use `PostAnalysis` --- .../ide-assists/src/handlers/generate_from_impl_for_enum.rs | 2 +- .../src/handlers/generate_single_field_struct_from.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index cb83c67c99535..d88b0f34b7969 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -87,7 +87,7 @@ fn existing_from_impl( let from_trait = FamousDefs(sema, krate).core_convert_From()?; let interner = DbInterner::new_with(db, Some(krate.base()), None); use hir::next_solver::infer::DbInternerInferExt; - let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let variant = variant.instantiate_infer(&infcx); let enum_ = variant.parent_enum(sema.db); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index deef4a9aac6db..943795d40d551 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -216,7 +216,7 @@ fn from_impl_exists( let from_trait = FamousDefs(sema, krate).core_convert_From()?; let interner = DbInterner::new_with(db, Some(krate.base()), None); use hir::next_solver::infer::DbInternerInferExt; - let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let strukt = strukt.instantiate_infer(&infcx); let field_ty = strukt.fields(db).get(main_field_i)?.ty(db); From 3141739bad36c517cd2425d06dc35df327ee1b3a Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Tue, 19 Aug 2025 11:41:58 +0200 Subject: [PATCH 081/251] Optimize icon Losslessly optimizes the icon with: ``` oxipng -o max -a -s oxipng -o max --zopfli -a -s ``` --- src/tools/rust-analyzer/editors/code/icon.png | Bin 15341 -> 9761 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/icon.png b/src/tools/rust-analyzer/editors/code/icon.png index 072090c6f4a1fbebc0a2e1ba20d991d5a75d513a..29a9679039010500e7d2b4db1e832f904618081b 100644 GIT binary patch literal 9761 zcmc(EcQl-D*X|Hy5DbYR>O?0<)aZq8$nJ~+8aKp6pp;aS-!D&DuVuz9 z+*0?uJC$=?m#)I38M(39K{-(ykq&+T5JV1K`;7iA`AA2SDrTC@V_5o?KmZjT;u0RI z+}qWaV9Z-DwE@KPXg1-cP^k-?-t>i5MZS*}W~oBdDZ@NwtyqiIXx~47`kn|T0yC6S zjG*oG%oNv7?r~f+M{&GNgpm;aU%Y3^P0PZBNcMaTOFab8`gXfbg=LLhYKUTS|pyM;XHuMzS zfZ=DJ=CaJka?23Gt`W$iVXP<^0ttJ8fZc|J0~i&42psQ!^7ubw1D*dqzSi!coa@PK zkj!MvyGa6k0s;#7Qv&KpI_hi0Y?=4tzCFIHoiCy9PV2-oVYs}wh&7O!NF}YkSM_os zRbN6~U4?($2NUl-kjf<0d;XQ;6ZYI}-DWkQcmJ?wpNvk8g7%du*kER6PB1;&YGc_B z6anIHg2M;>gF(=y*VhoV%+seva!>UY@jg5_N zYnsV<#l`CH$bgYM-Z2NKXCFU)eDMNq_5SQE$VnQ;iWa-&xe^y-#lXN|7Ic_P{Xrn0 zt+lmc3qUi@Dke6(xsQ2F*qbVmb8&C+or~=GLvEk~#Z4)^AnS0d*)hcLc1tT+-I+V^ zU7Vw+VWX%)Bb2c(Evh$^+%rBb?-I&13K)X|CSC`e<^B@%m2Zz`BnYK<&LyH$6 zSLf#~B~J3p!Xjn-&QJH_2}gxUVdy?0xBYIlsm#;UeJo%2o5W0^B$aoRKunaOq2Zq@ zQ4x{5CUJ`Gk3K9cSUJf;ZhXwoA3fv9uJ_*5?LlISrQ83C&w0zG>6~|^yu6%*grxI< zCH@T~rEX&2+`VlvA))N^gthDZJUkCHc6y{XZFlfs$O;n+i<~o~ZM+5fjNr3coKF*J zGX8s;y*>3)&I|I10w(=9%cY{*cCsyYgD}|s9qK)o7lbg>U3kmnWNJ`)QA>k)cjb35VECbBQAtqi;^K#kWqLhv@$sTEGR5jJ;Aw!Tr)O`v$Qwc4HePOSpOb^n zVt4?@orR?(kT@&nzh}NYpHX}e&dbj~6b1u`H62# zBqOAvqSDz>Vp9JB5BR9Te51}-fMz~bO&JtX{MV^EPqhoc#i`+8U32rSqLNAH{pm)3 zvtyT^b93vGjRFj}cQeGq#OB2xP>A2Ul@Da3up!{mQ$&YJ!-g8W3-j~&zhj9?i;BMY z_L?>NJ(OU13&%sChm_#q=JcE99(_DXNOCF{&+07mVGoeHXfuPgrV;vtN25kuhe%->efxQ2C; zZ2{AXPen!L_M)$7><>&HPGSz|VRBDMM5Lmkf;~_5Sq?ua+~OLJJPgK+0UriOA_Go$ zM;NYNO`mGq{ynS6hvE)rU667Bse`ii#2(uND#$v%UkTWR`B9B!QvdfV3dx z+OOzH%ROq@z+znPz@wREI>}JDpBmUI3JcYULuJrh8mWDd5m_c><>k+FX4gq)xiSK> z0bJCmdL?}VEPR}<*#&c|8%~e&LZ$x6oYL=w)J9|+)5oijaTj+&j%{`<^x#sGl2BQr zY|n4`yhHhHPRlScH7jz%q%P;&7TlnUS9TvAk*2= zQ&UrhNwlbp-aMS?g=XZPVh@BBZP#I(&?7g5h27oVwaIo+zuan{mGblB3{X;5CN^tM zrf;sPshLsF!{PAI+nyL7&q6UNCFQDg5AK?wkd>>sxdNHCqR-KvNM#+rLFJ8Q8ZB=q2g!F!DY%~cUe@;xPrKP3wf}N9dx+%~ISm%xhc~V*Va8n-=GCMdJ zM+6&Hr9v@KYFrl-Tumc^@?f&kVI)U6S_HBOg#!c>^IbR&L44=}0TfL*WDo)pgZ$rJ zY9xQ2%_lk?{8+75g;$i$ufKeC&}?s zUEMh7Gdeo+UiH<7BWW2K!KX*Nhljr8fI6Nct`S(8j|>fYZcNsq(P+>!c4LhNMgU!q zk&;@j*OZlIgUUzcr(KZE*!)T9kgwwY7*x`Fq;BlOKc23U3_&83W)6?AC+?ioI zhL)C=sOV@17*K!h`|!vJHt5*NDg>mLfPjEK?$i}(A+65?qB$Lw8c73Ef z?*b!*e%$|i#w{qQNAxzTXtI+W3MLtrqP4A!?|H|SbO1j{d0<#}eZ3KV>Bo<+?jRw* zuP2x3=<0rmOiW0qYG^2efPT@JlAP?jUO5tX>EgwUwm7>hg3eF97ZBSXIzSOJ_`0