From c1fdd6e7a25f0ae7f23184857a69e7db7b822800 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 9 May 2025 21:17:32 +0800 Subject: [PATCH 01/59] feat: code actions, generate blanket trait impl --- .../handlers/generate_blanket_trait_impl.rs | 1244 +++++++++++++++++ .../crates/ide-assists/src/lib.rs | 2 + .../crates/ide-assists/src/tests/generated.rs | 40 + 3 files changed, 1286 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs new file mode 100644 index 0000000000000..3100809fc62ff --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -0,0 +1,1244 @@ +use crate::{ + AssistConfig, + assist_context::{AssistContext, Assists}, + utils::add_cfg_attrs_to, +}; +use ide_db::assists::{AssistId, AssistKind, ExprFillDefaultMode}; +use syntax::{ + AstNode, + ast::{ + self, AssocItem, BlockExpr, GenericParam, HasGenericParams, HasName, HasTypeBounds, + HasVisibility as astHasVisibility, + edit_in_place::{AttrsOwnerEdit, Indent}, + make, + }, +}; + +// Assist: generate_blanket_trait_impl +// +// Generate blanket trait implementation. +// +// ``` +// trait $0Foo: ToOwned +// where +// Self::Owned: Default, +// { +// fn foo(&self) -> T; +// +// fn print_foo(&self) { +// println!("{}", self.foo()); +// } +// } +// ``` +// -> +// ``` +// trait Foo: ToOwned +// where +// Self::Owned: Default, +// { +// fn foo(&self) -> T; +// +// fn print_foo(&self) { +// println!("{}", self.foo()); +// } +// } +// +// $0impl Foo for This +// where +// Self::Owned: Default, +// { +// fn foo(&self) -> T { +// todo!() +// } +// } +// ``` +pub(crate) fn generate_blanket_trait_impl( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let name = ctx.find_node_at_offset::()?; + let traitd = ast::Trait::cast(name.syntax().parent()?)?; + + acc.add( + AssistId("generate_blanket_trait_impl", AssistKind::Generate, None), + "Generate blanket trait implementation", + name.syntax().text_range(), + |builder| { + let namety = make::ty_path(make::path_from_text(&name.text())); + let trait_where_clause = traitd.where_clause().map(|it| it.clone_for_update()); + let bounds = traitd.type_bound_list(); + let is_unsafe = traitd.unsafe_token().is_some(); + let thisname = make::name("This"); + let thisty = make::ty_path(make::path_from_text(&thisname.text())); + let indent = traitd.indent_level(); + + let gendecl = make::generic_param_list([GenericParam::TypeParam(make::type_param( + thisname.clone(), + bounds, + ))]); + + let trait_gen_args = + traitd.generic_param_list().map(|param_list| param_list.to_generic_args()); + + if let Some(ref where_clause) = trait_where_clause { + where_clause.reindent_to(0.into()); + } + + let impl_ = make::impl_trait( + is_unsafe, + traitd.generic_param_list(), + trait_gen_args, + Some(gendecl), + None, + false, + namety, + thisty.clone(), + trait_where_clause, + None, + None, + ) + .clone_for_update(); + + if let Some(trait_assoc_list) = traitd.assoc_item_list() { + let assoc_item_list = impl_.get_or_create_assoc_item_list(); + for method in trait_assoc_list.assoc_items() { + let AssocItem::Fn(method) = method else { + continue; + }; + if method.body().is_some() { + continue; + } + let f = todo_fn(&method, ctx.config).clone_for_update(); + f.remove_attrs_and_docs(); + add_cfg_attrs_to(&method, &f); + f.indent(1.into()); + assoc_item_list.add_item(AssocItem::Fn(f)); + } + } + + add_cfg_attrs_to(&traitd, &impl_); + + impl_.reindent_to(indent); + + // FIXME: $0 after the cfg attributes + builder.insert(traitd.syntax().text_range().end(), format!("\n\n{indent}$0{impl_}")); + }, + ); + + Some(()) +} + +fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { + let params = f.param_list().unwrap_or_else(|| make::param_list(None, None)); + make::fn_( + f.visibility(), + f.name().unwrap_or_else(|| make::name("unnamed")), + f.generic_param_list(), + f.where_clause(), + params, + default_block(config), + f.ret_type(), + f.async_token().is_some(), + f.const_token().is_some(), + f.unsafe_token().is_some(), + f.gen_token().is_some(), + ) +} + +fn default_block(config: &AssistConfig) -> BlockExpr { + let expr = match config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; + make::block_expr(None, Some(expr)) +} + +#[cfg(test)] +mod test { + + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn test_gen_blanket_works() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: ToOwned +where + Self::Owned: Default, +{ + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This +where + Self::Owned: Default, +{ + fn foo(&self) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_indent() { + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + trait $0Foo: ToOwned + where + Self::Owned: Default, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } +} + "#, + r#" +mod foo { + trait Foo: ToOwned + where + Self::Owned: Default, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0impl Foo for This + where + Self::Owned: Default, + { + fn foo(&self) -> T { + todo!() + } + } +} + "#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + trait $0Foo: ToOwned + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } +} + "#, + r#" +mod foo { + trait Foo: ToOwned + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0impl Foo for This + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T { + todo!() + } + } +} + "#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + mod bar { + trait $0Foo: ToOwned + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + } +} + "#, + r#" +mod foo { + mod bar { + trait Foo: ToOwned + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0impl Foo for This + where + Self::Owned: Default, + Self: Send, + { + fn foo(&self) -> T { + todo!() + } + } + } +} + "#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + trait $0Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } +} + "#, + r#" +mod foo { + trait Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0impl Foo for This { + fn foo(&self) -> T { + todo!() + } + } +} + "#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + mod bar { + trait $0Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + } +} + "#, + r#" +mod foo { + mod bar { + trait Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0impl Foo for This { + fn foo(&self) -> T { + todo!() + } + } + } +} + "#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +mod foo { + mod bar { + #[cfg(test)] + trait $0Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + } +} + "#, + r#" +mod foo { + mod bar { + #[cfg(test)] + trait Foo { + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } + } + + $0#[cfg(test)] + impl Foo for This { + fn foo(&self) -> T { + todo!() + } + } + } +} + "#, + ); + } + + #[test] + fn test_gen_blanket_remove_attribute() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: ToOwned +where + Self::Owned: Default, +{ + #[doc(hidden)] + fn foo(&self) -> T; + + /// foo + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + #[doc(hidden)] + fn foo(&self) -> T; + + /// foo + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This +where + Self::Owned: Default, +{ + fn foo(&self) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_not_gen_type_alias() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: ToOwned +where + Self::Owned: Default, +{ + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This +where + Self::Owned: Default, +{ + fn foo(&self, x: Self::X) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_no_quick_bound() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where + Self: ToOwned, + Self::Owned: Default, +{ + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo +where + Self: ToOwned, + Self::Owned: Default, +{ + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This +where + Self: ToOwned, + Self::Owned: Default, +{ + fn foo(&self, x: Self::X) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_no_where_clause() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo { + type X: Sync; + + fn foo(&self, x: Self::X) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This { + fn foo(&self, x: Self::X) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_basic() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + type X: Sync; + + fn foo(&self, x: Self::X) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +trait Foo { + type X: Sync; + + fn foo(&self, x: Self::X) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This { + fn foo(&self, x: Self::X) -> i32 { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_cfg_attrs() { + check_assist( + generate_blanket_trait_impl, + r#" +#[cfg(test)] +trait $0Foo { + fn foo(&self, x: i32) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +#[cfg(test)] +trait Foo { + fn foo(&self, x: i32) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0#[cfg(test)] +impl Foo for This { + fn foo(&self, x: i32) -> i32 { + todo!() + } +} +"#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +#[cfg(test)] +trait $0Foo { + /// ... + #[cfg(test)] + fn foo(&self, x: i32) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + r#" +#[cfg(test)] +trait Foo { + /// ... + #[cfg(test)] + fn foo(&self, x: i32) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0#[cfg(test)] +impl Foo for This { + #[cfg(test)] + fn foo(&self, x: i32) -> i32 { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo {} +"#, + r#" +trait Foo {} + +$0impl Foo for This {} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_quick_bounds() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Copy {} +"#, + r#" +trait Foo: Copy {} + +$0impl Foo for This {} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_where_clause() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo where Self: Copy {} +"#, + r#" +trait Foo where Self: Copy {} + +$0impl Foo for This +where Self: Copy +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_where_clause_comma() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo where Self: Copy, {} +"#, + r#" +trait Foo where Self: Copy, {} + +$0impl Foo for This +where Self: Copy, +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_where_clause_newline() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where Self: Copy +{} +"#, + r#" +trait Foo +where Self: Copy +{} + +$0impl Foo for This +where Self: Copy +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_where_clause_newline_newline() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where + Self: Copy +{} +"#, + r#" +trait Foo +where + Self: Copy +{} + +$0impl Foo for This +where + Self: Copy +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_where_clause_newline_newline_comma() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where + Self: Copy, +{} +"#, + r#" +trait Foo +where + Self: Copy, +{} + +$0impl Foo for This +where + Self: Copy, +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_multiple_where_clause() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where + Self: Copy, + (): Into, +{} +"#, + r#" +trait Foo +where + Self: Copy, + (): Into, +{} + +$0impl Foo for This +where + Self: Copy, + (): Into, +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_trait_with_multiple_bounds_where_clause() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo +where + Self: Copy + Sync, + (): Into, +{} +"#, + r#" +trait Foo +where + Self: Copy + Sync, + (): Into, +{} + +$0impl Foo for This +where + Self: Copy + Sync, + (): Into, +{ +} +"#, + ); + } + + #[test] + fn test_gen_blanket_empty_generate() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self) {} +} +"#, + r#" +trait Foo { + fn foo(&self) {} +} + +$0impl Foo for This {} +"#, + ); + } + + #[test] + fn test_gen_blanket_trait_with_doc() { + check_assist( + generate_blanket_trait_impl, + r#" +/// some docs +trait $0Foo {} +"#, + r#" +/// some docs +trait Foo {} + +$0impl Foo for This {} +"#, + ); + } + + #[test] + fn test_gen_blanket_multiple_method() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self); + fn bar(&self); +} +"#, + r#" +trait Foo { + fn foo(&self); + fn bar(&self); +} + +$0impl Foo for This { + fn foo(&self) { + todo!() + } + + fn bar(&self) { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_generic() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self, value: T) -> T; + fn bar(&self, value: T) -> T { todo!() } +} +"#, + r#" +trait Foo { + fn foo(&self, value: T) -> T; + fn bar(&self, value: T) -> T { todo!() } +} + +$0impl Foo for This { + fn foo(&self, value: T) -> T { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_lifetimes() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo<'a> { + fn foo(&self) -> &'a str; +} +"#, + r#" +trait Foo<'a> { + fn foo(&self) -> &'a str; +} + +$0impl<'a, This> Foo<'a> for This { + fn foo(&self) -> &'a str { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_lifetime_bounds() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo<'a: 'static> { + fn foo(&self) -> &'a str; +} +"#, + r#" +trait Foo<'a: 'static> { + fn foo(&self) -> &'a str; +} + +$0impl<'a: 'static, This> Foo<'a> for This { + fn foo(&self) -> &'a str { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_lifetime_quick_bounds() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo<'a>: 'a { + fn foo(&self) -> &'a str; +} +"#, + r#" +trait Foo<'a>: 'a { + fn foo(&self) -> &'a str; +} + +$0impl<'a, This: 'a> Foo<'a> for This { + fn foo(&self) -> &'a str { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_multiple_lifetimes() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo<'a, 'b> { + fn foo(&self) -> &'a &'b str; +} +"#, + r#" +trait Foo<'a, 'b> { + fn foo(&self) -> &'a &'b str; +} + +$0impl<'a, 'b, This> Foo<'a, 'b> for This { + fn foo(&self) -> &'a &'b str { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_method_with_lifetime_bounds_at_where_clause() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo<'a> +where 'a: 'static, +{ + fn foo(&self) -> &'a str; +} +"#, + r#" +trait Foo<'a> +where 'a: 'static, +{ + fn foo(&self) -> &'a str; +} + +$0impl<'a, This> Foo<'a> for This +where 'a: 'static, +{ + fn foo(&self) -> &'a str { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_not_on_name() { + check_assist_not_applicable( + generate_blanket_trait_impl, + r#" +trait Foo: $0ToOwned +where + Self::Owned: Default, +{ + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + ); + + check_assist_not_applicable( + generate_blanket_trait_impl, + r#" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + $0fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + ); + + check_assist_not_applicable( + generate_blanket_trait_impl, + r#" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + fn $0foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_apply_on_other_impl_block() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +trait Bar {} +impl Bar for i32 {} +"#, + r#" +trait Foo { + fn foo(&self) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This { + fn foo(&self) -> i32 { + todo!() + } +} + +trait Bar {} +impl Bar for i32 {} +"#, + ); + } + + #[test] + fn test_gen_blanket_apply_on_other_blanket_impl_block() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +trait Bar {} +impl Bar for This {} +"#, + r#" +trait Foo { + fn foo(&self) -> i32; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This { + fn foo(&self) -> i32 { + todo!() + } +} + +trait Bar {} +impl Bar for This {} +"#, + ); + } +} 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 4682c04732389..be379b396006e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -153,6 +153,7 @@ mod handlers { mod flip_comma; mod flip_or_pattern; mod flip_trait_bound; + mod generate_blanket_trait_impl; mod generate_constant; mod generate_default_from_enum_variant; mod generate_default_from_new; @@ -290,6 +291,7 @@ mod handlers { generate_default_from_enum_variant::generate_default_from_enum_variant, generate_default_from_new::generate_default_from_new, generate_delegate_trait::generate_delegate_trait, + generate_blanket_trait_impl::generate_blanket_trait_impl, generate_derive::generate_derive, generate_documentation_template::generate_doc_example, generate_documentation_template::generate_documentation_template, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 91348be97eb72..22e26c9ee1b5d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1311,6 +1311,46 @@ fn foo() { } ) } +#[test] +fn doctest_generate_blanket_trait_impl() { + check_doc_test( + "generate_blanket_trait_impl", + r#####" +trait $0Foo: ToOwned +where + Self::Owned: Default, +{ + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} +"#####, + r#####" +trait Foo: ToOwned +where + Self::Owned: Default, +{ + fn foo(&self) -> T; + + fn print_foo(&self) { + println!("{}", self.foo()); + } +} + +$0impl Foo for This +where + Self::Owned: Default, +{ + fn foo(&self) -> T { + todo!() + } +} +"#####, + ) +} + #[test] fn doctest_generate_constant() { check_doc_test( From e9555f9a429270f396fe7f904fbbbe8b1f16637f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 5 Jun 2025 11:04:35 +0800 Subject: [PATCH 02/59] Use editor and fix tabstop on attrs --- .../handlers/generate_blanket_trait_impl.rs | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 3100809fc62ff..52bfaedaa4e5e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -8,10 +8,9 @@ use syntax::{ AstNode, ast::{ self, AssocItem, BlockExpr, GenericParam, HasGenericParams, HasName, HasTypeBounds, - HasVisibility as astHasVisibility, - edit_in_place::{AttrsOwnerEdit, Indent}, - make, + HasVisibility as astHasVisibility, edit_in_place::Indent, make, }, + syntax_editor::Position, }; // Assist: generate_blanket_trait_impl @@ -64,6 +63,7 @@ pub(crate) fn generate_blanket_trait_impl( "Generate blanket trait implementation", name.syntax().text_range(), |builder| { + let mut edit = builder.make_editor(traitd.syntax()); let namety = make::ty_path(make::path_from_text(&name.text())); let trait_where_clause = traitd.where_clause().map(|it| it.clone_for_update()); let bounds = traitd.type_bound_list(); @@ -109,7 +109,6 @@ pub(crate) fn generate_blanket_trait_impl( continue; } let f = todo_fn(&method, ctx.config).clone_for_update(); - f.remove_attrs_and_docs(); add_cfg_attrs_to(&method, &f); f.indent(1.into()); assoc_item_list.add_item(AssocItem::Fn(f)); @@ -118,10 +117,21 @@ pub(crate) fn generate_blanket_trait_impl( add_cfg_attrs_to(&traitd, &impl_); - impl_.reindent_to(indent); + impl_.indent(indent); - // FIXME: $0 after the cfg attributes - builder.insert(traitd.syntax().text_range().end(), format!("\n\n{indent}$0{impl_}")); + edit.insert_all( + Position::after(traitd.syntax()), + vec![ + make::tokens::whitespace(&format!("\n\n{indent}")).into(), + impl_.syntax().clone().into(), + ], + ); + + if let Some(cap) = ctx.config.snippet_cap { + builder.add_tabstop_before_token(cap, impl_.impl_token().unwrap()); + } + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ); @@ -426,8 +436,8 @@ mod foo { } } - $0#[cfg(test)] - impl Foo for This { + #[cfg(test)] + $0impl Foo for This { fn foo(&self) -> T { todo!() } @@ -667,8 +677,8 @@ trait Foo { } } -$0#[cfg(test)] -impl Foo for This { +#[cfg(test)] +$0impl Foo for This { fn foo(&self, x: i32) -> i32 { todo!() } @@ -701,8 +711,8 @@ trait Foo { } } -$0#[cfg(test)] -impl Foo for This { +#[cfg(test)] +$0impl Foo for This { #[cfg(test)] fn foo(&self, x: i32) -> i32 { todo!() From f4db374e85378adff477285c9dbca17bc83eadb0 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 6 Jun 2025 11:25:59 +0800 Subject: [PATCH 03/59] Add smart name and auto unsized --- .../handlers/generate_blanket_trait_impl.rs | 366 +++++++++++++++--- .../crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 312 insertions(+), 56 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 52bfaedaa4e5e..32ea37c37f39b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -8,7 +8,7 @@ use syntax::{ AstNode, ast::{ self, AssocItem, BlockExpr, GenericParam, HasGenericParams, HasName, HasTypeBounds, - HasVisibility as astHasVisibility, edit_in_place::Indent, make, + HasVisibility, edit_in_place::Indent, make, }, syntax_editor::Position, }; @@ -42,7 +42,7 @@ use syntax::{ // } // } // -// $0impl Foo for This +// $0impl Foo for This // where // Self::Owned: Default, // { @@ -66,15 +66,15 @@ pub(crate) fn generate_blanket_trait_impl( let mut edit = builder.make_editor(traitd.syntax()); let namety = make::ty_path(make::path_from_text(&name.text())); let trait_where_clause = traitd.where_clause().map(|it| it.clone_for_update()); - let bounds = traitd.type_bound_list(); + let bounds = traitd.type_bound_list().and_then(exlucde_sized); let is_unsafe = traitd.unsafe_token().is_some(); - let thisname = make::name("This"); + let thisname = this_name(&traitd); let thisty = make::ty_path(make::path_from_text(&thisname.text())); let indent = traitd.indent_level(); let gendecl = make::generic_param_list([GenericParam::TypeParam(make::type_param( thisname.clone(), - bounds, + apply_sized(has_sized(&traitd), bounds), ))]); let trait_gen_args = @@ -138,6 +138,122 @@ pub(crate) fn generate_blanket_trait_impl( Some(()) } +fn has_sized(traitd: &ast::Trait) -> bool { + if let Some(sized) = find_bound("Sized", traitd.type_bound_list()) { + sized.question_mark_token().is_none() + } else if let Some(is_sized) = where_clause_sized(traitd.where_clause()) { + is_sized + } else { + contained_owned_self_method(traitd.assoc_item_list()) + } +} + +fn contained_owned_self_method(item_list: Option) -> bool { + item_list.into_iter().flat_map(|assoc_item_list| assoc_item_list.assoc_items()).any(|item| { + match item { + AssocItem::Fn(f) => { + has_owned_self(&f) && where_clause_sized(f.where_clause()).is_none() + } + _ => false, + } + }) +} + +fn has_owned_self(f: &ast::Fn) -> bool { + has_owned_self_param(f) || has_ret_owned_self(f) +} + +fn has_owned_self_param(f: &ast::Fn) -> bool { + f.param_list() + .and_then(|param_list| param_list.self_param()) + .is_some_and(|sp| sp.amp_token().is_none() && sp.colon_token().is_none()) +} + +fn has_ret_owned_self(f: &ast::Fn) -> bool { + f.ret_type() + .and_then(|ret| match ret.ty() { + Some(ast::Type::PathType(ty)) => ty.path(), + _ => None, + }) + .is_some_and(|path| { + path.segment() + .and_then(|seg| seg.name_ref()) + .is_some_and(|name| path.qualifier().is_none() && name.text() == "Self") + }) +} + +fn where_clause_sized(where_clause: Option) -> Option { + where_clause?.predicates().find_map(|pred| { + find_bound("Sized", pred.type_bound_list()) + .map(|bound| bound.question_mark_token().is_none()) + }) +} + +fn apply_sized(has_sized: bool, bounds: Option) -> Option { + if has_sized { + return bounds; + } + let bounds = bounds + .into_iter() + .flat_map(|bounds| bounds.bounds()) + .chain([make::type_bound_text("?Sized")]); + make::type_bound_list(bounds) +} + +fn exlucde_sized(bounds: ast::TypeBoundList) -> Option { + make::type_bound_list(bounds.bounds().filter(|bound| !ty_bound_is(bound, "Sized"))) +} + +fn this_name(traitd: &ast::Trait) -> ast::Name { + let mut use_t = false; + let mut use_i = false; + let mut use_this = false; + + let has_iter = find_bound("Iterator", traitd.type_bound_list()).is_some(); + + traitd + .generic_param_list() + .into_iter() + .flat_map(|param_list| param_list.generic_params()) + .filter_map(|param| match param { + GenericParam::LifetimeParam(_) => None, + GenericParam::ConstParam(cp) => cp.name(), + GenericParam::TypeParam(tp) => tp.name(), + }) + .for_each(|name| match &*name.text() { + "T" => use_t = true, + "I" => use_i = true, + "This" => use_this = true, + _ => (), + }); + + make::name(if has_iter { + if !use_i { + "I" + } else if !use_t { + "T" + } else { + "This" + } + } else if !use_t { + "T" + } else { + "This" + }) +} + +fn find_bound(s: &str, bounds: Option) -> Option { + bounds.into_iter().flat_map(|bounds| bounds.bounds()).find(|bound| ty_bound_is(bound, s)) +} + +fn ty_bound_is(bound: &ast::TypeBound, s: &str) -> bool { + matches!(bound.ty(), + Some(ast::Type::PathType(ty)) if ty.path() + .and_then(|path| path.segment()) + .and_then(|segment| segment.name_ref()) + .is_some_and(|name| name.text() == s)) +} + fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { let params = f.param_list().unwrap_or_else(|| make::param_list(None, None)); make::fn_( @@ -198,7 +314,7 @@ where } } -$0impl Foo for This +$0impl Foo for This where Self::Owned: Default, { @@ -210,6 +326,146 @@ where ); } + #[test] + fn test_gen_blanket_sized() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Iterator + Sized { + fn foo(mut self) -> Self::Item { + self.next().unwrap() + } +} +"#, + r#" +trait Foo: Iterator + Sized { + fn foo(mut self) -> Self::Item { + self.next().unwrap() + } +} + +$0impl Foo for I {} +"#, + ); + + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Iterator { + fn foo(self) -> Self::Item; +} +"#, + r#" +trait Foo: Iterator { + fn foo(self) -> Self::Item; +} + +$0impl Foo for I { + fn foo(self) -> Self::Item { + todo!() + } +} +"#, + ); + + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo { + fn foo(&self) -> Self; +} +"#, + r#" +trait Foo { + fn foo(&self) -> Self; +} + +$0impl Foo for T { + fn foo(&self) -> Self { + todo!() + } +} +"#, + ); + } + + #[test] + fn test_gen_blanket_non_sized() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Iterator { + fn foo(&self) -> Self::Item; +} +"#, + r#" +trait Foo: Iterator { + fn foo(&self) -> Self::Item; +} + +$0impl Foo for I { + fn foo(&self) -> Self::Item { + todo!() + } +} +"#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Iterator { + fn foo(&self) -> Self::Item; + + fn each(self) where Self: Sized; +} +"#, + r#" +trait Foo: Iterator { + fn foo(&self) -> Self::Item; + + fn each(self) where Self: Sized; +} + +$0impl Foo for I { + fn foo(&self) -> Self::Item { + todo!() + } + + fn each(self) where Self: Sized { + todo!() + } +} +"#, + ); + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Iterator { + fn foo(&self) -> Self::Item; + + fn each(&self) -> Self where Self: Sized; +} +"#, + r#" +trait Foo: Iterator { + fn foo(&self) -> Self::Item; + + fn each(&self) -> Self where Self: Sized; +} + +$0impl Foo for I { + fn foo(&self) -> Self::Item { + todo!() + } + + fn each(&self) -> Self where Self: Sized { + todo!() + } +} +"#, + ); + } + #[test] fn test_gen_blanket_indent() { check_assist( @@ -241,7 +497,7 @@ mod foo { } } - $0impl Foo for This + $0impl Foo for This where Self::Owned: Default, { @@ -283,7 +539,7 @@ mod foo { } } - $0impl Foo for This + $0impl Foo for This where Self::Owned: Default, Self: Send, @@ -329,7 +585,7 @@ mod foo { } } - $0impl Foo for This + $0impl Foo for This where Self::Owned: Default, Self: Send, @@ -347,7 +603,7 @@ mod foo { r#" mod foo { trait $0Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); @@ -358,15 +614,15 @@ mod foo { r#" mod foo { trait Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); } } - $0impl Foo for This { - fn foo(&self) -> T { + $0impl Foo for T { + fn foo(&self) -> i32 { todo!() } } @@ -379,7 +635,7 @@ mod foo { mod foo { mod bar { trait $0Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); @@ -392,15 +648,15 @@ mod foo { mod foo { mod bar { trait Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); } } - $0impl Foo for This { - fn foo(&self) -> T { + $0impl Foo for T { + fn foo(&self) -> i32 { todo!() } } @@ -415,7 +671,7 @@ mod foo { mod bar { #[cfg(test)] trait $0Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); @@ -429,7 +685,7 @@ mod foo { mod bar { #[cfg(test)] trait Foo { - fn foo(&self) -> T; + fn foo(&self) -> i32; fn print_foo(&self) { println!("{}", self.foo()); @@ -437,8 +693,8 @@ mod foo { } #[cfg(test)] - $0impl Foo for This { - fn foo(&self) -> T { + $0impl Foo for T { + fn foo(&self) -> i32 { todo!() } } @@ -480,7 +736,7 @@ where } } -$0impl Foo for This +$0impl Foo for This where Self::Owned: Default, { @@ -524,7 +780,7 @@ where } } -$0impl Foo for This +$0impl Foo for This where Self::Owned: Default, { @@ -570,7 +826,7 @@ where } } -$0impl Foo for This +$0impl Foo for This where Self: ToOwned, Self::Owned: Default, @@ -609,7 +865,7 @@ trait Foo { } } -$0impl Foo for This { +$0impl Foo for This { fn foo(&self, x: Self::X) -> T { todo!() } @@ -644,7 +900,7 @@ trait Foo { } } -$0impl Foo for This { +$0impl Foo for T { fn foo(&self, x: Self::X) -> i32 { todo!() } @@ -678,7 +934,7 @@ trait Foo { } #[cfg(test)] -$0impl Foo for This { +$0impl Foo for T { fn foo(&self, x: i32) -> i32 { todo!() } @@ -712,7 +968,7 @@ trait Foo { } #[cfg(test)] -$0impl Foo for This { +$0impl Foo for T { #[cfg(test)] fn foo(&self, x: i32) -> i32 { todo!() @@ -732,7 +988,7 @@ trait $0Foo {} r#" trait Foo {} -$0impl Foo for This {} +$0impl Foo for T {} "#, ); } @@ -747,7 +1003,7 @@ trait $0Foo: Copy {} r#" trait Foo: Copy {} -$0impl Foo for This {} +$0impl Foo for T {} "#, ); } @@ -762,7 +1018,7 @@ trait $0Foo where Self: Copy {} r#" trait Foo where Self: Copy {} -$0impl Foo for This +$0impl Foo for T where Self: Copy { } @@ -780,7 +1036,7 @@ trait $0Foo where Self: Copy, {} r#" trait Foo where Self: Copy, {} -$0impl Foo for This +$0impl Foo for T where Self: Copy, { } @@ -802,7 +1058,7 @@ trait Foo where Self: Copy {} -$0impl Foo for This +$0impl Foo for T where Self: Copy { } @@ -826,7 +1082,7 @@ where Self: Copy {} -$0impl Foo for This +$0impl Foo for T where Self: Copy { @@ -851,7 +1107,7 @@ where Self: Copy, {} -$0impl Foo for This +$0impl Foo for T where Self: Copy, { @@ -878,7 +1134,7 @@ where (): Into, {} -$0impl Foo for This +$0impl Foo for T where Self: Copy, (): Into, @@ -906,7 +1162,7 @@ where (): Into, {} -$0impl Foo for This +$0impl Foo for T where Self: Copy + Sync, (): Into, @@ -930,7 +1186,7 @@ trait Foo { fn foo(&self) {} } -$0impl Foo for This {} +$0impl Foo for T {} "#, ); } @@ -947,7 +1203,7 @@ trait $0Foo {} /// some docs trait Foo {} -$0impl Foo for This {} +$0impl Foo for T {} "#, ); } @@ -968,7 +1224,7 @@ trait Foo { fn bar(&self); } -$0impl Foo for This { +$0impl Foo for T { fn foo(&self) { todo!() } @@ -987,18 +1243,18 @@ $0impl Foo for This { generate_blanket_trait_impl, r#" trait $0Foo { - fn foo(&self, value: T) -> T; - fn bar(&self, value: T) -> T { todo!() } + fn foo(&self, value: i32) -> i32; + fn bar(&self, value: i32) -> i32 { todo!() } } "#, r#" trait Foo { - fn foo(&self, value: T) -> T; - fn bar(&self, value: T) -> T { todo!() } + fn foo(&self, value: i32) -> i32; + fn bar(&self, value: i32) -> i32 { todo!() } } -$0impl Foo for This { - fn foo(&self, value: T) -> T { +$0impl Foo for T { + fn foo(&self, value: i32) -> i32 { todo!() } } @@ -1020,7 +1276,7 @@ trait Foo<'a> { fn foo(&self) -> &'a str; } -$0impl<'a, This> Foo<'a> for This { +$0impl<'a, T: ?Sized> Foo<'a> for T { fn foo(&self) -> &'a str { todo!() } @@ -1043,7 +1299,7 @@ trait Foo<'a: 'static> { fn foo(&self) -> &'a str; } -$0impl<'a: 'static, This> Foo<'a> for This { +$0impl<'a: 'static, T: ?Sized> Foo<'a> for T { fn foo(&self) -> &'a str { todo!() } @@ -1066,7 +1322,7 @@ trait Foo<'a>: 'a { fn foo(&self) -> &'a str; } -$0impl<'a, This: 'a> Foo<'a> for This { +$0impl<'a, T: 'a + ?Sized> Foo<'a> for T { fn foo(&self) -> &'a str { todo!() } @@ -1089,7 +1345,7 @@ trait Foo<'a, 'b> { fn foo(&self) -> &'a &'b str; } -$0impl<'a, 'b, This> Foo<'a, 'b> for This { +$0impl<'a, 'b, T: ?Sized> Foo<'a, 'b> for T { fn foo(&self) -> &'a &'b str { todo!() } @@ -1116,7 +1372,7 @@ where 'a: 'static, fn foo(&self) -> &'a str; } -$0impl<'a, This> Foo<'a> for This +$0impl<'a, T: ?Sized> Foo<'a> for T where 'a: 'static, { fn foo(&self) -> &'a str { @@ -1203,7 +1459,7 @@ trait Foo { } } -$0impl Foo for This { +$0impl Foo for T { fn foo(&self) -> i32 { todo!() } @@ -1229,7 +1485,7 @@ trait $0Foo { } trait Bar {} -impl Bar for This {} +impl Bar for T {} "#, r#" trait Foo { @@ -1240,14 +1496,14 @@ trait Foo { } } -$0impl Foo for This { +$0impl Foo for T { fn foo(&self) -> i32 { todo!() } } trait Bar {} -impl Bar for This {} +impl Bar for T {} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 22e26c9ee1b5d..54d111aa43929 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1339,7 +1339,7 @@ where } } -$0impl Foo for This +$0impl Foo for This where Self::Owned: Default, { From ee892ad3b245ae2e786ab3f5ffb6578be274342e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 28 Jun 2025 14:54:59 +0800 Subject: [PATCH 04/59] Change tabstop to self_ty --- .../handlers/generate_blanket_trait_impl.rs | 86 ++++++++++--------- .../crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 32ea37c37f39b..7904170d37c0d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -42,7 +42,7 @@ use syntax::{ // } // } // -// $0impl Foo for This +// impl Foo for $0This // where // Self::Owned: Default, // { @@ -128,7 +128,9 @@ pub(crate) fn generate_blanket_trait_impl( ); if let Some(cap) = ctx.config.snippet_cap { - builder.add_tabstop_before_token(cap, impl_.impl_token().unwrap()); + if let Some(self_ty) = impl_.self_ty() { + builder.add_tabstop_before(cap, self_ty); + } } builder.add_file_edits(ctx.vfs_file_id(), edit); @@ -314,7 +316,7 @@ where } } -$0impl Foo for This +impl Foo for $0This where Self::Owned: Default, { @@ -344,7 +346,7 @@ trait Foo: Iterator + Sized { } } -$0impl Foo for I {} +impl Foo for $0I {} "#, ); @@ -360,7 +362,7 @@ trait Foo: Iterator { fn foo(self) -> Self::Item; } -$0impl Foo for I { +impl Foo for $0I { fn foo(self) -> Self::Item { todo!() } @@ -380,7 +382,7 @@ trait Foo { fn foo(&self) -> Self; } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self) -> Self { todo!() } @@ -403,7 +405,7 @@ trait Foo: Iterator { fn foo(&self) -> Self::Item; } -$0impl Foo for I { +impl Foo for $0I { fn foo(&self) -> Self::Item { todo!() } @@ -426,7 +428,7 @@ trait Foo: Iterator { fn each(self) where Self: Sized; } -$0impl Foo for I { +impl Foo for $0I { fn foo(&self) -> Self::Item { todo!() } @@ -453,7 +455,7 @@ trait Foo: Iterator { fn each(&self) -> Self where Self: Sized; } -$0impl Foo for I { +impl Foo for $0I { fn foo(&self) -> Self::Item { todo!() } @@ -497,7 +499,7 @@ mod foo { } } - $0impl Foo for This + impl Foo for $0This where Self::Owned: Default, { @@ -539,7 +541,7 @@ mod foo { } } - $0impl Foo for This + impl Foo for $0This where Self::Owned: Default, Self: Send, @@ -585,7 +587,7 @@ mod foo { } } - $0impl Foo for This + impl Foo for $0This where Self::Owned: Default, Self: Send, @@ -621,7 +623,7 @@ mod foo { } } - $0impl Foo for T { + impl Foo for $0T { fn foo(&self) -> i32 { todo!() } @@ -655,7 +657,7 @@ mod foo { } } - $0impl Foo for T { + impl Foo for $0T { fn foo(&self) -> i32 { todo!() } @@ -693,7 +695,7 @@ mod foo { } #[cfg(test)] - $0impl Foo for T { + impl Foo for $0T { fn foo(&self) -> i32 { todo!() } @@ -736,7 +738,7 @@ where } } -$0impl Foo for This +impl Foo for $0This where Self::Owned: Default, { @@ -780,7 +782,7 @@ where } } -$0impl Foo for This +impl Foo for $0This where Self::Owned: Default, { @@ -826,7 +828,7 @@ where } } -$0impl Foo for This +impl Foo for $0This where Self: ToOwned, Self::Owned: Default, @@ -865,7 +867,7 @@ trait Foo { } } -$0impl Foo for This { +impl Foo for $0This { fn foo(&self, x: Self::X) -> T { todo!() } @@ -900,7 +902,7 @@ trait Foo { } } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self, x: Self::X) -> i32 { todo!() } @@ -934,7 +936,7 @@ trait Foo { } #[cfg(test)] -$0impl Foo for T { +impl Foo for $0T { fn foo(&self, x: i32) -> i32 { todo!() } @@ -968,7 +970,7 @@ trait Foo { } #[cfg(test)] -$0impl Foo for T { +impl Foo for $0T { #[cfg(test)] fn foo(&self, x: i32) -> i32 { todo!() @@ -988,7 +990,7 @@ trait $0Foo {} r#" trait Foo {} -$0impl Foo for T {} +impl Foo for $0T {} "#, ); } @@ -1003,7 +1005,7 @@ trait $0Foo: Copy {} r#" trait Foo: Copy {} -$0impl Foo for T {} +impl Foo for $0T {} "#, ); } @@ -1018,7 +1020,7 @@ trait $0Foo where Self: Copy {} r#" trait Foo where Self: Copy {} -$0impl Foo for T +impl Foo for $0T where Self: Copy { } @@ -1036,7 +1038,7 @@ trait $0Foo where Self: Copy, {} r#" trait Foo where Self: Copy, {} -$0impl Foo for T +impl Foo for $0T where Self: Copy, { } @@ -1058,7 +1060,7 @@ trait Foo where Self: Copy {} -$0impl Foo for T +impl Foo for $0T where Self: Copy { } @@ -1082,7 +1084,7 @@ where Self: Copy {} -$0impl Foo for T +impl Foo for $0T where Self: Copy { @@ -1107,7 +1109,7 @@ where Self: Copy, {} -$0impl Foo for T +impl Foo for $0T where Self: Copy, { @@ -1134,7 +1136,7 @@ where (): Into, {} -$0impl Foo for T +impl Foo for $0T where Self: Copy, (): Into, @@ -1162,7 +1164,7 @@ where (): Into, {} -$0impl Foo for T +impl Foo for $0T where Self: Copy + Sync, (): Into, @@ -1186,7 +1188,7 @@ trait Foo { fn foo(&self) {} } -$0impl Foo for T {} +impl Foo for $0T {} "#, ); } @@ -1203,7 +1205,7 @@ trait $0Foo {} /// some docs trait Foo {} -$0impl Foo for T {} +impl Foo for $0T {} "#, ); } @@ -1224,7 +1226,7 @@ trait Foo { fn bar(&self); } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self) { todo!() } @@ -1253,7 +1255,7 @@ trait Foo { fn bar(&self, value: i32) -> i32 { todo!() } } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self, value: i32) -> i32 { todo!() } @@ -1276,7 +1278,7 @@ trait Foo<'a> { fn foo(&self) -> &'a str; } -$0impl<'a, T: ?Sized> Foo<'a> for T { +impl<'a, T: ?Sized> Foo<'a> for $0T { fn foo(&self) -> &'a str { todo!() } @@ -1299,7 +1301,7 @@ trait Foo<'a: 'static> { fn foo(&self) -> &'a str; } -$0impl<'a: 'static, T: ?Sized> Foo<'a> for T { +impl<'a: 'static, T: ?Sized> Foo<'a> for $0T { fn foo(&self) -> &'a str { todo!() } @@ -1322,7 +1324,7 @@ trait Foo<'a>: 'a { fn foo(&self) -> &'a str; } -$0impl<'a, T: 'a + ?Sized> Foo<'a> for T { +impl<'a, T: 'a + ?Sized> Foo<'a> for $0T { fn foo(&self) -> &'a str { todo!() } @@ -1345,7 +1347,7 @@ trait Foo<'a, 'b> { fn foo(&self) -> &'a &'b str; } -$0impl<'a, 'b, T: ?Sized> Foo<'a, 'b> for T { +impl<'a, 'b, T: ?Sized> Foo<'a, 'b> for $0T { fn foo(&self) -> &'a &'b str { todo!() } @@ -1372,7 +1374,7 @@ where 'a: 'static, fn foo(&self) -> &'a str; } -$0impl<'a, T: ?Sized> Foo<'a> for T +impl<'a, T: ?Sized> Foo<'a> for $0T where 'a: 'static, { fn foo(&self) -> &'a str { @@ -1459,7 +1461,7 @@ trait Foo { } } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self) -> i32 { todo!() } @@ -1496,7 +1498,7 @@ trait Foo { } } -$0impl Foo for T { +impl Foo for $0T { fn foo(&self) -> i32 { todo!() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 54d111aa43929..18edb1b8d17c6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1339,7 +1339,7 @@ where } } -$0impl Foo for This +impl Foo for $0This where Self::Owned: Default, { From 71f8c5a49968840fccaf78d6657ebfa2cc222a3a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 28 Jun 2025 15:24:12 +0800 Subject: [PATCH 05/59] Use NameGenerator --- .../handlers/generate_blanket_trait_impl.rs | 56 +++++++------------ .../crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 7904170d37c0d..36031f15a043a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -3,7 +3,10 @@ use crate::{ assist_context::{AssistContext, Assists}, utils::add_cfg_attrs_to, }; -use ide_db::assists::{AssistId, AssistKind, ExprFillDefaultMode}; +use ide_db::{ + assists::{AssistId, AssistKind, ExprFillDefaultMode}, + syntax_helpers::suggest_name, +}; use syntax::{ AstNode, ast::{ @@ -42,7 +45,7 @@ use syntax::{ // } // } // -// impl Foo for $0This +// impl Foo for $0T1 // where // Self::Owned: Default, // { @@ -207,13 +210,9 @@ fn exlucde_sized(bounds: ast::TypeBoundList) -> Option { } fn this_name(traitd: &ast::Trait) -> ast::Name { - let mut use_t = false; - let mut use_i = false; - let mut use_this = false; - let has_iter = find_bound("Iterator", traitd.type_bound_list()).is_some(); - traitd + let params = traitd .generic_param_list() .into_iter() .flat_map(|param_list| param_list.generic_params()) @@ -222,26 +221,13 @@ fn this_name(traitd: &ast::Trait) -> ast::Name { GenericParam::ConstParam(cp) => cp.name(), GenericParam::TypeParam(tp) => tp.name(), }) - .for_each(|name| match &*name.text() { - "T" => use_t = true, - "I" => use_i = true, - "This" => use_this = true, - _ => (), - }); - - make::name(if has_iter { - if !use_i { - "I" - } else if !use_t { - "T" - } else { - "This" - } - } else if !use_t { - "T" - } else { - "This" - }) + .map(|name| name.to_string()) + .collect::>(); + + let mut name_gen = + suggest_name::NameGenerator::new_with_names(params.iter().map(String::as_str)); + + make::name(&name_gen.suggest_name(if has_iter { "I" } else { "T" })) } fn find_bound(s: &str, bounds: Option) -> Option { @@ -316,7 +302,7 @@ where } } -impl Foo for $0This +impl Foo for $0T1 where Self::Owned: Default, { @@ -499,7 +485,7 @@ mod foo { } } - impl Foo for $0This + impl Foo for $0T1 where Self::Owned: Default, { @@ -541,7 +527,7 @@ mod foo { } } - impl Foo for $0This + impl Foo for $0T1 where Self::Owned: Default, Self: Send, @@ -587,7 +573,7 @@ mod foo { } } - impl Foo for $0This + impl Foo for $0T1 where Self::Owned: Default, Self: Send, @@ -738,7 +724,7 @@ where } } -impl Foo for $0This +impl Foo for $0T1 where Self::Owned: Default, { @@ -782,7 +768,7 @@ where } } -impl Foo for $0This +impl Foo for $0T1 where Self::Owned: Default, { @@ -828,7 +814,7 @@ where } } -impl Foo for $0This +impl Foo for $0T1 where Self: ToOwned, Self::Owned: Default, @@ -867,7 +853,7 @@ trait Foo { } } -impl Foo for $0This { +impl Foo for $0T1 { fn foo(&self, x: Self::X) -> T { todo!() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 18edb1b8d17c6..306812fbe1591 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1339,7 +1339,7 @@ where } } -impl Foo for $0This +impl Foo for $0T1 where Self::Owned: Default, { From c7cc54e15d3df998332a2839cbb42ce429891a91 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 28 Jun 2025 16:05:42 +0800 Subject: [PATCH 06/59] Move gen_blanket_trait_impl assist after generates --- src/tools/rust-analyzer/crates/ide-assists/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 be379b396006e..2977f8b8c2e75 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -291,7 +291,6 @@ mod handlers { generate_default_from_enum_variant::generate_default_from_enum_variant, generate_default_from_new::generate_default_from_new, generate_delegate_trait::generate_delegate_trait, - generate_blanket_trait_impl::generate_blanket_trait_impl, generate_derive::generate_derive, generate_documentation_template::generate_doc_example, generate_documentation_template::generate_documentation_template, @@ -310,6 +309,7 @@ mod handlers { generate_new::generate_new, generate_trait_from_impl::generate_trait_from_impl, generate_single_field_struct_from::generate_single_field_struct_from, + generate_blanket_trait_impl::generate_blanket_trait_impl, inline_call::inline_call, inline_call::inline_into_callers, inline_const_as_literal::inline_const_as_literal, From 8402a76f559332a2aafe5285c3b961c82103be41 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 25 Jul 2025 13:57:41 +0800 Subject: [PATCH 07/59] Add existing any implement not applicate blanket --- .../handlers/generate_blanket_trait_impl.rs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 36031f15a043a..1ec49f017fa2f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -3,7 +3,9 @@ use crate::{ assist_context::{AssistContext, Assists}, utils::add_cfg_attrs_to, }; +use hir::Semantics; use ide_db::{ + RootDatabase, assists::{AssistId, AssistKind, ExprFillDefaultMode}, syntax_helpers::suggest_name, }; @@ -61,6 +63,11 @@ pub(crate) fn generate_blanket_trait_impl( let name = ctx.find_node_at_offset::()?; let traitd = ast::Trait::cast(name.syntax().parent()?)?; + if existing_any_impl(&traitd, &ctx.sema).is_some() { + cov_mark::hit!(existing_any_impl); + return None; + } + acc.add( AssistId("generate_blanket_trait_impl", AssistKind::Generate, None), "Generate blanket trait implementation", @@ -143,6 +150,16 @@ pub(crate) fn generate_blanket_trait_impl( Some(()) } +fn existing_any_impl(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> Option { + let db = sema.db; + let traitd = sema.to_def(traitd)?; + traitd + .module(db) + .impl_defs(db) + .into_iter() + .find(|impl_| impl_.trait_(db).is_some_and(|it| it == traitd)) +} + fn has_sized(traitd: &ast::Trait) -> bool { if let Some(sized) = find_bound("Sized", traitd.type_bound_list()) { sized.question_mark_token().is_none() @@ -1422,6 +1439,51 @@ where ); } + #[test] + fn test_gen_blanket_existing_impl() { + cov_mark::check!(existing_any_impl); + check_assist_not_applicable( + generate_blanket_trait_impl, + r#" +trait $0Foo: Default { + fn foo(&self) -> Self; +} +impl Foo for () {} +"#, + ); + } + + #[test] + fn test_gen_blanket_existing_other_impl() { + check_assist( + generate_blanket_trait_impl, + r#" +trait $0Foo: Default { + fn foo(&self) -> Self; +} +trait Bar: Default { + fn bar(&self) -> Self; +} +impl Bar for () {} +"#, + r#" +trait Foo: Default { + fn foo(&self) -> Self; +} + +impl Foo for $0T { + fn foo(&self) -> Self { + todo!() + } +} +trait Bar: Default { + fn bar(&self) -> Self; +} +impl Bar for () {} +"#, + ); + } + #[test] fn test_gen_blanket_apply_on_other_impl_block() { check_assist( From d946b152c2f890198d1949e992590d9c1fb393e9 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 25 Jul 2025 20:52:56 +0800 Subject: [PATCH 08/59] Improve sized check, from super traits --- .../handlers/generate_blanket_trait_impl.rs | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index 1ec49f017fa2f..dc8056e90339e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -3,10 +3,11 @@ use crate::{ assist_context::{AssistContext, Assists}, utils::add_cfg_attrs_to, }; -use hir::Semantics; +use hir::{HasCrate, Semantics}; use ide_db::{ RootDatabase, assists::{AssistId, AssistKind, ExprFillDefaultMode}, + famous_defs::FamousDefs, syntax_helpers::suggest_name, }; use syntax::{ @@ -84,7 +85,7 @@ pub(crate) fn generate_blanket_trait_impl( let gendecl = make::generic_param_list([GenericParam::TypeParam(make::type_param( thisname.clone(), - apply_sized(has_sized(&traitd), bounds), + apply_sized(has_sized(&traitd, &ctx.sema), bounds), ))]); let trait_gen_args = @@ -160,16 +161,24 @@ fn existing_any_impl(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> .find(|impl_| impl_.trait_(db).is_some_and(|it| it == traitd)) } -fn has_sized(traitd: &ast::Trait) -> bool { +fn has_sized(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> bool { if let Some(sized) = find_bound("Sized", traitd.type_bound_list()) { sized.question_mark_token().is_none() } else if let Some(is_sized) = where_clause_sized(traitd.where_clause()) { is_sized } else { contained_owned_self_method(traitd.assoc_item_list()) + || super_traits_has_sized(traitd, sema) == Some(true) } } +fn super_traits_has_sized(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> Option { + let traitd = sema.to_def(traitd)?; + let sized = FamousDefs(sema, traitd.krate(sema.db)).core_marker_Sized()?; + + Some(traitd.all_supertraits(sema.db).contains(&sized)) +} + fn contained_owned_self_method(item_list: Option) -> bool { item_list.into_iter().flat_map(|assoc_item_list| assoc_item_list.assoc_items()).any(|item| { match item { @@ -394,6 +403,30 @@ impl Foo for $0T { ); } + #[test] + fn test_gen_blanket_super_sized() { + check_assist( + generate_blanket_trait_impl, + r#" +//- minicore: default +trait $0Foo: Default { + fn foo(&self); +} +"#, + r#" +trait Foo: Default { + fn foo(&self); +} + +impl Foo for $0T { + fn foo(&self) { + todo!() + } +} +"#, + ); + } + #[test] fn test_gen_blanket_non_sized() { check_assist( From c3c5f2f9e7b60d2b0b5bca5d9cd330d72da3dc73 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 30 Aug 2025 19:12:15 +0800 Subject: [PATCH 09/59] Change add_cfg_attrs_to to make parameter --- .../handlers/generate_blanket_trait_impl.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index dc8056e90339e..c25b0bbe7cea0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -1,7 +1,6 @@ use crate::{ AssistConfig, assist_context::{AssistContext, Assists}, - utils::add_cfg_attrs_to, }; use hir::{HasCrate, Semantics}; use ide_db::{ @@ -13,8 +12,8 @@ use ide_db::{ use syntax::{ AstNode, ast::{ - self, AssocItem, BlockExpr, GenericParam, HasGenericParams, HasName, HasTypeBounds, - HasVisibility, edit_in_place::Indent, make, + self, AssocItem, BlockExpr, GenericParam, HasAttrs, HasGenericParams, HasName, + HasTypeBounds, HasVisibility, edit_in_place::Indent, make, }, syntax_editor::Position, }; @@ -96,6 +95,7 @@ pub(crate) fn generate_blanket_trait_impl( } let impl_ = make::impl_trait( + cfg_attrs(&traitd), is_unsafe, traitd.generic_param_list(), trait_gen_args, @@ -120,14 +120,11 @@ pub(crate) fn generate_blanket_trait_impl( continue; } let f = todo_fn(&method, ctx.config).clone_for_update(); - add_cfg_attrs_to(&method, &f); f.indent(1.into()); assoc_item_list.add_item(AssocItem::Fn(f)); } } - add_cfg_attrs_to(&traitd, &impl_); - impl_.indent(indent); edit.insert_all( @@ -138,10 +135,10 @@ pub(crate) fn generate_blanket_trait_impl( ], ); - if let Some(cap) = ctx.config.snippet_cap { - if let Some(self_ty) = impl_.self_ty() { - builder.add_tabstop_before(cap, self_ty); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(self_ty) = impl_.self_ty() + { + builder.add_tabstop_before(cap, self_ty); } builder.add_file_edits(ctx.vfs_file_id(), edit); @@ -271,6 +268,7 @@ fn ty_bound_is(bound: &ast::TypeBound, s: &str) -> bool { fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { let params = f.param_list().unwrap_or_else(|| make::param_list(None, None)); make::fn_( + cfg_attrs(f), f.visibility(), f.name().unwrap_or_else(|| make::name("unnamed")), f.generic_param_list(), @@ -294,6 +292,10 @@ fn default_block(config: &AssistConfig) -> BlockExpr { make::block_expr(None, Some(expr)) } +fn cfg_attrs(node: &impl HasAttrs) -> impl Iterator { + node.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")) +} + #[cfg(test)] mod test { From 3d25a36099bd57ba95f685b699bedcba6a9cae2c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 24 Aug 2025 19:26:12 +0800 Subject: [PATCH 10/59] Fix .let completion not work for let-chain Example --- ```rust fn main() { let bar = Some(true); if true && bar.$0 } ``` **Before this PR**: Cannot complete `.let` **After this PR**: ```rust fn main() { let bar = Some(true); if true && let Some($0) = bar } ``` --- .../ide-completion/src/completions/postfix.rs | 62 ++++++++++++++++--- .../ide-completion/src/context/analysis.rs | 33 +++------- 2 files changed, 62 insertions(+), 33 deletions(-) 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 d355fdbe0739c..51acdb7802b3f 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 @@ -11,12 +11,12 @@ use ide_db::{ text_edit::TextEdit, ty_filter::TryEnum, }; -use itertools::Either; use stdx::never; use syntax::{ SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR}, - TextRange, TextSize, + T, TextRange, TextSize, ast::{self, AstNode, AstToken}, + match_ast, }; use crate::{ @@ -113,12 +113,8 @@ pub(crate) fn complete_postfix( if let Some(parent) = dot_receiver_including_refs.syntax().parent() && let Some(second_ancestor) = parent.parent() { - let sec_ancestor_kind = second_ancestor.kind(); - if let Some(expr) = >::cast(second_ancestor) { - is_in_cond = match expr { - Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), - Either::Right(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), - } + if let Some(parent_expr) = ast::Expr::cast(parent) { + is_in_cond = is_in_condition(&parent_expr); } match &try_enum { Some(try_enum) if is_in_cond => match try_enum { @@ -147,7 +143,7 @@ pub(crate) fn complete_postfix( .add_to(acc, ctx.db); } }, - _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => { + _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => { postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) .add_to(acc, ctx.db); postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) @@ -454,6 +450,22 @@ fn add_custom_postfix_completions( None } +pub(crate) fn is_in_condition(it: &ast::Expr) -> bool { + it.syntax() + .parent() + .and_then(|parent| { + Some(match_ast! { match parent { + ast::IfExpr(expr) => expr.condition()? == *it, + ast::WhileExpr(expr) => expr.condition()? == *it, + ast::MatchGuard(guard) => guard.condition()? == *it, + ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&]) + .then(|| is_in_condition(&bin_expr.into()))?, + _ => return None, + } }) + }) + .unwrap_or(false) +} + #[cfg(test)] mod tests { use expect_test::expect; @@ -648,6 +660,38 @@ fn main() { let bar = Some(true); if let Some($0) = bar } +"#, + ); + check_edit( + "let", + r#" +//- minicore: option +fn main() { + let bar = Some(true); + if true && bar.$0 +} +"#, + r#" +fn main() { + let bar = Some(true); + if true && let Some($0) = bar +} +"#, + ); + check_edit( + "let", + r#" +//- minicore: option +fn main() { + let bar = Some(true); + if true && true && bar.$0 +} +"#, + r#" +fn main() { + let bar = Some(true); + if true && true && let Some($0) = bar +} "#, ); } 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 77a94403abb94..6a154c61b82ff 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 @@ -20,12 +20,15 @@ use syntax::{ match_ast, }; -use crate::context::{ - AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx, - DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, - NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, PathKind, - PatternContext, PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, - TypeLocation, +use crate::{ + completions::postfix::is_in_condition, + context::{ + AttrCtx, BreakableKind, COMPLETION_MARKER, CompletionAnalysis, DotAccess, DotAccessExprCtx, + DotAccessKind, ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, + NameRefContext, NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, + PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx, + TypeAscriptionTarget, TypeLocation, + }, }; #[derive(Debug)] @@ -1216,24 +1219,6 @@ fn classify_name_ref<'db>( Some(res) }; - 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.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(); let in_block_expr = is_in_block(it); From b2071862aed0360da92dbc42d8c2818af4f37bc8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 30 Sep 2025 10:36:23 +0300 Subject: [PATCH 11/59] Migrate inference to next solver --- src/tools/rust-analyzer/Cargo.lock | 1 + .../crates/hir-def/src/expr_store/path.rs | 2 +- .../crates/hir-ty/src/autoderef.rs | 56 +- .../crates/hir-ty/src/builder.rs | 16 +- .../crates/hir-ty/src/chalk_db.rs | 15 +- .../crates/hir-ty/src/consteval.rs | 102 +- .../crates/hir-ty/src/consteval/tests.rs | 8 +- .../crates/hir-ty/src/consteval_nextsolver.rs | 20 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 72 +- .../crates/hir-ty/src/diagnostics/expr.rs | 46 +- .../hir-ty/src/diagnostics/match_check.rs | 37 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 24 +- .../crates/hir-ty/src/display.rs | 11 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 13 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 1246 +++++++---------- .../crates/hir-ty/src/infer/autoderef.rs | 14 +- .../crates/hir-ty/src/infer/cast.rs | 347 +++-- .../crates/hir-ty/src/infer/closure.rs | 78 +- .../hir-ty/src/infer/closure/analysis.rs | 264 ++-- .../crates/hir-ty/src/infer/coerce.rs | 240 ++-- .../crates/hir-ty/src/infer/diagnostics.rs | 46 +- .../crates/hir-ty/src/infer/expr.rs | 1244 +++++++--------- .../crates/hir-ty/src/infer/fallback.rs | 4 +- .../crates/hir-ty/src/infer/mutability.rs | 43 +- .../crates/hir-ty/src/infer/pat.rs | 323 +++-- .../crates/hir-ty/src/infer/path.rs | 217 ++- .../crates/hir-ty/src/infer/unify.rs | 964 ++++--------- .../rust-analyzer/crates/hir-ty/src/layout.rs | 17 +- .../crates/hir-ty/src/layout/tests.rs | 13 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 123 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 38 +- .../crates/hir-ty/src/lower/path.rs | 190 +-- .../crates/hir-ty/src/lower_nextsolver.rs | 176 ++- .../hir-ty/src/lower_nextsolver/path.rs | 57 +- .../crates/hir-ty/src/method_resolution.rs | 740 +++++----- .../rust-analyzer/crates/hir-ty/src/mir.rs | 6 +- .../crates/hir-ty/src/mir/borrowck.rs | 29 +- .../crates/hir-ty/src/mir/eval.rs | 226 +-- .../crates/hir-ty/src/mir/eval/shim.rs | 33 +- .../crates/hir-ty/src/mir/eval/shim/simd.rs | 6 +- .../crates/hir-ty/src/mir/eval/tests.rs | 4 +- .../crates/hir-ty/src/mir/lower.rs | 196 +-- .../crates/hir-ty/src/mir/lower/as_place.rs | 33 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 69 +- .../crates/hir-ty/src/mir/lower/tests.rs | 11 +- .../crates/hir-ty/src/mir/monomorphization.rs | 44 +- .../crates/hir-ty/src/next_solver.rs | 3 + .../crates/hir-ty/src/next_solver/def_id.rs | 11 + .../crates/hir-ty/src/next_solver/fold.rs | 23 + .../hir-ty/src/next_solver/generic_arg.rs | 68 +- .../hir-ty/src/next_solver/infer/mod.rs | 116 +- .../hir-ty/src/next_solver/infer/resolve.rs | 52 +- .../hir-ty/src/next_solver/infer/select.rs | 78 ++ .../src/next_solver/infer/snapshot/mod.rs | 13 + .../hir-ty/src/next_solver/infer/traits.rs | 36 +- .../crates/hir-ty/src/next_solver/interner.rs | 4 +- .../crates/hir-ty/src/next_solver/mapping.rs | 40 + .../crates/hir-ty/src/next_solver/region.rs | 12 +- .../crates/hir-ty/src/next_solver/ty.rs | 67 +- .../crates/hir-ty/src/next_solver/util.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 512 +++---- .../hir-ty/src/tests/closure_captures.rs | 15 +- .../crates/hir-ty/src/tests/coercion.rs | 16 +- .../hir-ty/src/tests/display_source_code.rs | 8 +- .../crates/hir-ty/src/tests/incremental.rs | 19 +- .../crates/hir-ty/src/tests/macros.rs | 8 +- .../hir-ty/src/tests/method_resolution.rs | 6 +- .../crates/hir-ty/src/tests/opaque_types.rs | 1 + .../crates/hir-ty/src/tests/regression.rs | 8 +- .../hir-ty/src/tests/regression/new_solver.rs | 2 +- .../crates/hir-ty/src/tests/simple.rs | 35 +- .../crates/hir-ty/src/tests/traits.rs | 54 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 35 +- .../crates/hir/src/diagnostics.rs | 29 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 74 +- .../rust-analyzer/crates/hir/src/semantics.rs | 32 +- .../crates/hir/src/source_analyzer.rs | 188 ++- .../src/handlers/convert_closure_to_fn.rs | 2 +- .../crates/ide-completion/src/render.rs | 2 +- .../src/handlers/type_mismatch.rs | 2 +- .../crates/ide-ssr/src/matching.rs | 60 +- .../rust-analyzer/crates/ide-ssr/src/tests.rs | 146 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 4 +- .../rust-analyzer/crates/ide/src/interpret.rs | 2 +- .../crates/ide/src/static_index.rs | 111 +- .../crates/ide/src/syntax_highlighting.rs | 9 +- .../crates/ide/src/view_memory_layout.rs | 26 +- .../crates/rust-analyzer/Cargo.toml | 2 + .../rust-analyzer/src/cli/analysis_stats.rs | 61 +- .../crates/rust-analyzer/src/lib.rs | 2 + 90 files changed, 4558 insertions(+), 4902 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 086f38f06a52d..5a0d209602dfe 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2040,6 +2040,7 @@ dependencies = [ "process-wrap", "profile", "project-model", + "ra-ap-rustc_type_ir", "rayon", "rustc-hash 2.1.1", "scip", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs index 55e738b58bd00..fbbaa587b095d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/path.rs @@ -88,7 +88,7 @@ pub struct AssociatedTypeBinding { } /// A single generic argument. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GenericArg { Type(TypeRefId), Lifetime(LifetimeRefId), 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 21a86d3e43727..0be00afe7bf45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -5,12 +5,15 @@ use std::fmt; +use hir_def::TraitId; 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::TraitRef; use crate::next_solver::infer::InferOk; +use crate::next_solver::infer::traits::Obligation; use crate::{ TraitEnvironment, db::HirDatabase, @@ -38,14 +41,14 @@ pub fn autoderef<'db>( ty: crate::Canonical, ) -> impl Iterator + use<> { 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.to_nextsolver(interner)); + let interner = table.interner(); + let ty = table.instantiate_canonical(ty.to_nextsolver(interner)); + let mut autoderef = Autoderef::new_no_tracking(&mut table, ty); 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.to_chalk(interner)); + 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. @@ -101,6 +104,7 @@ struct AutoderefSnapshot<'db, Steps> { #[derive(Clone, Copy)] struct AutoderefTraits { + trait_: TraitId, trait_target: TypeAliasId, } @@ -215,16 +219,26 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> { 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) - })?, - } + (|| { + Some(AutoderefTraits { + trait_: LangItem::Receiver + .resolve_trait(self.table.db, self.table.trait_env.krate)?, + trait_target: LangItem::ReceiverTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, + }) + })() + .or_else(|| { + Some(AutoderefTraits { + trait_: LangItem::Deref + .resolve_trait(self.table.db, self.table.trait_env.krate)?, + trait_target: LangItem::DerefTarget + .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, + }) + })? } else { AutoderefTraits { + trait_: LangItem::Deref + .resolve_trait(self.table.db, self.table.trait_env.krate)?, trait_target: LangItem::DerefTarget .resolve_type_alias(self.table.db, self.table.trait_env.krate)?, } @@ -236,10 +250,22 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> { fn overloaded_deref_ty(&mut self, ty: Ty<'db>) -> Option> { debug!("overloaded_deref_ty({:?})", ty); - let interner = self.table.interner; + 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 AutoderefTraits { trait_, trait_target } = self.autoderef_traits()?; + + let trait_ref = TraitRef::new(interner, trait_.into(), [ty]); + let obligation = + Obligation::new(interner, ObligationCause::new(), self.table.trait_env.env, trait_ref); + // We detect whether the self type implements `Deref` before trying to + // structurally normalize. We use `predicate_may_hold_opaque_types_jank` + // to support not-yet-defined opaque types. It will succeed for `impl Deref` + // but fail for `impl OtherTrait`. + if !self.table.infer_ctxt.predicate_may_hold_opaque_types_jank(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } let (normalized_ty, obligations) = structurally_normalize_ty( self.table, @@ -316,7 +342,7 @@ pub(crate) fn overloaded_deref_ty<'db>( table: &InferenceTable<'db>, ty: Ty<'db>, ) -> Option>> { - let interner = table.interner; + let interner = table.interner(); let trait_target = LangItem::DerefTarget.resolve_type_alias(table.db, table.trait_env.krate)?; 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 5511587c71a46..798b0f2c0c246 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -15,7 +15,10 @@ use crate::{ error_lifetime, generics::generics, infer::unify::InferenceTable, - next_solver::{DbInterner, EarlyBinder, mapping::ChalkToNextSolver}, + next_solver::{ + DbInterner, EarlyBinder, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, primitive, to_assoc_type_id, to_chalk_trait_id, }; @@ -141,10 +144,13 @@ impl TyBuilder { #[tracing::instrument(skip_all)] pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self { - self.fill(|x| match x { - ParamKind::Type => table.new_type_var().cast(Interner), - ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner), - ParamKind::Lifetime => table.new_lifetime_var().cast(Interner), + self.fill(|x| { + match x { + ParamKind::Type => crate::next_solver::GenericArg::Ty(table.next_ty_var()), + ParamKind::Const(_) => table.next_const_var().into(), + ParamKind::Lifetime => table.next_region_var().into(), + } + .to_chalk(table.interner()) }) } 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 546991cf6571e..3d06b52106709 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 @@ -2,7 +2,7 @@ //! about the code that Chalk needs. use hir_def::{CallableDefId, GenericDefId}; -use crate::{Interner, Substitution, db::HirDatabase, mapping::from_chalk}; +use crate::{Interner, db::HirDatabase, mapping::from_chalk}; pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; pub(crate) type TraitId = chalk_ir::TraitId; @@ -53,16 +53,3 @@ pub(crate) fn adt_variance_query(db: &dyn HirDatabase, adt_id: hir_def::AdtId) - }), ) } - -/// Returns instantiated predicates. -pub(super) fn convert_where_clauses( - db: &dyn HirDatabase, - def: GenericDefId, - substs: &Substitution, -) -> Vec> { - db.generic_predicates(def) - .iter() - .cloned() - .map(|pred| pred.substitute(Interner, substs)) - .collect() -} 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 b2daed425ef1c..8b12c5fd890c1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -4,8 +4,8 @@ use base_db::Crate; use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast}; use hir_def::{ EnumVariantId, GeneralConstId, HasModule as _, StaticId, - expr_store::{Body, HygieneId, path::Path}, - hir::{Expr, ExprId}, + expr_store::{HygieneId, path::Path}, + hir::Expr, resolver::{Resolver, ValueNs}, type_ref::LiteralConstRef, }; @@ -19,13 +19,12 @@ use crate::{ 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}; +use super::mir::{MirEvalError, MirLowerError, interpret_mir, pad16}; /// Extension trait for [`Const`] pub trait ConstExt { @@ -56,12 +55,12 @@ impl ConstExt for Const { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstEvalError { - MirLowerError(MirLowerError), - MirEvalError(MirEvalError), +pub enum ConstEvalError<'db> { + MirLowerError(MirLowerError<'db>), + MirEvalError(MirEvalError<'db>), } -impl ConstEvalError { +impl ConstEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -80,8 +79,8 @@ impl ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirLowerError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirLowerError<'db>) -> Self { match value { MirLowerError::ConstEvalError(_, e) => *e, _ => ConstEvalError::MirLowerError(value), @@ -89,8 +88,8 @@ impl From for ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirEvalError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirEvalError<'db>) -> Self { ConstEvalError::MirEvalError(value) } } @@ -225,35 +224,35 @@ pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option { } } -pub(crate) fn const_eval_cycle_result( - _: &dyn HirDatabase, +pub(crate) fn const_eval_cycle_result<'db>( + _: &'db dyn HirDatabase, _: GeneralConstId, _: Substitution, - _: Option>>, -) -> Result { + _: Option>>, +) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } -pub(crate) fn const_eval_static_cycle_result( - _: &dyn HirDatabase, +pub(crate) fn const_eval_static_cycle_result<'db>( + _: &'db dyn HirDatabase, _: StaticId, -) -> Result { +) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } -pub(crate) fn const_eval_discriminant_cycle_result( - _: &dyn HirDatabase, +pub(crate) fn const_eval_discriminant_cycle_result<'db>( + _: &'db dyn HirDatabase, _: EnumVariantId, -) -> Result { +) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } -pub(crate) fn const_eval_query( - db: &dyn HirDatabase, +pub(crate) fn const_eval_query<'db>( + db: &'db dyn HirDatabase, def: GeneralConstId, subst: Substitution, - trait_env: Option>>, -) -> Result { + trait_env: Option>>, +) -> Result> { let body = match def { GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? @@ -267,10 +266,10 @@ pub(crate) fn const_eval_query( Ok(c) } -pub(crate) fn const_eval_static_query( - db: &dyn HirDatabase, +pub(crate) fn const_eval_static_query<'db>( + db: &'db dyn HirDatabase, def: StaticId, -) -> Result { +) -> Result> { let body = db.monomorphized_mir_body( def.into(), Substitution::empty(Interner), @@ -280,10 +279,10 @@ pub(crate) fn const_eval_static_query( Ok(c) } -pub(crate) fn const_eval_discriminant_variant( - db: &dyn HirDatabase, +pub(crate) fn const_eval_discriminant_variant<'db>( + db: &'db dyn HirDatabase, variant_id: EnumVariantId, -) -> Result { +) -> Result> { let def = variant_id.into(); let body = db.body(def); let loc = variant_id.lookup(db); @@ -317,44 +316,5 @@ pub(crate) fn const_eval_discriminant_variant( 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( - expr: ExprId, - mode: ParamLoweringMode, - ctx: &mut InferenceContext<'_>, - debruijn: DebruijnIndex, -) -> Const { - let db = ctx.db; - let infer = ctx.fixme_resolve_all_clone(); - 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()); - } - if let Expr::Path(p) = &ctx.body[expr] { - let resolver = &ctx.resolver; - if let Some(c) = - path_to_const(db, resolver, p, mode, || ctx.generics(), debruijn, infer[expr].clone()) - { - return c; - } - } - if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) - && let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) - { - return result; - } - unknown_const(infer[expr].clone()) -} - #[cfg(test)] mod tests; 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 1586846bbe58d..5a214eabcdbd4 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 @@ -21,7 +21,7 @@ use super::{ mod intrinsics; -fn simplify(e: ConstEvalError) -> ConstEvalError { +fn simplify(e: ConstEvalError<'_>) -> ConstEvalError<'_> { match e { ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => { simplify(ConstEvalError::MirEvalError(*e)) @@ -33,7 +33,7 @@ fn simplify(e: ConstEvalError) -> ConstEvalError { #[track_caller] fn check_fail( #[rust_analyzer::rust_fixture] ra_fixture: &str, - error: impl FnOnce(ConstEvalError) -> bool, + error: impl FnOnce(ConstEvalError<'_>) -> bool, ) { let (db, file_id) = TestDB::with_single_file(ra_fixture); salsa::attach(&db, || match eval_goal(&db, file_id) { @@ -100,7 +100,7 @@ fn check_answer( }); } -fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { +fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); let display_target = @@ -117,7 +117,7 @@ fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { err } -fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result { +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); 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 155f1336e41d4..2509ba2ef2603 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 @@ -178,10 +178,10 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< } } -pub(crate) fn const_eval_discriminant_variant( - db: &dyn HirDatabase, +pub(crate) fn const_eval_discriminant_variant<'db>( + db: &'db dyn HirDatabase, variant_id: EnumVariantId, -) -> Result { +) -> Result> { let interner = DbInterner::new_with(db, None, None); let def = variant_id.into(); let body = db.body(def); @@ -220,7 +220,7 @@ pub(crate) fn const_eval_discriminant_variant( // 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> { +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.fixme_resolve_all_clone(); fn has_closure(body: &Body, expr: ExprId) -> bool { @@ -233,17 +233,11 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) } 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)); + return unknown_const(infer[expr]); } 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), - ) { + if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) { return c; } } @@ -252,5 +246,5 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) { return result.to_nextsolver(interner); } - unknown_const(infer[expr].to_nextsolver(interner)) + unknown_const(infer[expr]) } 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 71fb3d44fb707..82d17cc618cd2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -32,62 +32,71 @@ use crate::{ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::infer::infer_query)] #[salsa::cycle(cycle_result = crate::infer::infer_cycle_result)] - fn infer(&self, def: DefWithBodyId) -> Arc; + fn infer<'db>(&'db self, def: DefWithBodyId) -> Arc>; // region:mir #[salsa::invoke(crate::mir::mir_body_query)] #[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)] - fn mir_body(&self, def: DefWithBodyId) -> Result, MirLowerError>; + fn mir_body<'db>(&'db self, def: DefWithBodyId) -> Result, MirLowerError<'db>>; #[salsa::invoke(crate::mir::mir_body_for_closure_query)] - fn mir_body_for_closure(&self, def: InternedClosureId) -> Result, MirLowerError>; + fn mir_body_for_closure<'db>( + &'db self, + def: InternedClosureId, + ) -> Result, MirLowerError<'db>>; #[salsa::invoke(crate::mir::monomorphized_mir_body_query)] #[salsa::cycle(cycle_result = crate::mir::monomorphized_mir_body_cycle_result)] - fn monomorphized_mir_body( - &self, + fn monomorphized_mir_body<'db>( + &'db self, def: DefWithBodyId, subst: Substitution, - env: Arc>, - ) -> Result, MirLowerError>; + env: Arc>, + ) -> Result, MirLowerError<'db>>; #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] - fn monomorphized_mir_body_for_closure( - &self, + fn monomorphized_mir_body_for_closure<'db>( + &'db self, def: InternedClosureId, subst: Substitution, - env: Arc>, - ) -> Result, MirLowerError>; + env: Arc>, + ) -> Result, MirLowerError<'db>>; #[salsa::invoke(crate::mir::borrowck_query)] #[salsa::lru(2024)] - fn borrowck(&self, def: DefWithBodyId) -> Result, MirLowerError>; + fn borrowck<'db>( + &'db self, + def: DefWithBodyId, + ) -> Result, MirLowerError<'db>>; #[salsa::invoke(crate::consteval::const_eval_query)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_cycle_result)] - fn const_eval( - &self, + fn const_eval<'db>( + &'db self, def: GeneralConstId, subst: Substitution, - trait_env: Option>>, - ) -> Result; + trait_env: Option>>, + ) -> Result>; #[salsa::invoke(crate::consteval::const_eval_static_query)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)] - fn const_eval_static(&self, def: StaticId) -> Result; + fn const_eval_static<'db>(&'db self, def: StaticId) -> Result>; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)] - fn const_eval_discriminant(&self, def: EnumVariantId) -> Result; + fn const_eval_discriminant<'db>( + &'db self, + def: EnumVariantId, + ) -> Result>; #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] - fn lookup_impl_method( - &self, - env: Arc>, + fn lookup_impl_method<'db>( + &'db self, + env: Arc>, func: FunctionId, - fn_subst: Substitution, - ) -> (FunctionId, Substitution); + fn_subst: crate::next_solver::GenericArgs<'db>, + ) -> (FunctionId, crate::next_solver::GenericArgs<'db>); // endregion:mir @@ -370,6 +379,23 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: GenericDefId, ) -> crate::lower_nextsolver::GenericPredicates<'db>; + + #[salsa::invoke(crate::lower_nextsolver::generic_defaults_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_defaults_with_diagnostics_cycle_result)] + fn generic_defaults_ns_with_diagnostics<'db>( + &'db self, + def: GenericDefId, + ) -> (crate::lower_nextsolver::GenericDefaults<'db>, Diagnostics); + + /// This returns an empty list if no parameter has default. + /// + /// The binders of the returned defaults are only up to (not including) this parameter. + #[salsa::invoke(crate::lower_nextsolver::generic_defaults_query)] + #[salsa::transparent] + fn generic_defaults_ns<'db>( + &'db self, + def: GenericDefId, + ) -> crate::lower_nextsolver::GenericDefaults<'db>; } #[test] 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 d05814e0e7e40..7b6fb994ecaf5 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 @@ -23,6 +23,8 @@ use tracing::debug; use triomphe::Arc; use typed_arena::Arena; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind, db::HirDatabase, @@ -74,8 +76,16 @@ impl BodyValidationDiagnostic { let infer = db.infer(owner); let body = db.body(owner); let env = db.trait_environment_for_body(owner); - let mut validator = - ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints, env }; + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let mut validator = ExprValidator { + owner, + body, + infer, + diagnostics: Vec::new(), + validate_lints, + env, + interner, + }; validator.validate_body(db); validator.diagnostics } @@ -84,10 +94,11 @@ impl BodyValidationDiagnostic { struct ExprValidator<'db> { owner: DefWithBodyId, body: Arc, - infer: Arc, + infer: Arc>, env: Arc>, diagnostics: Vec, validate_lints: bool, + interner: DbInterner<'db>, } impl<'db> ExprValidator<'db> { @@ -175,7 +186,7 @@ impl<'db> ExprValidator<'db> { } if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) { - checker.prev_receiver_ty = Some(receiver_ty.clone()); + checker.prev_receiver_ty = Some(receiver_ty.to_chalk(self.interner)); } } } @@ -190,6 +201,7 @@ impl<'db> ExprValidator<'db> { let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else { return; }; + let scrut_ty = scrut_ty.to_chalk(self.interner); if scrut_ty.contains_unknown() { return; } @@ -205,6 +217,7 @@ impl<'db> ExprValidator<'db> { let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else { return; }; + let pat_ty = pat_ty.to_chalk(self.interner); if pat_ty.contains_unknown() { return; } @@ -222,7 +235,7 @@ impl<'db> ExprValidator<'db> { if (pat_ty == scrut_ty || scrut_ty .as_reference() - .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) + .map(|(match_expr_ty, ..)| *match_expr_ty == pat_ty) .unwrap_or(false)) && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer) { @@ -264,7 +277,7 @@ impl<'db> ExprValidator<'db> { match_expr, uncovered_patterns: missing_match_arms( &cx, - scrut_ty, + &scrut_ty, witnesses, m_arms.is_empty(), self.owner.krate(db), @@ -298,10 +311,12 @@ impl<'db> ExprValidator<'db> { ); 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 matches!(adt.0, AdtId::UnionId(_)) => false, - _ => self.is_known_valid_scrutinee(*expr, db), - }, + Expr::Field { expr, .. } => { + match self.infer.type_of_expr[*expr].to_chalk(self.interner).kind(Interner) { + 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), Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db), Expr::Missing => false, @@ -327,6 +342,7 @@ impl<'db> ExprValidator<'db> { } let Some(initializer) = initializer else { continue }; let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue }; + let ty = ty.to_chalk(self.interner); if ty.contains_unknown() { continue; } @@ -357,7 +373,7 @@ impl<'db> ExprValidator<'db> { pat, uncovered_patterns: missing_match_arms( &cx, - ty, + &ty, witnesses, false, self.owner.krate(db), @@ -542,7 +558,7 @@ impl FilterMapNextChecker { pub fn record_literal_missing_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: ExprId, expr: &Expr, ) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { @@ -572,7 +588,7 @@ pub fn record_literal_missing_fields( pub fn record_pattern_missing_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: PatId, pat: &Pat, ) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { @@ -600,8 +616,8 @@ pub fn record_pattern_missing_fields( Some((variant_def, missed_fields, exhaustive)) } -fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool { - fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) { +fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult<'_>) -> bool { + fn walk(pat: PatId, body: &Body, infer: &InferenceResult<'_>, has_type_mismatches: &mut bool) { match infer.type_mismatch_for_pat(pat) { Some(_) => *has_type_mismatches = true, None if *has_type_mismatches => (), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index e803b56a1ed8f..af541ffa342ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -20,6 +20,8 @@ use hir_expand::name::Name; use span::Edition; use stdx::{always, never}; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, db::HirDatabase, @@ -93,16 +95,21 @@ pub(crate) enum PatKind { }, } -pub(crate) struct PatCtxt<'a> { - db: &'a dyn HirDatabase, - infer: &'a InferenceResult, - body: &'a Body, +pub(crate) struct PatCtxt<'db> { + db: &'db dyn HirDatabase, + infer: &'db InferenceResult<'db>, + body: &'db Body, pub(crate) errors: Vec, + interner: DbInterner<'db>, } impl<'a> PatCtxt<'a> { - pub(crate) fn new(db: &'a dyn HirDatabase, infer: &'a InferenceResult, body: &'a Body) -> Self { - Self { db, infer, body, errors: Vec::new() } + pub(crate) fn new( + db: &'a dyn HirDatabase, + infer: &'a InferenceResult<'a>, + body: &'a Body, + ) -> Self { + Self { db, infer, body, errors: Vec::new(), interner: DbInterner::new_with(db, None, None) } } pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat { @@ -115,14 +122,14 @@ impl<'a> PatCtxt<'a> { self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold( unadjusted_pat, |subpattern, ref_ty| Pat { - ty: ref_ty.clone(), + ty: ref_ty.to_chalk(self.interner).clone(), kind: Box::new(PatKind::Deref { subpattern }), }, ) } fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat { - let mut ty = &self.infer[pat]; + let mut ty = self.infer[pat].to_chalk(self.interner); let variant = self.infer.variant_resolution_for_pat(pat); let kind = match self.body[pat] { @@ -140,7 +147,7 @@ impl<'a> PatCtxt<'a> { _ => { never!("unexpected type for tuple pattern: {:?}", ty); self.errors.push(PatternError::UnexpectedType); - return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; + return Pat { ty, kind: PatKind::Wild.into() }; } }; let subpatterns = self.lower_tuple_subpats(args, arity, ellipsis); @@ -149,10 +156,10 @@ impl<'a> PatCtxt<'a> { hir_def::hir::Pat::Bind { id, subpat, .. } => { let bm = self.infer.binding_modes[pat]; - ty = &self.infer[id]; + ty = self.infer[id].to_chalk(self.interner); let name = &self.body[id].name; match (bm, ty.kind(Interner)) { - (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty, + (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty.clone(), (BindingMode::Ref(_), _) => { never!( "`ref {}` has wrong type {:?}", @@ -170,7 +177,7 @@ impl<'a> PatCtxt<'a> { hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { let expected_len = variant.unwrap().fields(self.db).fields().len(); let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis); - self.lower_variant_or_leaf(pat, ty, subpatterns) + self.lower_variant_or_leaf(pat, &ty, subpatterns) } hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => { @@ -186,7 +193,7 @@ impl<'a> PatCtxt<'a> { }) .collect(); match subpatterns { - Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns), + Some(subpatterns) => self.lower_variant_or_leaf(pat, &ty, subpatterns), None => { self.errors.push(PatternError::MissingField); PatKind::Wild @@ -271,12 +278,12 @@ impl<'a> PatCtxt<'a> { } fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat { - let ty = &self.infer[pat]; + let ty = self.infer[pat].to_chalk(self.interner); let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) }; match self.infer.variant_resolution_for_pat(pat) { - Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())), + Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, &ty, Vec::new())), None => { self.errors.push(PatternError::UnresolvedVariant); pat_from_kind(PatKind::Wild) 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 3c78f5ef38704..31100e17f8465 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,8 @@ use hir_def::{ }; use span::Edition; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::utils::TargetFeatureIsSafeInTarget; use crate::{ InferenceResult, Interner, TargetFeatures, TyExt, TyKind, @@ -96,9 +98,9 @@ enum UnsafeDiagnostic { DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock }, } -pub fn unsafe_operations_for_body( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn unsafe_operations_for_body<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, def: DefWithBodyId, body: &Body, callback: &mut dyn FnMut(ExprOrPatId), @@ -115,9 +117,9 @@ pub fn unsafe_operations_for_body( } } -pub fn unsafe_operations( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn unsafe_operations<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, def: DefWithBodyId, body: &Body, current: ExprId, @@ -135,7 +137,7 @@ pub fn unsafe_operations( struct UnsafeVisitor<'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db Body, resolver: Resolver<'db>, def: DefWithBodyId, @@ -149,12 +151,13 @@ struct UnsafeVisitor<'db> { /// 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: TargetFeatureIsSafeInTarget, + interner: DbInterner<'db>, } impl<'db> UnsafeVisitor<'db> { fn new( db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db Body, def: DefWithBodyId, unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic), @@ -183,6 +186,7 @@ impl<'db> UnsafeVisitor<'db> { def_target_features, edition, target_feature_is_safe, + interner: DbInterner::new_with(db, None, None), } } @@ -285,7 +289,7 @@ impl<'db> UnsafeVisitor<'db> { let inside_assignment = mem::replace(&mut self.inside_assignment, false); match expr { &Expr::Call { callee, .. } => { - let callee = &self.infer[callee]; + let callee = self.infer[callee].to_chalk(self.interner); if let Some(func) = callee.as_fn_def(self.db) { self.check_call(current, func); } @@ -338,7 +342,7 @@ impl<'db> UnsafeVisitor<'db> { } } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &self.infer[*expr].kind(Interner) { + if let TyKind::Raw(..) = &self.infer[*expr].to_chalk(self.interner).kind(Interner) { self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref); } } 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 e11ce51cdb8f0..d79069901ebb8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1545,14 +1545,17 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { 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#{:?}}}", chalk_id.0.index()); + return write!( + f, + "{{closure#{:?}}}", + salsa::plumbing::AsId::as_id(&id).index() + ); } ClosureStyle::ClosureWithSubst => { - write!(f, "{{closure#{:?}}}", chalk_id.0.index())?; + write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?; return hir_fmt_generics(f, substs.as_slice(Interner), None, None); } _ => (), @@ -1561,7 +1564,7 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { if let Some(sig) = sig { let InternedClosure(def, _) = db.lookup_intern_closure(id); let infer = db.infer(def); - let (_, kind) = infer.closure_info(&chalk_id); + let (_, kind) = infer.closure_info(id); match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, ClosureStyle::RANotation => write!(f, "|")?, 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 413f70532a548..0618fd17d55d0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -8,7 +8,7 @@ use stdx::never; use triomphe::Arc; use crate::next_solver::DbInterner; -use crate::next_solver::mapping::NextSolverToChalk; +use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, @@ -120,13 +120,20 @@ pub(crate) fn has_drop_glue( } TyKind::Slice(ty) => db.has_drop_glue(ty.clone(), env), TyKind::Closure(closure_id, subst) => { - let owner = db.lookup_intern_closure((*closure_id).into()).0; + let closure_id = (*closure_id).into(); + let owner = db.lookup_intern_closure(closure_id).0; let infer = db.infer(owner); let (captures, _) = infer.closure_info(closure_id); let env = db.trait_environment_for_body(owner); + let interner = DbInterner::conjure(); captures .iter() - .map(|capture| db.has_drop_glue(capture.ty(db, subst), env.clone())) + .map(|capture| { + db.has_drop_glue( + capture.ty(db, subst.to_nextsolver(interner)).to_chalk(interner), + env.clone(), + ) + }) .max() .unwrap_or(DropGlue::None) } 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 0282b7a936324..72498681aca50 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -28,19 +28,11 @@ pub(crate) mod unify; use std::{cell::OnceCell, convert::identity, iter, ops::Index}; use base_db::Crate; -use chalk_ir::{ - DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance, - cast::Cast, - fold::TypeFoldable, - interner::HasInterner, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; use either::Either; use hir_def::{ AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::{LangItem, LangItemTarget, lang_item}, @@ -53,18 +45,19 @@ use hir_expand::{mod_path::ModPath, name::Name}; use indexmap::IndexSet; use intern::sym; use la_arena::{ArenaMap, Entry}; +use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::Ty as _; -use stdx::{always, never}; +use rustc_type_ir::{ + AliasTyKind, Flags, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, + inherent::{AdtDef, IntoKind, Region as _, SliceLike, Ty as _}, +}; +use stdx::never; use triomphe::Arc; use crate::{ - AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, - IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, - PathLoweringDiagnostic, ProjectionTy, Substitution, TargetFeatures, TraitEnvironment, Ty, - TyBuilder, TyExt, - db::{HirDatabase, InternedClosureId}, - fold_tys, + ImplTraitId, IncorrectGenericsLenKind, Interner, PathLoweringDiagnostic, TargetFeatures, + TraitEnvironment, + db::{HirDatabase, InternedClosureId, InternedOpaqueTyId}, generics::Generics, infer::{ coerce::{CoerceMany, DynamicCoerceMany}, @@ -72,16 +65,22 @@ use crate::{ expr::ExprIsRead, unify::InferenceTable, }, - lower::{ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic}, + lower::diagnostics::TyLoweringDiagnostic, + lower_nextsolver::{ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind}, mir::MirSpan, next_solver::{ - self, DbInterner, - infer::{DefineOpaqueTypes, traits::ObligationCause}, + AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, Ty, TyKind, + Tys, + abi::Safety, + fold::fold_tys, + infer::{ + DefineOpaqueTypes, + traits::{Obligation, ObligationCause}, + }, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, - static_lifetime, to_assoc_type_id, traits::FnTrait, - utils::{TargetFeatureIsSafeInTarget, UnevaluatedConstEvaluatorFolder}, + utils::TargetFeatureIsSafeInTarget, }; // This lint has a false positive here. See the link below for details. @@ -96,7 +95,7 @@ use cast::{CastCheck, CastError}; pub(crate) use closure::analysis::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. -pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { +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); @@ -109,30 +108,28 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc 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), + ctx.return_ty = match db.enum_signature(v.lookup(db).parent).variant_body_type() { + hir_def::layout::IntegerType::Pointer(signed) => match signed { + true => ctx.types.isize, + false => ctx.types.usize, + }, + hir_def::layout::IntegerType::Fixed(size, signed) => match signed { + true => match size { + Integer::I8 => ctx.types.i8, + Integer::I16 => ctx.types.i16, + Integer::I32 => ctx.types.i32, + Integer::I64 => ctx.types.i64, + Integer::I128 => ctx.types.i128, }, - 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, - }), + false => match size { + Integer::I8 => ctx.types.u8, + Integer::I16 => ctx.types.u16, + Integer::I32 => ctx.types.u32, + Integer::I64 => ctx.types.u64, + Integer::I128 => ctx.types.u128, }, }, - ); + }; } } @@ -159,8 +156,14 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc Arc { - Arc::new(InferenceResult { has_errors: true, ..Default::default() }) +pub(crate) fn infer_cycle_result( + db: &dyn HirDatabase, + _: DefWithBodyId, +) -> Arc> { + Arc::new(InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)) + }) } /// Fully normalize all the types found within `ty` in context of `owner` body definition. @@ -168,20 +171,24 @@ pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc>, ty: Ty) -> Ty { +pub(crate) fn normalize( + db: &dyn HirDatabase, + trait_env: Arc>, + ty: crate::Ty, +) -> crate::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 // when the bug in chalk becomes fixed. - if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) - && !matches!(ty.kind(Interner), TyKind::Array(..)) + if !ty.data(Interner).flags.intersects(crate::TypeFlags::HAS_PROJECTION) + && !matches!(ty.kind(Interner), crate::TyKind::Array(..)) { return ty; } let mut table = unify::InferenceTable::new(db, trait_env); - let ty_with_vars = table.normalize_associated_types_in(ty); + let ty_with_vars = table.normalize_associated_types_in(ty.to_nextsolver(table.interner())); table.select_obligations_where_possible(); - table.resolve_completely(ty_with_vars) + table.resolve_completely(ty_with_vars).to_chalk(table.interner()) } /// Binding modes inferred for patterns. @@ -203,14 +210,6 @@ 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>>, -} - #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum InferenceTyDiagnosticSource { /// Diagnostics that come from types in the body. @@ -219,12 +218,8 @@ pub enum InferenceTyDiagnosticSource { Signature, } -#[derive(Debug)] -pub(crate) struct TypeError; -pub(crate) type InferResult<'db, T> = Result, TypeError>; - #[derive(Debug, PartialEq, Eq, Clone)] -pub enum InferenceDiagnostic { +pub enum InferenceDiagnostic<'db> { NoSuchField { field: ExprOrPatId, private: Option, @@ -240,16 +235,16 @@ pub enum InferenceDiagnostic { }, UnresolvedField { expr: ExprId, - receiver: Ty, + receiver: Ty<'db>, name: Name, method_with_same_name_exists: bool, }, UnresolvedMethodCall { expr: ExprId, - receiver: Ty, + receiver: Ty<'db>, name: Name, /// Contains the type the field resolves to - field_with_same_name: Option, + field_with_same_name: Option>, assoc_func_with_same_name: Option, }, UnresolvedAssocItem { @@ -276,21 +271,21 @@ pub enum InferenceDiagnostic { }, ExpectedFunction { call_expr: ExprId, - found: Ty, + found: Ty<'db>, }, TypedHole { expr: ExprId, - expected: Ty, + expected: Ty<'db>, }, CastToUnsized { expr: ExprId, - cast_ty: Ty, + cast_ty: Ty<'db>, }, InvalidCast { expr: ExprId, error: CastError, - expr_ty: Ty, - cast_ty: Ty, + expr_ty: Ty<'db>, + cast_ty: Ty<'db>, }, TyDiagnostic { source: InferenceTyDiagnosticSource, @@ -318,29 +313,11 @@ pub enum InferenceDiagnostic { /// A mismatch between an expected and an inferred type. #[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TypeMismatch { - pub expected: Ty, - pub actual: Ty, +pub struct TypeMismatch<'db> { + pub expected: Ty<'db>, + pub actual: Ty<'db>, } -#[derive(Clone, PartialEq, Eq, Debug)] -struct InternedStandardTypes { - unknown: Ty, - bool_: Ty, - unit: Ty, - never: Ty, -} - -impl Default for InternedStandardTypes { - fn default() -> Self { - InternedStandardTypes { - unknown: TyKind::Error.intern(Interner), - bool_: TyKind::Scalar(Scalar::Bool).intern(Interner), - unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), - never: TyKind::Never.intern(Interner), - } - } -} /// Represents coercing a value to a different type of value. /// /// We transform values by following a number of `Adjust` steps in order. @@ -382,14 +359,14 @@ impl Default for InternedStandardTypes { /// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> /// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Adjustment { - pub kind: Adjust, - pub target: Ty, +pub struct Adjustment<'db> { + pub kind: Adjust<'db>, + pub target: Ty<'db>, } -impl Adjustment { - pub fn borrow(m: Mutability, ty: Ty, lt: Lifetime) -> Self { - let ty = TyKind::Ref(m, lt.clone(), ty).intern(Interner); +impl<'db> Adjustment<'db> { + pub fn borrow(interner: DbInterner<'db>, m: Mutability, ty: Ty<'db>, lt: Region<'db>) -> Self { + let ty = Ty::new_ref(interner, lt, ty, m); Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(lt, m)), target: ty } } } @@ -415,13 +392,13 @@ pub(crate) enum AllowTwoPhase { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum Adjust { +pub enum Adjust<'db> { /// Go from ! to any type. NeverToAny, /// Dereference once, producing a place. Deref(Option), /// Take the address and produce either a `&` or `*` pointer. - Borrow(AutoBorrow), + Borrow(AutoBorrow<'db>), Pointer(PointerCast), } @@ -433,14 +410,14 @@ pub enum Adjust { pub struct OverloadedDeref(pub Option); #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum AutoBorrow { +pub enum AutoBorrow<'db> { /// Converts from T to &T. - Ref(Lifetime, Mutability), + Ref(Region<'db>, Mutability), /// Converts from T to *T. RawPtr(Mutability), } -impl AutoBorrow { +impl<'db> AutoBorrow<'db> { fn mutability(&self) -> Mutability { let (AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) = self; *m @@ -484,41 +461,41 @@ pub enum PointerCast { /// When you add a field that stores types (including `Substitution` and the like), don't forget /// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must /// not appear in the final inference result. -#[derive(Clone, PartialEq, Eq, Debug, Default)] -pub struct InferenceResult { +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct InferenceResult<'db> { /// For each method call expr, records the function it resolves to. - method_resolutions: FxHashMap, + method_resolutions: FxHashMap)>, /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap>, /// For each struct literal or pattern, records the variant it resolves to. variant_resolutions: FxHashMap, /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, + assoc_resolutions: FxHashMap)>, /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of /// that which allows us to resolve a [`TupleFieldId`]s type. - tuple_field_access_types: FxHashMap, + tuple_field_access_types: FxHashMap>, /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. - diagnostics: Vec, - pub(crate) type_of_expr: ArenaMap, + diagnostics: Vec>, + pub(crate) type_of_expr: ArenaMap>, /// For each pattern record the type it resolves to. /// /// **Note**: When a pattern type is resolved it may still contain /// unresolved or missing subpatterns or subpatterns of mismatched types. - pub(crate) type_of_pat: ArenaMap, - pub(crate) type_of_binding: ArenaMap, - pub(crate) type_of_rpit: ArenaMap, - type_mismatches: FxHashMap, + pub(crate) type_of_pat: ArenaMap>, + pub(crate) type_of_binding: ArenaMap>, + pub(crate) type_of_rpit: ArenaMap, Ty<'db>>, + type_mismatches: FxHashMap>, /// Whether there are any type-mismatching errors in the result. // FIXME: This isn't as useful as initially thought due to us falling back placeholders to // `TyKind::Error`. // Which will then mark this field. pub(crate) has_errors: bool, - /// Interned common types to return references to. - // FIXME: Move this into `InferenceContext` - standard_types: InternedStandardTypes, + /// Interned `Error` type to return references to. + // FIXME: Remove this. + error_ty: Ty<'db>, /// Stores the types which were implicitly dereferenced in pattern binding modes. - pub(crate) pat_adjustments: FxHashMap>, + pub(crate) pat_adjustments: FxHashMap>>, /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings. /// /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an @@ -533,16 +510,40 @@ pub struct InferenceResult { /// ``` /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`. pub(crate) binding_modes: ArenaMap, - pub(crate) expr_adjustments: FxHashMap>, - pub(crate) closure_info: FxHashMap, FnTrait)>, + pub(crate) expr_adjustments: FxHashMap]>>, + pub(crate) closure_info: FxHashMap>, FnTrait)>, // FIXME: remove this field pub mutated_bindings_in_closure: FxHashSet, pub(crate) coercion_casts: FxHashSet, } -impl InferenceResult { - pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { - self.method_resolutions.get(&expr).cloned() +impl<'db> InferenceResult<'db> { + fn new(error_ty: Ty<'db>) -> Self { + Self { + method_resolutions: Default::default(), + field_resolutions: Default::default(), + variant_resolutions: Default::default(), + assoc_resolutions: Default::default(), + tuple_field_access_types: Default::default(), + diagnostics: Default::default(), + type_of_expr: Default::default(), + type_of_pat: Default::default(), + type_of_binding: Default::default(), + type_of_rpit: Default::default(), + type_mismatches: Default::default(), + has_errors: Default::default(), + error_ty, + pat_adjustments: Default::default(), + binding_modes: Default::default(), + expr_adjustments: Default::default(), + closure_info: Default::default(), + mutated_bindings_in_closure: Default::default(), + coercion_casts: Default::default(), + } + } + + pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, GenericArgs<'db>)> { + self.method_resolutions.get(&expr).copied() } pub fn field_resolution(&self, expr: ExprId) -> Option> { self.field_resolutions.get(&expr).copied() @@ -559,46 +560,49 @@ impl InferenceResult { ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id), } } - pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> { - self.assoc_resolutions.get(&id.into()).cloned() + pub fn assoc_resolutions_for_expr( + &self, + id: ExprId, + ) -> Option<(AssocItemId, GenericArgs<'db>)> { + self.assoc_resolutions.get(&id.into()).copied() } - pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> { - self.assoc_resolutions.get(&id.into()).cloned() + pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, GenericArgs<'db>)> { + self.assoc_resolutions.get(&id.into()).copied() } pub fn assoc_resolutions_for_expr_or_pat( &self, id: ExprOrPatId, - ) -> Option<(AssocItemId, Substitution)> { + ) -> Option<(AssocItemId, GenericArgs<'db>)> { match id { ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id), ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), } } - pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { + pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch<'db>> { self.type_mismatches.get(&expr.into()) } - pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> { + pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch<'db>> { self.type_mismatches.get(&pat.into()) } - pub fn type_mismatches(&self) -> impl Iterator { + pub fn type_mismatches(&self) -> impl Iterator)> { self.type_mismatches.iter().map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch)) } - pub fn expr_type_mismatches(&self) -> impl Iterator { + pub fn expr_type_mismatches(&self) -> impl Iterator)> { self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { ExprOrPatId::ExprId(expr) => Some((expr, mismatch)), _ => None, }) } - pub fn closure_info(&self, closure: &ClosureId) -> &(Vec, FnTrait) { - self.closure_info.get(closure).unwrap() + pub fn closure_info(&self, closure: InternedClosureId) -> &(Vec>, FnTrait) { + self.closure_info.get(&closure).unwrap() } - pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> { + pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option> { match id { - ExprOrPatId::ExprId(id) => self.type_of_expr.get(id), - ExprOrPatId::PatId(id) => self.type_of_pat.get(id), + ExprOrPatId::ExprId(id) => self.type_of_expr.get(id).copied(), + ExprOrPatId::PatId(id) => self.type_of_pat.get(id).copied(), } } - pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<&Ty> { + pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option> { match self.expr_adjustments.get(&id).and_then(|adjustments| { adjustments .iter() @@ -614,33 +618,33 @@ impl InferenceResult { }) .next_back() }) { - Some(adjustment) => Some(&adjustment.target), - None => self.type_of_expr.get(id), + Some(adjustment) => Some(adjustment.target), + None => self.type_of_expr.get(id).copied(), } } - pub fn type_of_pat_with_adjust(&self, id: PatId) -> Option<&Ty> { + pub fn type_of_pat_with_adjust(&self, id: PatId) -> Option> { match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { - adjusted @ Some(_) => adjusted, - None => self.type_of_pat.get(id), + Some(adjusted) => Some(*adjusted), + None => self.type_of_pat.get(id).copied(), } } pub fn is_erroneous(&self) -> bool { self.has_errors && self.type_of_expr.iter().count() == 0 } - pub fn diagnostics(&self) -> &[InferenceDiagnostic] { + pub fn diagnostics(&self) -> &[InferenceDiagnostic<'db>] { &self.diagnostics } - pub fn tuple_field_access_type(&self, id: TupleId) -> &Substitution { - &self.tuple_field_access_types[&id] + pub fn tuple_field_access_type(&self, id: TupleId) -> Tys<'db> { + self.tuple_field_access_types[&id] } - pub fn pat_adjustment(&self, id: PatId) -> Option<&[Ty]> { + pub fn pat_adjustment(&self, id: PatId) -> Option<&[Ty<'db>]> { self.pat_adjustments.get(&id).map(|it| &**it) } - pub fn expr_adjustment(&self, id: ExprId) -> Option<&[Adjustment]> { + pub fn expr_adjustment(&self, id: ExprId) -> Option<&[Adjustment<'db>]> { self.expr_adjustments.get(&id).map(|it| &**it) } @@ -649,83 +653,138 @@ impl InferenceResult { } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn expression_types(&self) -> impl Iterator { - self.type_of_expr.iter() + pub fn expression_types(&self) -> impl Iterator)> { + self.type_of_expr.iter().map(|(k, v)| (k, *v)) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn pattern_types(&self) -> impl Iterator { - self.type_of_pat.iter() + pub fn pattern_types(&self) -> impl Iterator)> { + self.type_of_pat.iter().map(|(k, v)| (k, *v)) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn binding_types(&self) -> impl Iterator { - self.type_of_binding.iter() + pub fn binding_types(&self) -> impl Iterator)> { + self.type_of_binding.iter().map(|(k, v)| (k, *v)) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn return_position_impl_trait_types(&self) -> impl Iterator { - self.type_of_rpit.iter() + pub fn return_position_impl_trait_types( + &self, + ) -> impl Iterator, Ty<'db>)> { + self.type_of_rpit.iter().map(|(k, v)| (k, *v)) } } -impl Index for InferenceResult { - type Output = Ty; +impl<'db> Index for InferenceResult<'db> { + type Output = Ty<'db>; - fn index(&self, expr: ExprId) -> &Ty { - self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown) + fn index(&self, expr: ExprId) -> &Ty<'db> { + self.type_of_expr.get(expr).unwrap_or(&self.error_ty) } } -impl Index for InferenceResult { - type Output = Ty; +impl<'db> Index for InferenceResult<'db> { + type Output = Ty<'db>; - fn index(&self, pat: PatId) -> &Ty { - self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown) + fn index(&self, pat: PatId) -> &Ty<'db> { + self.type_of_pat.get(pat).unwrap_or(&self.error_ty) } } -impl Index for InferenceResult { - type Output = Ty; +impl<'db> Index for InferenceResult<'db> { + type Output = Ty<'db>; - fn index(&self, id: ExprOrPatId) -> &Ty { - self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown) + fn index(&self, id: ExprOrPatId) -> &Ty<'db> { + match id { + ExprOrPatId::ExprId(id) => &self[id], + ExprOrPatId::PatId(id) => &self[id], + } } } -impl Index for InferenceResult { - type Output = Ty; +impl<'db> Index for InferenceResult<'db> { + type Output = Ty<'db>; - fn index(&self, b: BindingId) -> &Ty { - self.type_of_binding.get(b).unwrap_or(&self.standard_types.unknown) + fn index(&self, b: BindingId) -> &Ty<'db> { + self.type_of_binding.get(b).unwrap_or(&self.error_ty) } } #[derive(Debug, Clone)] -struct InternedStandardTypesNextSolver<'db> { - unit: crate::next_solver::Ty<'db>, - never: crate::next_solver::Ty<'db>, - i32: crate::next_solver::Ty<'db>, - f64: crate::next_solver::Ty<'db>, +struct InternedStandardTypes<'db> { + unit: Ty<'db>, + never: Ty<'db>, + char: Ty<'db>, + bool: Ty<'db>, + i8: Ty<'db>, + i16: Ty<'db>, + i32: Ty<'db>, + i64: Ty<'db>, + i128: Ty<'db>, + isize: Ty<'db>, + u8: Ty<'db>, + u16: Ty<'db>, + u32: Ty<'db>, + u64: Ty<'db>, + u128: Ty<'db>, + usize: Ty<'db>, + f16: Ty<'db>, + f32: Ty<'db>, + f64: Ty<'db>, + f128: Ty<'db>, + static_str_ref: Ty<'db>, + error: Ty<'db>, + + re_static: Region<'db>, + re_error: Region<'db>, + + empty_args: GenericArgs<'db>, + empty_tys: Tys<'db>, } -impl<'db> InternedStandardTypesNextSolver<'db> { +impl<'db> InternedStandardTypes<'db> { fn new(interner: DbInterner<'db>) -> Self { + let str = Ty::new(interner, rustc_type_ir::TyKind::Str); + let re_static = Region::new_static(interner); Self { - unit: crate::next_solver::Ty::new_unit(interner), - never: crate::next_solver::Ty::new(interner, crate::next_solver::TyKind::Never), - i32: crate::next_solver::Ty::new_int(interner, rustc_type_ir::IntTy::I32), - f64: crate::next_solver::Ty::new_float(interner, rustc_type_ir::FloatTy::F64), + unit: Ty::new_unit(interner), + never: Ty::new(interner, TyKind::Never), + char: Ty::new(interner, TyKind::Char), + bool: Ty::new(interner, TyKind::Bool), + i8: Ty::new_int(interner, rustc_type_ir::IntTy::I8), + i16: Ty::new_int(interner, rustc_type_ir::IntTy::I16), + i32: Ty::new_int(interner, rustc_type_ir::IntTy::I32), + i64: Ty::new_int(interner, rustc_type_ir::IntTy::I64), + i128: Ty::new_int(interner, rustc_type_ir::IntTy::I128), + isize: Ty::new_int(interner, rustc_type_ir::IntTy::Isize), + u8: Ty::new_uint(interner, rustc_type_ir::UintTy::U8), + u16: Ty::new_uint(interner, rustc_type_ir::UintTy::U16), + u32: Ty::new_uint(interner, rustc_type_ir::UintTy::U32), + u64: Ty::new_uint(interner, rustc_type_ir::UintTy::U64), + u128: Ty::new_uint(interner, rustc_type_ir::UintTy::U128), + usize: Ty::new_uint(interner, rustc_type_ir::UintTy::Usize), + f16: Ty::new_float(interner, rustc_type_ir::FloatTy::F16), + f32: Ty::new_float(interner, rustc_type_ir::FloatTy::F32), + f64: Ty::new_float(interner, rustc_type_ir::FloatTy::F64), + f128: Ty::new_float(interner, rustc_type_ir::FloatTy::F128), + static_str_ref: Ty::new_ref(interner, re_static, str, Mutability::Not), + error: Ty::new_error(interner, ErrorGuaranteed), + + re_static, + re_error: Region::error(interner), + + empty_args: GenericArgs::new_from_iter(interner, []), + empty_tys: Tys::new_from_iter(interner, []), } } } /// The inference context contains all information needed during type inference. #[derive(Clone, Debug)] -pub(crate) struct InferenceContext<'db> { +pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) owner: DefWithBodyId, - pub(crate) body: &'db Body, + pub(crate) body: &'body Body, /// 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>, @@ -735,32 +794,32 @@ pub(crate) struct InferenceContext<'db> { table: unify::InferenceTable<'db>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, - pub(crate) result: InferenceResult, + pub(crate) result: InferenceResult<'db>, tuple_field_accesses_rev: - IndexSet>, + IndexSet, std::hash::BuildHasherDefault>, /// The return type of the function being inferred, the closure or async block if we're /// currently within one. /// /// We might consider using a nested inference context for checking /// closures so we can swap all shared things out at once. - return_ty: Ty, + return_ty: Ty<'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>, /// The resume type and the yield type, respectively, of the coroutine being inferred. - resume_yield_tys: Option<(Ty, Ty)>, + resume_yield_tys: Option<(Ty<'db>, Ty<'db>)>, diverges: Diverges, breakables: Vec>, - types: InternedStandardTypesNextSolver<'db>, + types: InternedStandardTypes<'db>, /// Whether we are inside the pattern of a destructuring assignment. inside_assignment: bool, - deferred_cast_checks: Vec, + deferred_cast_checks: Vec>, // fields related to closure capture - current_captures: Vec, + current_captures: Vec>, /// A stack that has an entry for each projection in the current capture. /// /// For example, in `a.b.c`, we capture the spans of `a`, `a.b`, and `a.b.c`. @@ -771,9 +830,9 @@ pub(crate) struct InferenceContext<'db> { /// 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)>>, + deferred_closures: FxHashMap, Ty<'db>, Vec>, ExprId)>>, - diagnostics: Diagnostics, + diagnostics: Diagnostics<'db>, } #[derive(Clone, Debug)] @@ -820,28 +879,29 @@ fn find_continuable<'a, 'db>( } } -enum ImplTraitReplacingMode { - ReturnPosition(FxHashSet), +enum ImplTraitReplacingMode<'db> { + ReturnPosition(FxHashSet>), TypeAlias, } -impl<'db> InferenceContext<'db> { +impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, owner: DefWithBodyId, - body: &'db Body, + body: &'body Body, resolver: Resolver<'db>, ) -> Self { let trait_env = db.trait_environment_for_body(owner); let table = unify::InferenceTable::new(db, trait_env); + let types = InternedStandardTypes::new(table.interner()); InferenceContext { - types: InternedStandardTypesNextSolver::new(table.interner), + result: InferenceResult::new(types.error), + return_ty: types.error, // set in collect_* calls + types, target_features: OnceCell::new(), generics: OnceCell::new(), - result: InferenceResult::default(), table, tuple_field_accesses_rev: Default::default(), - return_ty: TyKind::Error.intern(Interner), // set in collect_* calls resume_yield_tys: None, return_coercion: None, db, @@ -904,7 +964,7 @@ impl<'db> InferenceContext<'db> { /// Clones `self` and calls `resolve_all()` on it. // FIXME: Remove this. - pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult { + pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult<'db> { let mut ctx = self.clone(); ctx.type_inference_fallback(); @@ -928,7 +988,7 @@ impl<'db> InferenceContext<'db> { // `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(self) -> InferenceResult<'db> { let InferenceContext { mut table, mut result, tuple_field_accesses_rev, diagnostics, .. } = self; @@ -946,7 +1006,7 @@ impl<'db> InferenceContext<'db> { type_of_rpit, type_mismatches, has_errors, - standard_types: _, + error_ty: _, pat_adjustments, binding_modes: _, expr_adjustments, @@ -961,39 +1021,32 @@ impl<'db> InferenceContext<'db> { } = &mut result; for ty in type_of_expr.values_mut() { - *ty = table.resolve_completely(ty.clone()); - *has_errors = *has_errors || ty.contains_unknown(); + *ty = table.resolve_completely(*ty); + *has_errors = *has_errors || ty.references_non_lt_error(); } type_of_expr.shrink_to_fit(); for ty in type_of_pat.values_mut() { - *ty = table.resolve_completely(ty.clone()); - *has_errors = *has_errors || ty.contains_unknown(); + *ty = table.resolve_completely(*ty); + *has_errors = *has_errors || ty.references_non_lt_error(); } type_of_pat.shrink_to_fit(); for ty in type_of_binding.values_mut() { - *ty = table.resolve_completely(ty.clone()); - *has_errors = *has_errors || ty.contains_unknown(); + *ty = table.resolve_completely(*ty); + *has_errors = *has_errors || ty.references_non_lt_error(); } type_of_binding.shrink_to_fit(); for ty in type_of_rpit.values_mut() { - *ty = table.resolve_completely(ty.clone()); - *has_errors = *has_errors || ty.contains_unknown(); + *ty = table.resolve_completely(*ty); + *has_errors = *has_errors || ty.references_non_lt_error(); } type_of_rpit.shrink_to_fit(); *has_errors |= !type_mismatches.is_empty(); - type_mismatches.retain(|_, mismatch| { - mismatch.expected = table.resolve_completely(mismatch.expected.clone()); - mismatch.actual = table.resolve_completely(mismatch.actual.clone()); - chalk_ir::zip::Zip::zip_with( - &mut UnknownMismatch(self.db), - Variance::Invariant, - &mismatch.expected, - &mismatch.actual, - ) - .is_ok() - }); + for mismatch in (*type_mismatches).values_mut() { + mismatch.expected = table.resolve_completely(mismatch.expected); + mismatch.actual = table.resolve_completely(mismatch.actual); + } type_mismatches.shrink_to_fit(); diagnostics.retain_mut(|diagnostic| { use InferenceDiagnostic::*; @@ -1001,23 +1054,23 @@ impl<'db> InferenceContext<'db> { ExpectedFunction { found: ty, .. } | UnresolvedField { receiver: ty, .. } | UnresolvedMethodCall { receiver: ty, .. } => { - *ty = table.resolve_completely(ty.clone()); + *ty = table.resolve_completely(*ty); // FIXME: Remove this when we are on par with rustc in terms of inference - if ty.contains_unknown() { + if ty.references_non_lt_error() { return false; } if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic && let Some(ty) = field_with_same_name { - *ty = table.resolve_completely(ty.clone()); - if ty.contains_unknown() { + *ty = table.resolve_completely(*ty); + if ty.references_non_lt_error() { *field_with_same_name = None; } } } TypedHole { expected: ty, .. } => { - *ty = table.resolve_completely(ty.clone()); + *ty = table.resolve_completely(*ty); } _ => (), } @@ -1025,41 +1078,31 @@ impl<'db> InferenceContext<'db> { }); diagnostics.shrink_to_fit(); for (_, subst) in method_resolutions.values_mut() { - *subst = - table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); - *has_errors = - *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + *subst = table.resolve_completely(*subst); + *has_errors = *has_errors || subst.types().any(|ty| ty.references_non_lt_error()); } method_resolutions.shrink_to_fit(); for (_, subst) in assoc_resolutions.values_mut() { - *subst = - table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); - *has_errors = - *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + *subst = table.resolve_completely(*subst); + *has_errors = *has_errors || subst.types().any(|ty| ty.references_non_lt_error()); } assoc_resolutions.shrink_to_fit(); for adjustment in expr_adjustments.values_mut().flatten() { - adjustment.target = table.resolve_completely(adjustment.target.clone()); - *has_errors = *has_errors || adjustment.target.contains_unknown(); + adjustment.target = table.resolve_completely(adjustment.target); + *has_errors = *has_errors || adjustment.target.references_non_lt_error(); } expr_adjustments.shrink_to_fit(); for adjustment in pat_adjustments.values_mut().flatten() { - *adjustment = table.resolve_completely(adjustment.clone()); - *has_errors = *has_errors || adjustment.contains_unknown(); + *adjustment = table.resolve_completely(*adjustment); + *has_errors = *has_errors || adjustment.references_non_lt_error(); } pat_adjustments.shrink_to_fit(); result.tuple_field_access_types = tuple_field_accesses_rev .into_iter() .enumerate() - .map(|(idx, subst)| { - ( - TupleId(idx as u32), - table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst), - ) - }) + .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst))) .inspect(|(_, subst)| { - *has_errors = - *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + *has_errors = *has_errors || subst.iter().any(|ty| ty.references_non_lt_error()); }) .collect(); result.tuple_field_access_types.shrink_to_fit(); @@ -1074,11 +1117,11 @@ impl<'db> InferenceContext<'db> { data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, - LifetimeElisionKind::for_const(id.loc(self.db).container), + LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container), ); // Constants might be defining usage sites of TAITs. - self.make_tait_coercion_table(iter::once(&return_ty)); + self.make_tait_coercion_table(iter::once(return_ty)); self.return_ty = return_ty; } @@ -1088,11 +1131,11 @@ impl<'db> InferenceContext<'db> { data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, - LifetimeElisionKind::Elided(static_lifetime()), + LifetimeElisionKind::Elided(self.types.re_static), ); // Statics might be defining usage sites of TAITs. - self.make_tait_coercion_table(iter::once(&return_ty)); + self.make_tait_coercion_table(iter::once(return_ty)); self.return_ty = return_ty; } @@ -1103,25 +1146,28 @@ impl<'db> InferenceContext<'db> { &data.store, InferenceTyDiagnosticSource::Signature, LifetimeElisionKind::for_fn_params(&data), - |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder); - data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>() - }, + |ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>(), ); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { let va_list_ty = match self.resolve_va_list() { - Some(va_list) => TyBuilder::adt(self.db, va_list) - .fill_with_defaults(self.db, || self.table.new_type_var()) - .build(), + Some(va_list) => Ty::new_adt( + self.interner(), + va_list, + GenericArgs::for_item_with_defaults( + self.interner(), + va_list.into(), + |_, _, id, _| self.table.next_var_for_param(id), + ), + ), None => self.err_ty(), }; param_tys.push(va_list_ty); } - let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var())); + let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.next_ty_var())); if let Some(self_param) = self.body.self_param && let Some(ty) = param_tys.next() { @@ -1132,12 +1178,8 @@ impl<'db> InferenceContext<'db> { for (ty, pat) in param_tys.zip(&*self.body.params) { let ty = self.process_user_written_ty(ty); - self.infer_top_pat(*pat, &ty, None); - if ty - .data(Interner) - .flags - .intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) - { + self.infer_top_pat(*pat, ty, None); + if ty.flags().intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) { tait_candidates.insert(ty); } } @@ -1146,31 +1188,24 @@ impl<'db> InferenceContext<'db> { let return_ty = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, - LifetimeElisionKind::for_fn_ret(), + LifetimeElisionKind::for_fn_ret(self.interner()), |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Opaque); + ctx.impl_trait_mode(ImplTraitLoweringMode::Opaque); ctx.lower_ty(return_ty) }, ); let return_ty = self.insert_type_vars(return_ty); - if let Some(rpits) = self.db.return_type_impl_traits(func) { - // RPIT opaque types use substitution of their parent function. - let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); + if let Some(rpits) = self.db.return_type_impl_traits_ns(func) { let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default()); - let result = self.insert_inference_vars_for_impl_trait( - return_ty, - fn_placeholders, - &mut mode, - ); + let result = self.insert_inference_vars_for_impl_trait(return_ty, &mut mode); if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { tait_candidates.extend(taits); } - let rpits = rpits.skip_binders(); + let rpits = (*rpits).as_ref().skip_binder(); for (id, _) in rpits.impl_traits.iter() { if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { never!("Missed RPIT in `insert_inference_vars_for_rpit`"); - e.insert(TyKind::Error.intern(Interner)); + e.insert(self.types.error); } } result @@ -1178,111 +1213,97 @@ impl<'db> InferenceContext<'db> { return_ty } } - None => self.result.standard_types.unit.clone(), + None => self.types.unit, }; self.return_ty = self.process_user_written_ty(return_ty); - self.return_coercion = - Some(CoerceMany::new(self.return_ty.to_nextsolver(self.table.interner))); + self.return_coercion = Some(CoerceMany::new(self.return_ty)); // 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. - 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()); - } - _ => {} + fold_tys(self.interner(), self.return_ty, |ty| { + match ty.kind() { + TyKind::Alias(AliasTyKind::Opaque, _) | TyKind::Infer(..) => { + tait_candidates.insert(self.return_ty); } - ty - }, - DebruijnIndex::INNERMOST, - ); + _ => {} + } + ty + }); + + self.make_tait_coercion_table(tait_candidates.iter().copied()); + } - self.make_tait_coercion_table(tait_candidates.iter()); + #[inline] + pub(crate) fn interner(&self) -> DbInterner<'db> { + self.table.interner() } fn insert_inference_vars_for_impl_trait( &mut self, t: T, - placeholders: Substitution, - mode: &mut ImplTraitReplacingMode, + mode: &mut ImplTraitReplacingMode<'db>, ) -> T where - T: crate::HasInterner + crate::TypeFoldable, + T: TypeFoldable>, { - 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, _) - | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id, .. })) => { - *opaque_ty_id - } - _ => return ty, - }; - let (impl_traits, idx) = - match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - // We don't replace opaque types from other kind with inference vars - // because `insert_inference_vars_for_impl_traits` for each kinds - // and unreplaced opaque types of other kind are resolved while - // inferencing because of `tait_coercion_table`. - // Moreover, calling `insert_inference_vars_for_impl_traits` with same - // `placeholders` for other kind may cause trouble because - // the substs for the bounds of each impl traits do not match - ImplTraitId::ReturnTypeImplTrait(def, idx) => { - if matches!(mode, ImplTraitReplacingMode::TypeAlias) { - // RPITs don't have `tait_coercion_table`, so use inserted inference - // vars for them. - if let Some(ty) = self.result.type_of_rpit.get(idx) { - return ty.clone(); - } - return ty; - } - (self.db.return_type_impl_traits(def), idx) - } - ImplTraitId::TypeAliasImplTrait(def, idx) => { - if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { - // Gather TAITs while replacing RPITs because TAITs inside RPITs - // may not visited while replacing TAITs - taits.insert(ty.clone()); - return ty; - } - (self.db.type_alias_impl_traits(def), idx) + fold_tys(self.interner(), t, |ty| { + let ty = self.table.try_structurally_resolve_type(ty); + let opaque_ty_id = match ty.kind() { + TyKind::Alias(AliasTyKind::Opaque, alias_ty) => alias_ty.def_id.expect_opaque_ty(), + _ => return ty, + }; + let (impl_traits, idx) = match self.db.lookup_intern_impl_trait_id(opaque_ty_id) { + // We don't replace opaque types from other kind with inference vars + // because `insert_inference_vars_for_impl_traits` for each kinds + // and unreplaced opaque types of other kind are resolved while + // inferencing because of `tait_coercion_table`. + ImplTraitId::ReturnTypeImplTrait(def, idx) => { + if matches!(mode, ImplTraitReplacingMode::TypeAlias) { + // RPITs don't have `tait_coercion_table`, so use inserted inference + // vars for them. + if let Some(ty) = + self.result.type_of_rpit.get(idx.to_nextsolver(self.interner())) + { + return *ty; } - _ => unreachable!(), - }; - let Some(impl_traits) = impl_traits else { - return ty; - }; - let bounds = (*impl_traits) - .map_ref(|its| its.impl_traits[idx].bounds.map_ref(|it| it.iter())); - let var = self.table.new_type_var(); - let var_subst = Substitution::from1(Interner, var.clone()); - for bound in bounds { - let predicate = bound.map(|it| it.cloned()); - let predicate = predicate.substitute(Interner, &placeholders); - let (var_predicate, binders) = - predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); - always!(binders.is_empty(Interner)); // quantified where clauses not yet handled - let var_predicate = self.insert_inference_vars_for_impl_trait( - var_predicate, - placeholders.clone(), - mode, - ); - self.push_obligation(var_predicate.cast(Interner)); + return ty; + } + (self.db.return_type_impl_traits_ns(def), idx) } - self.result.type_of_rpit.insert(idx, var.clone()); - var - }, - DebruijnIndex::INNERMOST, - ) + ImplTraitId::TypeAliasImplTrait(def, idx) => { + if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { + // Gather TAITs while replacing RPITs because TAITs inside RPITs + // may not visited while replacing TAITs + taits.insert(ty); + return ty; + } + (self.db.type_alias_impl_traits_ns(def), idx) + } + _ => unreachable!(), + }; + let Some(impl_traits) = impl_traits else { + return ty; + }; + let bounds = (*impl_traits).as_ref().map_bound(|its| { + its.impl_traits[idx.to_nextsolver(self.interner())].predicates.as_slice() + }); + let var = match self.result.type_of_rpit.entry(idx.to_nextsolver(self.interner())) { + Entry::Occupied(entry) => return *entry.get(), + Entry::Vacant(entry) => *entry.insert(self.table.next_ty_var()), + }; + for clause in bounds.iter_identity_copied() { + let clause = self.insert_inference_vars_for_impl_trait(clause, mode); + self.table.register_predicate(Obligation::new( + self.interner(), + ObligationCause::new(), + self.table.trait_env.env, + clause, + )); + } + var + }) } /// The coercion of a non-inference var into an opaque type should fail, @@ -1296,51 +1317,38 @@ impl<'db> InferenceContext<'db> { /// - We are pushing `impl Trait` bounds into it /// /// This function inserts a map that maps the opaque type to that proxy inference var. - fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator) { - struct TypeAliasImplTraitCollector<'a, 'b> { - db: &'b dyn HirDatabase, - table: &'b mut InferenceTable<'a>, - assocs: FxHashMap, - non_assocs: FxHashMap, + fn make_tait_coercion_table(&mut self, tait_candidates: impl Iterator>) { + struct TypeAliasImplTraitCollector<'a, 'db> { + db: &'a dyn HirDatabase, + table: &'a mut InferenceTable<'db>, + assocs: FxHashMap)>, + non_assocs: FxHashMap>, } - impl TypeVisitor for TypeAliasImplTraitCollector<'_, '_> { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } - - fn interner(&self) -> Interner { - Interner - } + impl<'db> TypeVisitor> for TypeAliasImplTraitCollector<'_, 'db> { + type Result = (); - fn visit_ty( - &mut self, - ty: &chalk_ir::Ty, - outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow { - let ty = self.table.structurally_resolve_type(ty); + fn visit_ty(&mut self, ty: Ty<'db>) { + let ty = self.table.try_structurally_resolve_type(ty); - if let TyKind::OpaqueType(id, _) - | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id: id, .. })) = - ty.kind(Interner) + if let TyKind::Alias(AliasTyKind::Opaque, alias_ty) = ty.kind() + && let id = alias_ty.def_id.expect_opaque_ty() && let ImplTraitId::TypeAliasImplTrait(alias_id, _) = - self.db.lookup_intern_impl_trait_id((*id).into()) + self.db.lookup_intern_impl_trait_id(id) { let loc = self.db.lookup_intern_type_alias(alias_id); match loc.container { ItemContainerId::ImplId(impl_id) => { - self.assocs.insert(*id, (impl_id, ty.clone())); + self.assocs.insert(id, (impl_id, ty)); } ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => { - self.non_assocs.insert(*id, ty.clone()); + self.non_assocs.insert(id, ty); } _ => {} } } - ty.super_visit_with(self, outer_binder) + ty.super_visit_with(self) } } @@ -1351,7 +1359,7 @@ impl<'db> InferenceContext<'db> { non_assocs: FxHashMap::default(), }; for ty in tait_candidates { - _ = ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); + ty.visit_with(&mut collector); } // Non-assoc TAITs can be define-used everywhere as long as they are @@ -1405,13 +1413,10 @@ impl<'db> InferenceContext<'db> { let tait_coercion_table: FxHashMap<_, _> = taits .into_iter() .filter_map(|(id, ty)| { - if let ImplTraitId::TypeAliasImplTrait(alias_id, _) = - self.db.lookup_intern_impl_trait_id(id.into()) + if let ImplTraitId::TypeAliasImplTrait(..) = self.db.lookup_intern_impl_trait_id(id) { - let subst = TyBuilder::placeholder_subst(self.db, alias_id); let ty = self.insert_inference_vars_for_impl_trait( ty, - subst, &mut ImplTraitReplacingMode::TypeAlias, ); Some((id, ty)) @@ -1432,18 +1437,18 @@ impl<'db> InferenceContext<'db> { None => { _ = self.infer_expr_coerce( self.body.body_expr, - &Expectation::has_type(self.return_ty.clone()), + &Expectation::has_type(self.return_ty), ExprIsRead::Yes, ) } } } - fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) { + fn write_expr_ty(&mut self, expr: ExprId, ty: Ty<'db>) { self.result.type_of_expr.insert(expr, ty); } - fn write_expr_adj(&mut self, expr: ExprId, adjustments: Box<[Adjustment]>) { + fn write_expr_adj(&mut self, expr: ExprId, adjustments: Box<[Adjustment<'db>]>) { if adjustments.is_empty() { return; } @@ -1456,7 +1461,7 @@ impl<'db> InferenceContext<'db> { ) => { // NeverToAny coercion can target any type, so instead of adding a new // adjustment on top we can change the target. - *target = new_target.clone(); + *target = *new_target; } _ => { *entry.get_mut() = adjustments; @@ -1469,14 +1474,14 @@ impl<'db> InferenceContext<'db> { } } - fn write_pat_adj(&mut self, pat: PatId, adjustments: Box<[Ty]>) { + fn write_pat_adj(&mut self, pat: PatId, adjustments: Box<[Ty<'db>]>) { 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) { + fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: GenericArgs<'db>) { self.result.method_resolutions.insert(expr, (func, subst)); } @@ -1484,19 +1489,24 @@ impl<'db> InferenceContext<'db> { self.result.variant_resolutions.insert(id, variant); } - fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId, subs: Substitution) { + fn write_assoc_resolution( + &mut self, + id: ExprOrPatId, + item: AssocItemId, + subs: GenericArgs<'db>, + ) { self.result.assoc_resolutions.insert(id, (item, subs)); } - fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { + fn write_pat_ty(&mut self, pat: PatId, ty: Ty<'db>) { self.result.type_of_pat.insert(pat, ty); } - fn write_binding_ty(&mut self, id: BindingId, ty: Ty) { + fn write_binding_ty(&mut self, id: BindingId, ty: Ty<'db>) { self.result.type_of_binding.insert(id, ty); } - fn push_diagnostic(&self, diagnostic: InferenceDiagnostic) { + fn push_diagnostic(&self, diagnostic: InferenceDiagnostic<'db>) { self.diagnostics.push(diagnostic); } @@ -1504,8 +1514,8 @@ impl<'db> InferenceContext<'db> { &mut self, store: &ExpressionStore, types_source: InferenceTyDiagnosticSource, - lifetime_elision: LifetimeElisionKind, - f: impl FnOnce(&mut TyLoweringContext<'_>) -> R, + lifetime_elision: LifetimeElisionKind<'db>, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, ) -> R { let mut ctx = TyLoweringContext::new( self.db, @@ -1519,7 +1529,10 @@ impl<'db> InferenceContext<'db> { f(&mut ctx) } - fn with_body_ty_lowering(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R { + fn with_body_ty_lowering( + &mut self, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, + ) -> R { self.with_ty_lowering( self.body, InferenceTyDiagnosticSource::Body, @@ -1533,14 +1546,14 @@ impl<'db> InferenceContext<'db> { type_ref: TypeRefId, store: &ExpressionStore, type_source: InferenceTyDiagnosticSource, - lifetime_elision: LifetimeElisionKind, - ) -> Ty { + lifetime_elision: LifetimeElisionKind<'db>, + ) -> Ty<'db> { let ty = self .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); self.process_user_written_ty(ty) } - fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { + fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.make_ty( type_ref, self.body, @@ -1549,37 +1562,31 @@ impl<'db> InferenceContext<'db> { ) } - fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty) -> Const { + fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( self.body, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, - |ctx| { - ctx.type_param_mode = ParamLoweringMode::Placeholder; - ctx.lower_const(&const_ref, ty) - }, + |ctx| ctx.lower_const(const_ref, ty), ); self.insert_type_vars(const_) } - fn make_path_as_body_const(&mut self, path: &Path, ty: Ty) -> Const { + fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( self.body, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, - |ctx| { - ctx.type_param_mode = ParamLoweringMode::Placeholder; - ctx.lower_path_as_const(path, ty) - }, + |ctx| ctx.lower_path_as_const(path, ty), ); self.insert_type_vars(const_) } - fn err_ty(&self) -> Ty { - self.result.standard_types.unknown.clone() + fn err_ty(&self) -> Ty<'db> { + self.types.error } - fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Lifetime { + fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Region<'db> { let lt = self.with_ty_lowering( self.body, InferenceTyDiagnosticSource::Body, @@ -1590,44 +1597,25 @@ impl<'db> InferenceContext<'db> { } /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. - fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { + fn insert_type_vars_shallow(&mut self, ty: Ty<'db>) -> Ty<'db> { self.table.insert_type_vars_shallow(ty) } fn insert_type_vars(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: TypeFoldable>, { self.table.insert_type_vars(ty) } - fn push_obligation(&mut self, o: DomainGoal) { - 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 { - let ty1 = ty1 - .clone() - .try_fold_with( - &mut UnevaluatedConstEvaluatorFolder { db: self.db }, - DebruijnIndex::INNERMOST, - ) - .unwrap(); - let ty2 = ty2 - .clone() - .try_fold_with( - &mut UnevaluatedConstEvaluatorFolder { db: self.db }, - DebruijnIndex::INNERMOST, - ) - .unwrap(); - self.table.unify(&ty1, &ty2) + fn unify(&mut self, ty1: Ty<'db>, ty2: Ty<'db>) -> bool { + self.table.unify(ty1, ty2) } /// Attempts to returns the deeply last field of nested structures, but /// does not apply any normalization in its search. Returns the same type /// if input `ty` is not a structure at all. - fn struct_tail_without_normalization(&mut self, ty: Ty) -> Ty { + fn struct_tail_without_normalization(&mut self, ty: Ty<'db>) -> Ty<'db> { self.struct_tail_with_normalize(ty, identity) } @@ -1640,37 +1628,34 @@ impl<'db> InferenceContext<'db> { /// function to indicate no normalization should take place. fn struct_tail_with_normalize( &mut self, - mut ty: Ty, - mut normalize: impl FnMut(Ty) -> Ty, - ) -> Ty { + mut ty: Ty<'db>, + mut normalize: impl FnMut(Ty<'db>) -> Ty<'db>, + ) -> Ty<'db> { // FIXME: fetch the limit properly let recursion_limit = 10; for iteration in 0.. { if iteration > recursion_limit { return self.err_ty(); } - match ty.kind(Interner) { - TyKind::Adt(chalk_ir::AdtId(hir_def::AdtId::StructId(struct_id)), substs) => { - match self.db.field_types((*struct_id).into()).values().next_back().cloned() { - Some(field) => { - ty = field.substitute(Interner, substs); + match ty.kind() { + TyKind::Adt(adt_def, substs) => match adt_def.def_id().0 { + AdtId::StructId(struct_id) => { + match self.db.field_types_ns(struct_id.into()).values().next_back().copied() + { + Some(field) => { + ty = field.instantiate(self.interner(), substs); + } + None => break, } - None => break, - } - } - TyKind::Adt(..) => break, - TyKind::Tuple(_, substs) => { - match substs - .as_slice(Interner) - .split_last() - .and_then(|(last_ty, _)| last_ty.ty(Interner)) - { - Some(last_ty) => ty = last_ty.clone(), - None => break, } - } + _ => break, + }, + TyKind::Tuple(substs) => match substs.as_slice().split_last() { + Some((last_ty, _)) => ty = *last_ty, + None => break, + }, TyKind::Alias(..) => { - let normalized = normalize(ty.clone()); + let normalized = normalize(ty); if ty == normalized { return ty; } else { @@ -1684,41 +1669,35 @@ impl<'db> InferenceContext<'db> { } /// Whenever you lower a user-written type, you should call this. - fn process_user_written_ty(&mut self, ty: T) -> T + 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>, + T: 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 + 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>, + T: TypeFoldable>, { self.table.process_remote_user_written_ty(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> { + fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { self.table.shallow_resolve(ty) } - fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option) -> Ty { + fn resolve_associated_type( + &mut self, + inner_ty: Ty<'db>, + assoc_ty: Option, + ) -> Ty<'db> { self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) } - fn demand_eqtype( - &mut self, - expected: crate::next_solver::Ty<'db>, - actual: crate::next_solver::Ty<'db>, - ) { + fn demand_eqtype(&mut self, expected: Ty<'db>, actual: Ty<'db>) { let result = self .table .infer_ctxt @@ -1732,34 +1711,24 @@ impl<'db> InferenceContext<'db> { fn resolve_associated_type_with_params( &mut self, - inner_ty: Ty, + inner_ty: Ty<'db>, assoc_ty: Option, // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be // handled when we support them. - params: &[GenericArg], - ) -> Ty { + params: &[GenericArg<'db>], + ) -> Ty<'db> { match assoc_ty { Some(res_assoc_ty) => { - let trait_ = match res_assoc_ty.lookup(self.db).container { - hir_def::ItemContainerId::TraitId(trait_) => trait_, - _ => panic!("resolve_associated_type called with non-associated type"), - }; - let ty = self.table.new_type_var(); - let mut param_iter = params.iter().cloned(); - let trait_ref = TyBuilder::trait_ref(self.db, trait_) - .push(inner_ty) - .fill(|_| param_iter.next().unwrap()) - .build(); - let alias_eq = AliasEq { - alias: AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(res_assoc_ty), - substitution: trait_ref.substitution.clone(), - }), - ty: ty.clone(), - }; - self.push_obligation(trait_ref.cast(Interner)); - self.push_obligation(alias_eq.cast(Interner)); - ty + let alias = Ty::new_alias( + self.interner(), + AliasTyKind::Projection, + AliasTy::new( + self.interner(), + res_assoc_ty.into(), + iter::once(inner_ty.into()).chain(params.iter().copied()), + ), + ); + self.table.try_structurally_resolve_type(alias) } None => self.err_ty(), } @@ -1770,7 +1739,7 @@ impl<'db> InferenceContext<'db> { node: ExprOrPatId, path: Option<&Path>, value_ns: bool, - ) -> (Ty, Option) { + ) -> (Ty<'db>, Option) { let path = match path { Some(path) => path, None => return (self.err_ty(), None), @@ -1793,28 +1762,19 @@ impl<'db> InferenceContext<'db> { match res { ResolveValueResult::ValueNs(value, _) => match value { ValueNs::EnumVariantId(var) => { - let substs = path_ctx.substs_from_path(var.into(), true, false); + let args = path_ctx.substs_from_path(var.into(), true, false); drop(ctx); - let args: crate::next_solver::GenericArgs<'_> = - substs.to_nextsolver(interner); let ty = self .db .ty(var.lookup(self.db).parent.into()) - .instantiate(interner, args) - .to_chalk(interner); + .instantiate(interner, args); let ty = self.insert_type_vars(ty); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { - let substs = path_ctx.substs_from_path(strukt.into(), true, false); + let args = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); - let args: crate::next_solver::GenericArgs<'_> = - substs.to_nextsolver(interner); - let ty = self - .db - .ty(strukt.into()) - .instantiate(interner, args) - .to_chalk(interner); + let ty = self.db.ty(strukt.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty); return (ty, Some(strukt.into())); } @@ -1834,39 +1794,28 @@ impl<'db> InferenceContext<'db> { }; return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { - let substs = path_ctx.substs_from_path(strukt.into(), true, false); + let args = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self.db.ty(strukt.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.db.ty(strukt.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty); - forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) + forbid_unresolved_segments(self, (ty, Some(strukt.into())), unresolved) } TypeNs::AdtId(AdtId::UnionId(u)) => { - let substs = path_ctx.substs_from_path(u.into(), true, false); + let args = path_ctx.substs_from_path(u.into(), true, false); drop(ctx); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self.db.ty(u.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.db.ty(u.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty); - forbid_unresolved_segments((ty, Some(u.into())), unresolved) + forbid_unresolved_segments(self, (ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { - let substs = path_ctx.substs_from_path(var.into(), true, false); + let args = path_ctx.substs_from_path(var.into(), true, false); drop(ctx); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self - .db - .ty(var.lookup(self.db).parent.into()) - .instantiate(interner, args) - .to_chalk(interner); + let ty = self.db.ty(var.lookup(self.db).parent.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty); - forbid_unresolved_segments((ty, Some(var.into())), unresolved) + forbid_unresolved_segments(self, (ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { - let generics = crate::generics::generics(self.db, impl_id.into()); - let substs = generics.placeholder_subst(self.db); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let mut ty = - self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); + let mut ty = self.db.impl_self_ty(impl_id).instantiate_identity(); let Some(remaining_idx) = unresolved else { drop(ctx); @@ -1889,7 +1838,9 @@ impl<'db> InferenceContext<'db> { while let Some(current_segment) = remaining_segments.first() { // If we can resolve to an enum variant, it takes priority over associated type // of the same name. - if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { + if let TyKind::Adt(adt_def, _) = ty.kind() + && let AdtId::EnumId(id) = adt_def.def_id().0 + { let enum_data = id.enum_variants(self.db); if let Some(variant) = enum_data.variant(current_segment.name) { return if remaining_segments.len() == 1 { @@ -1917,8 +1868,8 @@ impl<'db> InferenceContext<'db> { ty = self.table.insert_type_vars(ty); ty = self.table.normalize_associated_types_in(ty); - ty = self.table.structurally_resolve_type(&ty); - if ty.is_unknown() { + ty = self.table.structurally_resolve_type(ty); + if ty.is_ty_error() { return (self.err_ty(), None); } @@ -1941,11 +1892,10 @@ impl<'db> InferenceContext<'db> { never!("resolver should always resolve lang item paths"); return (self.err_ty(), None); }; - let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false); + let args = path_ctx.substs_from_path_segment(it.into(), true, None, false); drop(ctx); let interner = DbInterner::conjure(); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self.db.ty(it.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.db.ty(it.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty); self.resolve_variant_on_alias(ty, unresolved, mod_path) @@ -1967,33 +1917,28 @@ impl<'db> InferenceContext<'db> { } }; - fn forbid_unresolved_segments( - result: (Ty, Option), + fn forbid_unresolved_segments<'db>( + ctx: &InferenceContext<'_, 'db>, + result: (Ty<'db>, Option), unresolved: Option, - ) -> (Ty, Option) { + ) -> (Ty<'db>, Option) { if unresolved.is_none() { result } else { // FIXME diagnostic - (TyKind::Error.intern(Interner), None) + (ctx.types.error, None) } } } fn resolve_variant_on_alias( &mut self, - ty: Ty, + ty: Ty<'db>, unresolved: Option, path: &ModPath, - ) -> (Ty, Option) { + ) -> (Ty<'db>, Option) { let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); - let ty = match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - let ty = self.table.normalize_projection_ty(proj_ty.clone()); - self.table.structurally_resolve_type(&ty) - } - _ => ty, - }; + let ty = self.table.try_structurally_resolve_type(ty); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -2115,19 +2060,18 @@ impl<'db> InferenceContext<'db> { /// When inferring an expression, we propagate downward whatever type hint we /// are able in the form of an `Expectation`. #[derive(Clone, PartialEq, Eq, Debug)] -pub(crate) enum Expectation { +pub(crate) enum Expectation<'db> { None, - HasType(Ty), - #[allow(dead_code)] - Castable(Ty), - RValueLikeUnsized(Ty), + HasType(Ty<'db>), + Castable(Ty<'db>), + RValueLikeUnsized(Ty<'db>), } -impl Expectation { +impl<'db> Expectation<'db> { /// The expectation that the type of the expression needs to equal the given /// type. - fn has_type(ty: Ty) -> Self { - if ty.is_unknown() { + fn has_type(ty: Ty<'db>) -> Self { + if ty.is_ty_error() { // FIXME: get rid of this? Expectation::None } else { @@ -2155,9 +2099,11 @@ impl Expectation { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self { - match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) { - TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty), + fn rvalue_hint(ctx: &mut InferenceContext<'_, 'db>, ty: Ty<'db>) -> Self { + match ctx.struct_tail_without_normalization(ty).kind() { + TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(..) => { + Expectation::RValueLikeUnsized(ty) + } _ => Expectation::has_type(ty), } } @@ -2167,18 +2113,18 @@ impl Expectation { Expectation::None } - fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { + fn resolve(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { match self { Expectation::None => Expectation::None, - Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)), - Expectation::Castable(t) => Expectation::Castable(table.resolve_ty_shallow(t)), + Expectation::HasType(t) => Expectation::HasType(table.shallow_resolve(*t)), + Expectation::Castable(t) => Expectation::Castable(table.shallow_resolve(*t)), Expectation::RValueLikeUnsized(t) => { - Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t)) + Expectation::RValueLikeUnsized(table.shallow_resolve(*t)) } } } - fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option { + fn to_option(&self, table: &mut unify::InferenceTable<'db>) -> Option> { match self.resolve(table) { Expectation::None => None, Expectation::HasType(t) @@ -2187,17 +2133,17 @@ impl Expectation { } } - fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option { + fn only_has_type(&self, table: &mut unify::InferenceTable<'db>) -> Option> { match self { - Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)), + Expectation::HasType(t) => Some(table.shallow_resolve(*t)), Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => { None } } } - fn coercion_target_type(&self, table: &mut unify::InferenceTable<'_>) -> Ty { - self.only_has_type(table).unwrap_or_else(|| table.new_type_var()) + fn coercion_target_type(&self, table: &mut unify::InferenceTable<'db>) -> Ty<'db> { + self.only_has_type(table).unwrap_or_else(|| table.next_ty_var()) } /// Comment copied from rustc: @@ -2217,13 +2163,13 @@ impl Expectation { /// an expected type. Otherwise, we might write parts of the type /// when checking the 'then' block which are incompatible with the /// 'else' branch. - fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { - match self { + fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { + match *self { Expectation::HasType(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()), + Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety), _ => Expectation::None, } } @@ -2266,123 +2212,3 @@ impl std::ops::BitOrAssign for Diverges { *self = *self | other; } } - -/// A zipper that checks for unequal occurrences of `{unknown}` and unresolved projections -/// in the two types. Used to filter out mismatch diagnostics that only differ in -/// `{unknown}` and unresolved projections. These mismatches are usually not helpful. -/// As the cause is usually an underlying name resolution problem -struct UnknownMismatch<'db>(&'db dyn HirDatabase); -impl chalk_ir::zip::Zipper for UnknownMismatch<'_> { - fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> { - let zip_substs = |this: &mut Self, - variances, - sub_a: &Substitution, - sub_b: &Substitution| { - this.zip_substs(variance, variances, sub_a.as_slice(Interner), sub_b.as_slice(Interner)) - }; - match (a.kind(Interner), b.kind(Interner)) { - (TyKind::Adt(id_a, sub_a), TyKind::Adt(id_b, sub_b)) if id_a == id_b => zip_substs( - self, - Some(self.unification_database().adt_variance(*id_a)), - sub_a, - sub_b, - )?, - ( - TyKind::AssociatedType(assoc_ty_a, sub_a), - TyKind::AssociatedType(assoc_ty_b, sub_b), - ) if assoc_ty_a == assoc_ty_b => zip_substs(self, None, sub_a, sub_b)?, - (TyKind::Tuple(arity_a, sub_a), TyKind::Tuple(arity_b, sub_b)) - if arity_a == arity_b => - { - zip_substs(self, None, sub_a, sub_b)? - } - (TyKind::OpaqueType(opaque_ty_a, sub_a), TyKind::OpaqueType(opaque_ty_b, sub_b)) - if opaque_ty_a == opaque_ty_b => - { - zip_substs(self, None, sub_a, sub_b)? - } - (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.zip_tys(variance, ty_a, ty_b)?, - (TyKind::FnDef(fn_def_a, sub_a), TyKind::FnDef(fn_def_b, sub_b)) - if fn_def_a == fn_def_b => - { - zip_substs( - self, - Some(self.unification_database().fn_def_variance(*fn_def_a)), - sub_a, - sub_b, - )? - } - (TyKind::Ref(mutability_a, _, ty_a), TyKind::Ref(mutability_b, _, ty_b)) - if mutability_a == mutability_b => - { - self.zip_tys(variance, ty_a, ty_b)? - } - (TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b)) - if mutability_a == mutability_b => - { - self.zip_tys(variance, ty_a, ty_b)? - } - (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) if const_a == const_b => { - self.zip_tys(variance, ty_a, ty_b)? - } - (TyKind::Closure(id_a, sub_a), TyKind::Closure(id_b, sub_b)) if id_a == id_b => { - zip_substs(self, None, sub_a, sub_b)? - } - (TyKind::Coroutine(coroutine_a, sub_a), TyKind::Coroutine(coroutine_b, sub_b)) - if coroutine_a == coroutine_b => - { - zip_substs(self, None, sub_a, sub_b)? - } - ( - TyKind::CoroutineWitness(coroutine_a, sub_a), - TyKind::CoroutineWitness(coroutine_b, sub_b), - ) if coroutine_a == coroutine_b => zip_substs(self, None, sub_a, sub_b)?, - (TyKind::Function(fn_ptr_a), TyKind::Function(fn_ptr_b)) - if fn_ptr_a.sig == fn_ptr_b.sig && fn_ptr_a.num_binders == fn_ptr_b.num_binders => - { - zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)? - } - (TyKind::Error, TyKind::Error) => (), - (TyKind::Error, _) - | (_, TyKind::Error) - | (TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _), _) - | (_, TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _)) => { - return Err(chalk_ir::NoSolution); - } - _ => (), - } - - Ok(()) - } - - fn zip_lifetimes(&mut self, _: Variance, _: &Lifetime, _: &Lifetime) -> chalk_ir::Fallible<()> { - Ok(()) - } - - fn zip_consts(&mut self, _: Variance, _: &Const, _: &Const) -> chalk_ir::Fallible<()> { - Ok(()) - } - - fn zip_binders( - &mut self, - variance: Variance, - a: &Binders, - b: &Binders, - ) -> chalk_ir::Fallible<()> - where - T: Clone - + HasInterner - + chalk_ir::zip::Zip - + TypeFoldable, - { - chalk_ir::zip::Zip::zip_with(self, variance, a.skip_binders(), b.skip_binders()) - } - - fn interner(&self) -> Interner { - Interner - } - - fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase { - &self.0 - } -} 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 index 77b1ae6a94a46..ba133aa553d7d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/autoderef.rs @@ -2,6 +2,8 @@ use std::iter; +use rustc_ast_ir::Mutability; + use crate::{ Adjust, Adjustment, OverloadedDeref, autoderef::{Autoderef, AutoderefKind}, @@ -9,7 +11,6 @@ use crate::{ next_solver::{ Ty, infer::{InferOk, traits::PredicateObligations}, - mapping::NextSolverToChalk, }, }; @@ -21,12 +22,12 @@ impl<'db> InferenceTable<'db> { impl<'db> Autoderef<'_, 'db> { /// Returns the adjustment steps. - pub(crate) fn adjust_steps(mut self) -> Vec { + 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> { + 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![] }; @@ -37,16 +38,13 @@ impl<'db> Autoderef<'_, 'db> { .iter() .map(|&(_source, kind)| { if let AutoderefKind::Overloaded = kind { - Some(OverloadedDeref(Some(chalk_ir::Mutability::Not))) + Some(OverloadedDeref(Some(Mutability::Not))) } else { None } }) .zip(targets) - .map(|(autoderef, target)| Adjustment { - kind: Adjust::Deref(autoderef), - target: target.to_chalk(self.table.interner), - }) + .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target }) .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 4cd6144a14cba..017f45f43df46 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,17 +1,18 @@ //! Type cast logic. Basically coercion + additional casts. -use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy}; use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags}; +use rustc_ast_ir::Mutability; +use rustc_type_ir::{ + Flags, InferTy, TypeFlags, UintTy, + inherent::{AdtDef, BoundExistentialPredicates as _, IntoKind, SliceLike, Ty as _}, +}; use stdx::never; -use crate::infer::coerce::CoerceNever; use crate::{ - Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, QuantifiedWhereClauses, Ty, - TyExt, TyKind, TypeFlags, WhereClause, + InferenceDiagnostic, db::HirDatabase, - from_chalk_trait_id, - infer::{AllowTwoPhase, InferenceContext}, - next_solver::mapping::ChalkToNextSolver, + infer::{AllowTwoPhase, InferenceContext, coerce::CoerceNever}, + next_solver::{BoundExistentialPredicates, DbInterner, ParamTy, Ty, TyKind}, }; #[derive(Debug)] @@ -25,24 +26,24 @@ pub(crate) enum Int { } #[derive(Debug)] -pub(crate) enum CastTy { +pub(crate) enum CastTy<'db> { Int(Int), Float, FnPtr, - Ptr(Ty, Mutability), + Ptr(Ty<'db>, Mutability), // `DynStar` is Not supported yet in r-a } -impl CastTy { - 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)), - TyKind::Scalar(Scalar::Int(_)) => Some(Self::Int(Int::I)), - TyKind::Scalar(Scalar::Uint(it)) => Some(Self::Int(Int::U(*it))), - TyKind::InferenceVar(_, TyVariableKind::Integer) => Some(Self::Int(Int::InferenceVar)), - TyKind::InferenceVar(_, TyVariableKind::Float) => Some(Self::Float), - TyKind::Scalar(Scalar::Float(_)) => Some(Self::Float), +impl<'db> CastTy<'db> { + pub(crate) fn from_ty(db: &dyn HirDatabase, t: Ty<'db>) -> Option { + match t.kind() { + TyKind::Bool => Some(Self::Int(Int::Bool)), + TyKind::Char => Some(Self::Int(Int::Char)), + TyKind::Int(_) => Some(Self::Int(Int::I)), + TyKind::Uint(it) => Some(Self::Int(Int::U(it))), + TyKind::Infer(InferTy::IntVar(_)) => Some(Self::Int(Int::InferenceVar)), + TyKind::Infer(InferTy::FloatVar(_)) => Some(Self::Float), + TyKind::Float(_) => Some(Self::Float), TyKind::Adt(..) => { let (AdtId::EnumId(id), _) = t.as_adt()? else { return None; @@ -50,8 +51,8 @@ impl CastTy { 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), + TyKind::RawPtr(ty, m) => Some(Self::Ptr(ty, m)), + TyKind::FnPtr(..) => Some(Self::FnPtr), _ => None, } } @@ -77,37 +78,47 @@ pub enum CastError { } impl CastError { - fn into_diagnostic(self, expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> InferenceDiagnostic { + fn into_diagnostic<'db>( + self, + expr: ExprId, + expr_ty: Ty<'db>, + cast_ty: Ty<'db>, + ) -> InferenceDiagnostic<'db> { InferenceDiagnostic::InvalidCast { expr, error: self, expr_ty, cast_ty } } } #[derive(Clone, Debug)] -pub(super) struct CastCheck { +pub(super) struct CastCheck<'db> { expr: ExprId, source_expr: ExprId, - expr_ty: Ty, - cast_ty: Ty, + expr_ty: Ty<'db>, + cast_ty: Ty<'db>, } -impl CastCheck { - pub(super) fn new(expr: ExprId, source_expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> Self { +impl<'db> CastCheck<'db> { + pub(super) fn new( + expr: ExprId, + source_expr: ExprId, + expr_ty: Ty<'db>, + cast_ty: Ty<'db>, + ) -> Self { Self { expr, source_expr, expr_ty, cast_ty } } pub(super) fn check( &mut self, - 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()); + ctx: &mut InferenceContext<'_, 'db>, + ) -> Result<(), InferenceDiagnostic<'db>> { + self.expr_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty); + self.cast_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty); // This should always come first so that we apply the coercion, which impacts infer vars. if ctx .coerce( self.source_expr.into(), - self.expr_ty.to_nextsolver(ctx.table.interner), - self.cast_ty.to_nextsolver(ctx.table.interner), + self.expr_ty, + self.cast_ty, AllowTwoPhase::No, CoerceNever::Yes, ) @@ -117,83 +128,82 @@ impl CastCheck { return Ok(()); } - if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() { + if self.expr_ty.references_non_lt_error() || self.cast_ty.references_non_lt_error() { return Ok(()); } - if !self.cast_ty.data(Interner).flags.contains(TypeFlags::HAS_TY_INFER) - && !ctx.table.is_sized(&self.cast_ty) + if !self.cast_ty.flags().contains(TypeFlags::HAS_TY_INFER) + && !ctx.table.is_sized(self.cast_ty) { return Err(InferenceDiagnostic::CastToUnsized { expr: self.expr, - cast_ty: self.cast_ty.clone(), + cast_ty: self.cast_ty, }); } // Chalk doesn't support trait upcasting and fails to solve some obvious goals // when the trait environment contains some recursive traits (See issue #18047) // We skip cast checks for such cases for now, until the next-gen solver. - if contains_dyn_trait(&self.cast_ty) { + if contains_dyn_trait(self.cast_ty) { return Ok(()); } - self.do_check(ctx) - .map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone())) + self.do_check(ctx).map_err(|e| e.into_diagnostic(self.expr, self.expr_ty, self.cast_ty)) } - fn do_check(&self, ctx: &mut InferenceContext<'_>) -> Result<(), CastError> { - let (t_from, t_cast) = match ( - 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(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 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); - } + fn do_check(&self, ctx: &mut InferenceContext<'_, 'db>) -> Result<(), CastError> { + let (t_from, t_cast) = + match (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() { + TyKind::FnDef(..) => { + let sig = + self.expr_ty.callable_sig(ctx.interner()).expect("FnDef had no sig"); + let sig = ctx.table.eagerly_normalize_and_resolve_shallow_in(sig); + let fn_ptr = Ty::new_fn_ptr(ctx.interner(), sig); + if ctx + .coerce( + self.source_expr.into(), + self.expr_ty, + fn_ptr, + AllowTwoPhase::No, + CoerceNever::Yes, + ) + .is_ok() + { + } else { + return Err(CastError::IllegalCast); + } - (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 = ctx.table.eagerly_normalize_and_resolve_shallow_in(t); - if !ctx.table.is_sized(&t) { - return Err(CastError::IllegalCast); + (CastTy::FnPtr, t_cast) + } + TyKind::Ref(_, inner_ty, mutbl) => { + return match t_cast { + CastTy::Int(_) | CastTy::Float => match inner_ty.kind() { + TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => { + Err(CastError::NeedDeref) + } + + _ => Err(CastError::NeedViaPtr), + }, + // array-ptr-cast + CastTy::Ptr(t, m) => { + 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(ctx, inner_ty, mutbl, t, m) } - self.check_ref_cast(ctx, inner_ty, *mutbl, &t, m) - } - _ => Err(CastError::NonScalar), - }; - } + _ => Err(CastError::NonScalar), + }; + } + _ => return Err(CastError::NonScalar), + }, _ => return Err(CastError::NonScalar), - }, - _ => return Err(CastError::NonScalar), - }; + }; // rustc checks whether the `expr_ty` is foreign adt with `non_exhaustive` sym @@ -207,10 +217,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(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::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(()), @@ -220,23 +230,23 @@ impl CastCheck { fn check_ref_cast( &self, - ctx: &mut InferenceContext<'_>, - t_expr: &Ty, + ctx: &mut InferenceContext<'_, 'db>, + t_expr: Ty<'db>, m_expr: Mutability, - t_cast: &Ty, + t_cast: Ty<'db>, m_cast: Mutability, ) -> Result<(), CastError> { // Mutability order is opposite to rustc. `Mut < Not` if m_expr <= m_cast - && let TyKind::Array(ety, _) = t_expr.kind(Interner) + && let TyKind::Array(ety, _) = t_expr.kind() { // 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); + let array_ptr_type = Ty::new_ptr(ctx.interner(), t_expr, m_expr); if ctx .coerce( self.source_expr.into(), - self.expr_ty.to_nextsolver(ctx.table.interner), - array_ptr_type.to_nextsolver(ctx.table.interner), + self.expr_ty, + array_ptr_type, AllowTwoPhase::No, CoerceNever::Yes, ) @@ -253,13 +263,7 @@ impl CastCheck { // This is a less strict condition than rustc's `demand_eqtype`, // but false negative is better than false positive if ctx - .coerce( - self.source_expr.into(), - ety.to_nextsolver(ctx.table.interner), - t_cast.to_nextsolver(ctx.table.interner), - AllowTwoPhase::No, - CoerceNever::Yes, - ) + .coerce(self.source_expr.into(), ety, t_cast, AllowTwoPhase::No, CoerceNever::Yes) .is_ok() { return Ok(()); @@ -271,9 +275,9 @@ impl CastCheck { fn check_ptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_>, - src: &Ty, - dst: &Ty, + ctx: &mut InferenceContext<'_, 'db>, + src: Ty<'db>, + dst: Ty<'db>, ) -> Result<(), CastError> { let src_kind = pointer_kind(src, ctx).map_err(|_| CastError::Unknown)?; let dst_kind = pointer_kind(dst, ctx).map_err(|_| CastError::Unknown)?; @@ -286,24 +290,13 @@ impl CastCheck { (_, Some(PointerKind::Thin)) => Ok(()), (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast), (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => { - let principal = |tty: &Binders| { - tty.skip_binders().as_slice(Interner).first().and_then(|pred| { - if let WhereClause::Implemented(tr) = pred.skip_binders() { - Some(tr.trait_id) - } else { - None - } - }) - }; - match (principal(&src_tty), principal(&dst_tty)) { + match (src_tty.principal_def_id(), dst_tty.principal_def_id()) { (Some(src_principal), Some(dst_principal)) => { if src_principal == dst_principal { return Ok(()); } - let src_principal = - ctx.db.trait_signature(from_chalk_trait_id(src_principal)); - let dst_principal = - ctx.db.trait_signature(from_chalk_trait_id(dst_principal)); + let src_principal = ctx.db.trait_signature(src_principal.0); + let dst_principal = ctx.db.trait_signature(dst_principal.0); if src_principal.flags.contains(TraitFlags::AUTO) && dst_principal.flags.contains(TraitFlags::AUTO) { @@ -322,8 +315,8 @@ impl CastCheck { fn check_ptr_addr_cast( &self, - ctx: &mut InferenceContext<'_>, - expr_ty: &Ty, + ctx: &mut InferenceContext<'_, 'db>, + expr_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(expr_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownExprPtrKind), @@ -336,8 +329,8 @@ impl CastCheck { fn check_addr_ptr_cast( &self, - ctx: &mut InferenceContext<'_>, - cast_ty: &Ty, + ctx: &mut InferenceContext<'_, 'db>, + cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), @@ -352,8 +345,8 @@ impl CastCheck { fn check_fptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_>, - cast_ty: &Ty, + ctx: &mut InferenceContext<'_, 'db>, + cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? { // None => Err(CastError::UnknownCastPtrKind), @@ -366,30 +359,34 @@ impl CastCheck { } #[derive(Debug, PartialEq, Eq)] -enum PointerKind { +enum PointerKind<'db> { // thin pointer Thin, // trait object - VTable(Binders), + VTable(BoundExistentialPredicates<'db>), // slice Length, OfAlias, - OfParam(PlaceholderIndex), + OfParam(ParamTy), Error, } -fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result, ()> { - let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty.clone()); +fn pointer_kind<'db>( + ty: Ty<'db>, + ctx: &mut InferenceContext<'_, 'db>, +) -> Result>, ()> { + let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty); - if ctx.table.is_sized(&ty) { + if ctx.table.is_sized(ty) { return Ok(Some(PointerKind::Thin)); } - match ty.kind(Interner) { + match ty.kind() { TyKind::Slice(_) | TyKind::Str => Ok(Some(PointerKind::Length)), - TyKind::Dyn(DynTy { bounds, .. }) => Ok(Some(PointerKind::VTable(bounds.clone()))), - TyKind::Adt(chalk_ir::AdtId(id), subst) => { - let AdtId::StructId(id) = *id else { + TyKind::Dynamic(bounds, _) => Ok(Some(PointerKind::VTable(bounds))), + TyKind::Adt(adt_def, subst) => { + let id = adt_def.def_id().0; + let AdtId::StructId(id) = id else { never!("`{:?}` should be sized but is not?", ty); return Err(()); }; @@ -397,69 +394,63 @@ fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result { - match subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) { - None => Ok(Some(PointerKind::Thin)), - Some(ty) => pointer_kind(ty, ctx), - } - } + TyKind::Tuple(subst) => match subst.iter().last() { + None => Ok(Some(PointerKind::Thin)), + Some(ty) => pointer_kind(ty, ctx), + }, TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)), - TyKind::Alias(_) | TyKind::AssociatedType(..) | TyKind::OpaqueType(..) => { - Ok(Some(PointerKind::OfAlias)) - } - TyKind::Error => Ok(Some(PointerKind::Error)), - TyKind::Placeholder(idx) => Ok(Some(PointerKind::OfParam(*idx))), - TyKind::BoundVar(_) | TyKind::InferenceVar(..) => Ok(None), - TyKind::Scalar(_) + TyKind::Alias(..) => Ok(Some(PointerKind::OfAlias)), + TyKind::Error(_) => Ok(Some(PointerKind::Error)), + TyKind::Param(idx) => Ok(Some(PointerKind::OfParam(idx))), + TyKind::Bound(..) | TyKind::Placeholder(..) | TyKind::Infer(..) => Ok(None), + TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Bool + | TyKind::Char | TyKind::Array(..) | TyKind::CoroutineWitness(..) - | TyKind::Raw(..) + | TyKind::RawPtr(..) | TyKind::Ref(..) | TyKind::FnDef(..) - | TyKind::Function(_) + | TyKind::FnPtr(..) | TyKind::Closure(..) | TyKind::Coroutine(..) + | TyKind::CoroutineClosure(..) | TyKind::Never => { never!("`{:?}` should be sized but is not?", ty); Err(()) } + TyKind::UnsafeBinder(..) | TyKind::Pat(..) => { + never!("we don't produce these types: {ty:?}"); + Err(()) + } } } -fn contains_dyn_trait(ty: &Ty) -> bool { +fn contains_dyn_trait<'db>(ty: Ty<'db>) -> bool { use std::ops::ControlFlow; - use chalk_ir::{ - DebruijnIndex, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, - }; + use rustc_type_ir::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; struct DynTraitVisitor; - impl TypeVisitor for DynTraitVisitor { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } - - fn interner(&self) -> Interner { - Interner - } + impl<'db> TypeVisitor> for DynTraitVisitor { + type Result = ControlFlow<()>; - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow { - match ty.kind(Interner) { - TyKind::Dyn(_) => ControlFlow::Break(()), - _ => ty.super_visit_with(self.as_dyn(), outer_binder), + fn visit_ty(&mut self, ty: Ty<'db>) -> ControlFlow<()> { + match ty.kind() { + TyKind::Dynamic(..) => ControlFlow::Break(()), + _ => ty.super_visit_with(self), } } } - ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break() + ty.visit_with(&mut DynTraitVisitor).is_break() } 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 4a57b2f37510e..2637ed6b3ec93 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 @@ -2,8 +2,7 @@ pub(crate) mod analysis; -use std::ops::ControlFlow; -use std::{iter, mem}; +use std::{iter, mem, ops::ControlFlow}; use hir_def::{ TraitId, @@ -18,7 +17,6 @@ use rustc_type_ir::{ }; use tracing::debug; -use crate::traits::FnTrait; use crate::{ FnAbi, db::{InternedClosure, InternedCoroutine}, @@ -31,25 +29,25 @@ use crate::{ BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult, traits::{ObligationCause, PredicateObligations}, }, - mapping::{ChalkToNextSolver, NextSolverToChalk}, util::explicit_item_bounds, }, + traits::FnTrait, }; use super::{Expectation, InferenceContext}; #[derive(Debug)] -struct ClosureSignatures<'tcx> { +struct ClosureSignatures<'db> { /// The signature users of the closure see. - bound_sig: PolyFnSig<'tcx>, + bound_sig: PolyFnSig<'db>, /// 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>, + liberated_sig: FnSig<'db>, } -impl<'db> InferenceContext<'db> { +impl<'db> InferenceContext<'_, 'db> { pub(super) fn infer_closure( &mut self, body: ExprId, @@ -58,15 +56,13 @@ impl<'db> InferenceContext<'db> { arg_types: &[Option], closure_kind: ClosureKind, tgt_expr: ExprId, - expected: &Expectation, - ) -> crate::Ty { + expected: &Expectation<'db>, + ) -> Ty<'db> { assert_eq!(args.len(), arg_types.len()); - let interner = self.table.interner; + let interner = self.interner(); let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) { - Some(expected_ty) => { - self.deduce_closure_signature(expected_ty.to_nextsolver(interner), closure_kind) - } + Some(expected_ty) => self.deduce_closure_signature(expected_ty, closure_kind), None => (None, None), }; @@ -79,10 +75,7 @@ impl<'db> InferenceContext<'db> { let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Coroutine(_) => { 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)); + let resume_ty = liberated_sig.inputs().get(0).unwrap_or(self.types.unit); // FIXME: Infer the upvars later. let parts = CoroutineArgsParts { @@ -102,11 +95,7 @@ impl<'db> InferenceContext<'db> { CoroutineArgs::new(interner, parts).args, ); - ( - None, - coroutine_ty, - Some((resume_ty.to_chalk(interner), yield_ty.to_chalk(interner))), - ) + (None, coroutine_ty, Some((resume_ty, yield_ty))) } // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`. // But for now we treat it as a closure. @@ -115,7 +104,7 @@ impl<'db> InferenceContext<'db> { match expected_kind { Some(kind) => { self.result.closure_info.insert( - closure_id.into(), + closure_id, ( Vec::new(), match kind { @@ -151,13 +140,13 @@ impl<'db> InferenceContext<'db> { // Now go through the argument patterns 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); + self.infer_top_pat(*arg_pat, arg_ty, 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.to_chalk(interner)); + let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty); 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); @@ -171,7 +160,7 @@ impl<'db> InferenceContext<'db> { self.current_closure = prev_closure; self.resume_yield_tys = prev_resume_yield_tys; - ty.to_chalk(interner) + ty } fn fn_trait_kind_from_def_id(&self, trait_id: TraitId) -> Option { @@ -209,14 +198,13 @@ impl<'db> InferenceContext<'db> { .deduce_closure_signature_from_predicates( expected_ty, closure_kind, - explicit_item_bounds(self.table.interner, def_id) - .iter_instantiated(self.table.interner, args) + explicit_item_bounds(self.interner(), def_id) + .iter_instantiated(self.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)); + let pb = pb.with_self_ty(self.interner(), Ty::new_unit(self.interner())); self.deduce_sig_from_projection(closure_kind, pb) }); let kind = object_type @@ -226,7 +214,7 @@ impl<'db> InferenceContext<'db> { } 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)), + Ty::new_var(self.interner(), self.table.infer_ctxt.root_var(vid)), closure_kind, self.table.obligations_for_self_ty(vid).into_iter().map(|obl| obl.predicate), ), @@ -251,7 +239,7 @@ impl<'db> InferenceContext<'db> { let mut expected_kind = None; for pred in rustc_type_ir::elaborate::elaborate( - self.table.interner, + self.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. @@ -313,7 +301,7 @@ impl<'db> InferenceContext<'db> { // 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); + let inferred_fnptr_sig = Ty::new_fn_ptr(self.interner(), inferred_sig); // FIXME: Report diagnostics. _ = self .table @@ -326,7 +314,7 @@ impl<'db> InferenceContext<'db> { 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)); + expected_sig = Some(resolved_sig.fn_sig(self.interner())); } } else if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { expected_sig = inferred_sig; @@ -339,7 +327,7 @@ impl<'db> InferenceContext<'db> { // 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) + Some(data.projection_term.trait_def_id(self.interner()).0) } PredicateKind::Clause(ClauseKind::Trait(data)) => Some(data.def_id().0), _ => None, @@ -427,7 +415,7 @@ impl<'db> InferenceContext<'db> { let ret_param_ty = projection.skip_binder().term.expect_type(); debug!(?ret_param_ty); - let sig = projection.rebind(self.table.interner.mk_fn_sig( + let sig = projection.rebind(self.interner().mk_fn_sig( input_tys, ret_param_ty, false, @@ -515,7 +503,7 @@ impl<'db> InferenceContext<'db> { // 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( + let sig = projection.rebind(self.interner().mk_fn_sig( input_tys, return_ty, false, @@ -619,7 +607,7 @@ impl<'db> InferenceContext<'db> { // 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( + self.interner().mk_fn_sig( sig.inputs(), sig.output(), sig.c_variadic, @@ -631,7 +619,7 @@ impl<'db> InferenceContext<'db> { // `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); + let bound_sig = self.interner().anonymize_bound_vars(bound_sig); let closure_sigs = self.closure_sigs(bound_sig); @@ -723,7 +711,7 @@ impl<'db> InferenceContext<'db> { .into_iter() .map(|ty| table.infer_ctxt.resolve_vars_if_possible(ty)); - expected_sigs.liberated_sig = table.interner.mk_fn_sig( + expected_sigs.liberated_sig = table.interner().mk_fn_sig( inputs, supplied_output_ty, expected_sigs.liberated_sig.c_variadic, @@ -744,12 +732,12 @@ impl<'db> InferenceContext<'db> { decl_inputs: &[Option], decl_output: Option, ) -> PolyFnSig<'db> { - let interner = self.table.interner; + let interner = self.interner(); let supplied_return = match decl_output { Some(output) => { let output = self.make_body_ty(output); - self.process_user_written_ty(output).to_nextsolver(interner) + self.process_user_written_ty(output) } None => self.table.next_ty_var(), }; @@ -757,7 +745,7 @@ impl<'db> InferenceContext<'db> { 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) + self.process_user_written_ty(input) } None => self.table.next_ty_var(), }); @@ -779,7 +767,7 @@ impl<'db> InferenceContext<'db> { decl_inputs: &[Option], decl_output: Option, ) -> PolyFnSig<'db> { - let interner = self.table.interner; + let interner = self.interner(); let err_ty = Ty::new_error(interner, ErrorGuaranteed); if let Some(output) = decl_output { 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 index fd14b9e2de571..8a6ce0a69bda7 100644 --- 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 @@ -2,10 +2,6 @@ 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, @@ -20,44 +16,47 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::sym; +use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _}; 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, + Adjust, Adjustment, BindingMode, + db::{HirDatabase, InternedClosure, InternedClosureId}, + infer::InferenceContext, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, + next_solver::{ + DbInterner, EarlyBinder, GenericArgs, Ty, TyKind, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, 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) struct HirPlace<'db> { pub(crate) local: BindingId, - pub(crate) projections: Vec>, + 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()); +impl<'db> HirPlace<'db> { + fn ty(&self, ctx: &mut InferenceContext<'_, 'db>) -> Ty<'db> { + let mut ty = ctx.table.resolve_completely(ctx.result[self.local]); 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 = p + .projected_ty( + ty.to_chalk(ctx.interner()), + ctx.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + ctx.owner.module(ctx.db).krate(), + ) + .to_nextsolver(ctx.interner()); } ty } @@ -86,8 +85,8 @@ pub enum CaptureKind { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct CapturedItem { - pub(crate) place: HirPlace, +pub struct CapturedItem<'db> { + pub(crate) place: HirPlace<'db>, pub(crate) kind: CaptureKind, /// The inner vec is the stacks; the outer vec is for each capture reference. /// @@ -96,10 +95,10 @@ pub struct CapturedItem { /// 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, + pub(crate) ty: EarlyBinder<'db, Ty<'db>>, } -impl CapturedItem { +impl<'db> CapturedItem<'db> { pub fn local(&self) -> BindingId { self.place.local } @@ -109,8 +108,9 @@ impl CapturedItem { 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 ty(&self, db: &'db dyn HirDatabase, subst: GenericArgs<'db>) -> Ty<'db> { + let interner = DbInterner::new_with(db, None, None); + self.ty.instantiate(interner, subst.split_closure_args_untupled().parent_args) } pub fn kind(&self) -> CaptureKind { @@ -279,15 +279,15 @@ impl CapturedItem { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct CapturedItemWithoutTy { - pub(crate) place: HirPlace, +pub(crate) struct CapturedItemWithoutTy<'db> { + pub(crate) place: HirPlace<'db>, 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 { +impl<'db> CapturedItemWithoutTy<'db> { + fn with_ty(self, ctx: &mut InferenceContext<'_, 'db>) -> CapturedItem<'db> { let ty = self.place.ty(ctx); let ty = match &self.kind { CaptureKind::ByValue => ty, @@ -296,66 +296,20 @@ impl CapturedItemWithoutTy { BorrowKind::Mut { .. } => Mutability::Mut, _ => Mutability::Not, }; - TyKind::Ref(m, error_lifetime(), ty).intern(Interner) + Ty::new_ref(ctx.interner(), ctx.types.re_error, ty, m) } }; - return CapturedItem { + 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) + ty: EarlyBinder::bind(ty), } } } -impl InferenceContext<'_> { - fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option { +impl<'db> InferenceContext<'_, 'db> { + 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(); @@ -363,7 +317,7 @@ impl InferenceContext<'_> { } /// Pushes the span into `current_capture_span_stack`, *without clearing it first*. - fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { + fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option> { if path.type_anchor().is_some() { return None; } @@ -384,7 +338,7 @@ impl InferenceContext<'_> { } /// 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 { + 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) => { @@ -403,8 +357,8 @@ impl InferenceContext<'_> { } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { if matches!( - self.expr_ty_after_adjustments(*expr).kind(Interner), - TyKind::Ref(..) | TyKind::Raw(..) + self.expr_ty_after_adjustments(*expr).kind(), + TyKind::Ref(..) | TyKind::RawPtr(..) ) { let mut place = self.place_of_expr(*expr)?; self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr)); @@ -417,7 +371,7 @@ impl InferenceContext<'_> { None } - fn push_capture(&mut self, place: HirPlace, kind: CaptureKind) { + fn push_capture(&mut self, place: HirPlace<'db>, kind: CaptureKind) { self.current_captures.push(CapturedItemWithoutTy { place, kind, @@ -425,7 +379,11 @@ impl InferenceContext<'_> { }); } - fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut truncate_to: usize) { + fn truncate_capture_spans( + &self, + capture: &mut CapturedItemWithoutTy<'db>, + 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 { @@ -450,14 +408,14 @@ impl InferenceContext<'_> { } } - fn ref_expr(&mut self, expr: ExprId, place: Option) { + 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) { + fn add_capture(&mut self, place: HirPlace<'db>, kind: CaptureKind) { if self.is_upvar(&place) { self.push_capture(place, kind); } @@ -473,7 +431,7 @@ impl InferenceContext<'_> { } } - fn mutate_expr(&mut self, expr: ExprId, place: Option) { + fn mutate_expr(&mut self, expr: ExprId, place: Option>) { if let Some(place) = place { self.add_capture( place, @@ -490,7 +448,7 @@ impl InferenceContext<'_> { self.walk_expr(expr); } - fn consume_place(&mut self, place: HirPlace) { + fn consume_place(&mut self, place: HirPlace<'db>) { if self.is_upvar(&place) { let ty = place.ty(self); let kind = if self.is_ty_copy(ty) { @@ -502,7 +460,7 @@ impl InferenceContext<'_> { } } - fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) { + fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment<'db>]) { if let Some((last, rest)) = adjustment.split_last() { match &last.kind { Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => { @@ -523,7 +481,12 @@ impl InferenceContext<'_> { } } - fn ref_capture_with_adjusts(&mut self, m: Mutability, tgt_expr: ExprId, rest: &[Adjustment]) { + fn ref_capture_with_adjusts( + &mut self, + m: Mutability, + tgt_expr: ExprId, + rest: &[Adjustment<'db>], + ) { let capture_kind = match m { Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared), @@ -652,8 +615,8 @@ impl InferenceContext<'_> { 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.expr_ty_after_adjustments(*expr).kind(), + TyKind::Ref(..) | TyKind::RawPtr(..) ) { self.select_from_expr(*expr); } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) { @@ -728,12 +691,12 @@ impl InferenceContext<'_> { } Expr::Closure { .. } => { let ty = self.expr_ty(tgt_expr); - let TyKind::Closure(id, _) = ty.kind(Interner) else { + let TyKind::Closure(id, _) = ty.kind() else { never!("closure type is always closure"); return; }; let (captures, _) = - self.result.closure_info.get(id).expect( + self.result.closure_info.get(&id.0).expect( "We sort closures, so we should always have data for inner closures", ); let mut cc = mem::take(&mut self.current_captures); @@ -830,7 +793,7 @@ impl InferenceContext<'_> { } Pat::Bind { id, .. } => match self.result.binding_modes[p] { crate::BindingMode::Move => { - if self.is_ty_copy(self.result.type_of_binding[*id].clone()) { + if self.is_ty_copy(self.result.type_of_binding[*id]) { update_result(CaptureKind::ByRef(BorrowKind::Shared)); } else { update_result(CaptureKind::ByValue); @@ -848,21 +811,21 @@ impl InferenceContext<'_> { 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(&self, expr: ExprId) -> Ty<'db> { + self.result[expr] } - fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { + fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty<'db> { 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 = Some(it.target); } ty.unwrap_or_else(|| self.expr_ty(e)) } - fn is_upvar(&self, place: &HirPlace) -> bool { + fn is_upvar(&self, place: &HirPlace<'db>) -> 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); @@ -870,14 +833,20 @@ impl InferenceContext<'_> { false } - fn is_ty_copy(&mut self, ty: Ty) -> bool { - if let TyKind::Closure(id, _) = ty.kind(Interner) { + fn is_ty_copy(&mut self, ty: Ty<'db>) -> bool { + if let TyKind::Closure(id, _) = ty.kind() { // 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); + return self + .result + .closure_info + .get(&id.0) + .map(|it| it.1 == FnTrait::Fn) + .unwrap_or(true); } - self.table.resolve_completely(ty).is_copy(self.db, self.owner) + let ty = self.table.resolve_completely(ty); + self.table.type_is_copy_modulo_regions(ty) } fn select_from_expr(&mut self, expr: ExprId) { @@ -888,23 +857,25 @@ impl InferenceContext<'_> { // 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() { + let mut ty = self.table.resolve_completely(self.result[capture.place.local]); + if ty.is_raw_ptr() || 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() { + ty = p + .projected_ty( + ty.to_chalk(self.interner()), + self.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + self.owner.module(self.db).krate(), + ) + .to_nextsolver(self.interner()); + if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); self.truncate_capture_spans(capture, i + 1); capture.place.projections.truncate(i + 1); @@ -932,7 +903,7 @@ impl InferenceContext<'_> { fn minimize_captures(&mut self) { self.current_captures.sort_unstable_by_key(|it| it.place.projections.len()); - let mut hash_map = FxHashMap::::default(); + let mut hash_map = FxHashMap::, usize>::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![] }; @@ -967,7 +938,7 @@ impl InferenceContext<'_> { } } - fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { + fn consume_with_pat(&mut self, mut place: HirPlace<'db>, 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)); @@ -978,8 +949,8 @@ impl InferenceContext<'_> { 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), + let field_count = match self.result[tgt_pat].kind() { + TyKind::Tuple(s) => s.len(), _ => break 'reset_span_stack, }; let fields = 0..field_count; @@ -1125,9 +1096,9 @@ impl InferenceContext<'_> { 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()); + fn analyze_closure(&mut self, closure: InternedClosureId) -> FnTrait { + let InternedClosure(_, root) = self.db.lookup_intern_closure(closure); + self.current_closure = Some(closure); let Expr::Closure { body, capture_by, .. } = &self.body[root] else { unreachable!("Closure expression id is always closure"); }; @@ -1193,9 +1164,9 @@ impl InferenceContext<'_> { self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); self.write_fn_trait_method_resolution( kind, - &derefed_callee, + derefed_callee, &mut adjustments, - &callee_ty, + callee_ty, ¶ms, expr, ); @@ -1213,27 +1184,26 @@ impl InferenceContext<'_> { /// /// 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)>)> { + fn sort_closures( + &mut self, + ) -> Vec<(InternedClosureId, Vec<(Ty<'db>, Ty<'db>, 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(); + 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).into()).or_default() += 1; + *dependents_count.entry(*dep).or_default() += 1; } } - let mut queue: Vec<_> = deferred_closures - .keys() - .copied() - .filter(|&it| dependents_count[&it.into()] == 0) - .collect(); + 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.into(), d)); + 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.into()).unwrap(); + let cnt = dependents_count.get_mut(&dep).unwrap(); *cnt -= 1; if *cnt == 0 { queue.push(dep); @@ -1279,11 +1249,11 @@ impl InferenceContext<'_> { } /// Call this only when the last span in the stack isn't a split. -fn apply_adjusts_to_place( +fn apply_adjusts_to_place<'db>( current_capture_span_stack: &mut Vec, - mut r: HirPlace, - adjustments: &[Adjustment], -) -> Option { + mut r: HirPlace<'db>, + adjustments: &[Adjustment<'db>], +) -> Option> { let span = *current_capture_span_stack.last().expect("empty capture span stack"); for adj in adjustments { match &adj.kind { 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 62ce00a2e33d4..10c1f9c980917 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 @@ -35,7 +35,6 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` -use chalk_ir::cast::Cast; use hir_def::{ CallableDefId, hir::{ExprId, ExprOrPatId}, @@ -45,22 +44,23 @@ use hir_def::{ use intern::sym; use rustc_ast_ir::Mutability; use rustc_type_ir::{ - TypeAndMut, + BoundVar, TypeAndMut, error::TypeError, - inherent::{IntoKind, Safety, Ty as _}, + inherent::{Const as _, GenericArg as _, IntoKind, Region as _, Safety, SliceLike, Ty as _}, }; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, Interner, PointerCast, TargetFeatures, TraitEnvironment, + Adjust, Adjustment, AutoBorrow, 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, + Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper, + ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, + PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty, TyKind, infer::{ DefineOpaqueTypes, InferCtxt, InferOk, InferResult, relate::RelateResult, @@ -93,7 +93,7 @@ struct Coerce<'a, 'b, 'db> { cause: ObligationCause, } -type CoerceResult<'db> = InferResult<'db, (Vec, Ty<'db>)>; +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. @@ -103,7 +103,7 @@ fn coerce_mutbls<'db>(from_mutbl: Mutability, to_mutbl: Mutability) -> RelateRes /// This always returns `Ok(...)`. fn success<'db>( - adj: Vec, + adj: Vec>, target: Ty<'db>, obligations: PredicateObligations<'db>, ) -> CoerceResult<'db> { @@ -118,7 +118,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { #[inline] fn interner(&self) -> DbInterner<'db> { - self.table.interner + self.table.interner() } #[inline] @@ -182,17 +182,14 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { &mut self, a: Ty<'db>, b: Ty<'db>, - adjustments: impl IntoIterator, - final_adjustment: Adjust, + adjustments: impl IntoIterator>, + final_adjustment: Adjust<'db>, ) -> 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, - })) + .chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment })) .collect(), ty, obligations, @@ -216,10 +213,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { if self.coerce_never { return success( - vec![Adjustment { - kind: Adjust::NeverToAny, - target: b.to_chalk(self.interner()), - }], + vec![Adjustment { kind: Adjust::NeverToAny, target: b }], b, PredicateObligations::new(), ); @@ -241,10 +235,9 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { && 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()) + && let Some(ty) = tait_table.get(&opaque_ty_id) { - b = ty.to_nextsolver(self.interner()); - b = self.table.shallow_resolve(b); + b = self.table.shallow_resolve(*ty); } let b = b; @@ -474,7 +467,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { r_borrow_var.unwrap() }; let derefd_ty_a = Ty::new_ref( - autoderef.table.interner, + autoderef.table.interner(), r, referent_ty, mutbl_b, // [1] above @@ -547,11 +540,8 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { panic!("expected a ref type, got {:?}", ty); }; adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref( - region.to_chalk(self.interner()), - mutbl_b.to_chalk(self.interner()), - )), - target: ty.to_chalk(self.interner()), + kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl_b)), + target: ty, }); debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, adjustments); @@ -655,20 +645,13 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { // 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()); + let mutbl = mutbl_b; Some(( + Adjustment { kind: Adjust::Deref(None), target: ty_a }, 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()), + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), + target: Ty::new_ref(self.interner(), r_borrow, ty_a, mutbl_b), }, )) } @@ -676,20 +659,16 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { coerce_mutbls(mt_a, mt_b)?; Some(( + Adjustment { kind: Adjust::Deref(None), target: ty_a }, 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()), + kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), + target: Ty::new_ptr(self.interner(), ty_a, mt_b), }, )) } _ => None, }; - let coerce_source = - reborrow.as_ref().map_or(source, |(_, r)| r.target.to_nextsolver(self.interner())); + let coerce_source = reborrow.as_ref().map_or(source, |(_, r)| r.target); // Setup either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. @@ -834,7 +813,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { &mut self, fn_ty_a: PolyFnSig<'db>, b: Ty<'db>, - adjustment: Option, + adjustment: Option>, ) -> CoerceResult<'db> { debug_assert!(self.table.shallow_resolve(b) == b); @@ -849,7 +828,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { b, adjustment.map(|kind| Adjustment { kind, - target: Ty::new_fn_ptr(this.interner(), fn_ty_a).to_chalk(this.interner()), + target: Ty::new_fn_ptr(this.interner(), fn_ty_a), }), Adjust::Pointer(PointerCast::UnsafeFnPointer), ) @@ -961,9 +940,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { pointer_ty, b, [], - Adjust::Pointer(PointerCast::ClosureFnPointer( - safety.to_chalk(self.interner()), - )), + Adjust::Pointer(PointerCast::ClosureFnPointer(safety)), ) } _ => self.unify(a, b), @@ -991,11 +968,8 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { 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()))), + [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }], + Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), ) } else if mt_a.mutbl != mutbl_b { self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCast::MutToConstPointer)) @@ -1011,7 +985,7 @@ pub(crate) enum CoerceNever { Yes, } -impl<'db> InferenceContext<'db> { +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. @@ -1128,13 +1102,13 @@ impl<'db> InferenceContext<'db> { // 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)), + 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 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 @@ -1142,7 +1116,7 @@ impl<'db> InferenceContext<'db> { (Some(a_sig), Some(b_sig)) } (TyKind::FnDef(..), TyKind::Closure(_, args)) => { - let a_sig = prev_ty.fn_sig(self.table.interner); + 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 @@ -1166,36 +1140,30 @@ impl<'db> InferenceContext<'db> { .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 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::Closure(..) => { + Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.safety())) + } 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::Closure(..) => { + Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.safety())) + } 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), - }]), + Box::new([Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }]), ); } self.write_expr_adj( new, - Box::new([Adjustment { - kind: next_adjustment, - target: fn_ptr.to_chalk(self.table.interner), - }]), + Box::new([Adjustment { kind: next_adjustment, target: fn_ptr }]), ); return Ok(fn_ptr); } @@ -1382,7 +1350,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// if necessary. pub(crate) fn coerce( &mut self, - icx: &mut InferenceContext<'db>, + icx: &mut InferenceContext<'_, 'db>, cause: &ObligationCause, expression: ExprId, expression_ty: Ty<'db>, @@ -1404,19 +1372,12 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// removing a `;`). pub(crate) fn coerce_forced_unit( &mut self, - icx: &mut InferenceContext<'db>, + 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, - ) + self.coerce_inner(icx, cause, expr, icx.types.unit, true, label_unit_as_expected) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1424,7 +1385,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// `Nil`. pub(crate) fn coerce_inner( &mut self, - icx: &mut InferenceContext<'db>, + icx: &mut InferenceContext<'_, 'db>, cause: &ObligationCause, expression: ExprId, mut expression_ty: Ty<'db>, @@ -1533,20 +1494,14 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { // 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)); + self.final_ty = Some(icx.types.error); 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), - } + TypeMismatch { expected: found, actual: expected } } else { - TypeMismatch { - expected: expected.to_chalk(icx.table.interner), - actual: found.to_chalk(icx.table.interner), - } + TypeMismatch { expected, actual: found } }, ); } @@ -1555,14 +1510,14 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { self.pushed += 1; } - pub(crate) fn complete(self, icx: &mut InferenceContext<'db>) -> Ty<'db> { + 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) + icx.types.never } } } @@ -1579,11 +1534,11 @@ fn coerce<'db>( db: &'db dyn HirDatabase, env: Arc>, tys: &crate::Canonical<(crate::Ty, crate::Ty)>, -) -> Result<(Vec, crate::Ty), TypeError>> { +) -> 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 interner = table.interner(); + let tys = tys.to_nextsolver(interner); + let ((ty1_with_vars, ty2_with_vars), vars) = table.infer_ctxt.instantiate_canonical(&tys); let cause = ObligationCause::new(); // FIXME: Target features. @@ -1597,36 +1552,67 @@ fn coerce<'db>( 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), - )?; + let InferOk { value: (adjustments, ty), obligations } = + coerce.coerce(ty1_with_vars, ty2_with_vars)?; 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 mut fallback_ty = |debruijn, infer| { + let var = vars.var_values.iter().position(|arg| { + arg.as_type().is_some_and(|ty| match ty.kind() { + TyKind::Infer(it) => infer == it, + _ => false, + }) + }); + var.map_or_else( + || Ty::new_error(interner, ErrorGuaranteed), + |i| { + Ty::new_bound( + interner, + debruijn, + BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_usize(i) }, + ) + }, + ) + }; + let mut fallback_const = |debruijn, infer| { + let var = vars.var_values.iter().position(|arg| { + arg.as_const().is_some_and(|ty| match ty.kind() { + ConstKind::Infer(it) => infer == it, + _ => false, + }) + }); + var.map_or_else( + || Const::new_error(interner, ErrorGuaranteed), + |i| Const::new_bound(interner, debruijn, BoundConst { var: BoundVar::from_usize(i) }), + ) }; - let fallback = |iv, kind, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else( - || chalk_ir::TyKind::Error.intern(Interner).cast(Interner), - |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner), - ), - chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else( - || crate::LifetimeData::Error.intern(Interner).cast(Interner), - |i| crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner), - ), - chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else( - || crate::unknown_const(ty.clone()).cast(Interner), - |i| crate::BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner), - ), + let mut fallback_region = |debruijn, infer| { + let var = vars.var_values.iter().position(|arg| { + arg.as_region().is_some_and(|ty| match ty.kind() { + RegionKind::ReVar(it) => infer == it, + _ => false, + }) + }); + var.map_or_else( + || Region::error(interner), + |i| { + Region::new_bound( + interner, + debruijn, + BoundRegion { kind: BoundRegionKind::Anon, var: BoundVar::from_usize(i) }, + ) + }, + ) }; // FIXME also map the types in the adjustments // FIXME: We don't fallback correctly since this is done on `InferenceContext` and we only have `InferenceTable`. - Ok((adjustments, table.resolve_with_fallback(ty.to_chalk(table.interner), &fallback))) + let ty = table.resolve_with_fallback( + ty, + &mut fallback_ty, + &mut fallback_const, + &mut fallback_region, + ); + Ok((adjustments, ty.to_chalk(interner))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs index 003364d4336b6..39e70c262a24a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs @@ -12,11 +12,11 @@ use hir_def::expr_store::path::Path; use hir_def::{hir::ExprOrPatId, resolver::Resolver}; use la_arena::{Idx, RawIdx}; -use crate::lower::LifetimeElisionKind; use crate::{ - InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringContext, TyLoweringDiagnostic, + InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, db::HirDatabase, - lower::path::{PathDiagnosticCallback, PathLoweringContext}, + lower_nextsolver::path::{PathDiagnosticCallback, PathLoweringContext}, + lower_nextsolver::{LifetimeElisionKind, TyLoweringContext}, }; // Unfortunately, this struct needs to use interior mutability (but we encapsulate it) @@ -24,10 +24,10 @@ use crate::{ // to our resolver and so we cannot have mutable reference, but we really want to have // ability to dispatch diagnostics during this work otherwise the code becomes a complete mess. #[derive(Debug, Default, Clone)] -pub(super) struct Diagnostics(RefCell>); +pub(super) struct Diagnostics<'db>(RefCell>>); -impl Diagnostics { - pub(super) fn push(&self, diagnostic: InferenceDiagnostic) { +impl<'db> Diagnostics<'db> { + pub(super) fn push(&self, diagnostic: InferenceDiagnostic<'db>) { self.0.borrow_mut().push(diagnostic); } @@ -41,32 +41,32 @@ impl Diagnostics { ); } - pub(super) fn finish(self) -> Vec { + pub(super) fn finish(self) -> Vec> { self.0.into_inner() } } -pub(crate) struct PathDiagnosticCallbackData<'a> { +pub(crate) struct PathDiagnosticCallbackData<'a, 'db> { node: ExprOrPatId, - diagnostics: &'a Diagnostics, + diagnostics: &'a Diagnostics<'db>, } -pub(super) struct InferenceTyLoweringContext<'a> { - ctx: TyLoweringContext<'a>, - diagnostics: &'a Diagnostics, +pub(super) struct InferenceTyLoweringContext<'db, 'a> { + ctx: TyLoweringContext<'db, 'a>, + diagnostics: &'a Diagnostics<'db>, source: InferenceTyDiagnosticSource, } -impl<'a> InferenceTyLoweringContext<'a> { +impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { #[inline] pub(super) fn new( - db: &'a dyn HirDatabase, - resolver: &'a Resolver<'_>, + db: &'db dyn HirDatabase, + resolver: &'a Resolver<'db>, store: &'a ExpressionStore, - diagnostics: &'a Diagnostics, + diagnostics: &'a Diagnostics<'db>, source: InferenceTyDiagnosticSource, generic_def: GenericDefId, - lifetime_elision: LifetimeElisionKind, + lifetime_elision: LifetimeElisionKind<'db>, ) -> Self { Self { ctx: TyLoweringContext::new(db, resolver, store, generic_def, lifetime_elision), @@ -80,7 +80,7 @@ impl<'a> InferenceTyLoweringContext<'a> { &'b mut self, path: &'b Path, node: ExprOrPatId, - ) -> PathLoweringContext<'b, 'a> { + ) -> PathLoweringContext<'b, 'a, 'db> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }), callback: |data, _, diag| { @@ -96,7 +96,7 @@ impl<'a> InferenceTyLoweringContext<'a> { pub(super) fn at_path_forget_diagnostics<'b>( &'b mut self, path: &'b Path, - ) -> PathLoweringContext<'b, 'a> { + ) -> PathLoweringContext<'b, 'a, 'db> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, @@ -113,8 +113,8 @@ impl<'a> InferenceTyLoweringContext<'a> { } } -impl<'a> Deref for InferenceTyLoweringContext<'a> { - type Target = TyLoweringContext<'a>; +impl<'db, 'a> Deref for InferenceTyLoweringContext<'db, 'a> { + type Target = TyLoweringContext<'db, 'a>; #[inline] fn deref(&self) -> &Self::Target { @@ -122,14 +122,14 @@ impl<'a> Deref for InferenceTyLoweringContext<'a> { } } -impl DerefMut for InferenceTyLoweringContext<'_> { +impl DerefMut for InferenceTyLoweringContext<'_, '_> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.ctx } } -impl Drop for InferenceTyLoweringContext<'_> { +impl Drop for InferenceTyLoweringContext<'_, '_> { #[inline] fn drop(&mut self) { self.diagnostics 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 ddf632c1c81b5..b4140d88db349 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 @@ -2,12 +2,11 @@ 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}, + expr_store::path::{GenericArg as HirGenericArg, GenericArgs as HirGenericArgs, Path}, hir::{ ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, Expr, ExprId, ExprOrPatId, LabelId, Literal, Pat, PatId, Statement, UnaryOp, generics::GenericParamDataRef, @@ -17,19 +16,19 @@ 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 rustc_ast_ir::Mutability; +use rustc_type_ir::{ + AliasTyKind, InferTy, Interner, + inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _}, +}; use syntax::ast::RangeOp; use tracing::debug; -use crate::autoderef::overloaded_deref_ty; -use crate::next_solver::infer::DefineOpaqueTypes; -use crate::next_solver::obligation_ctxt::ObligationCtxt; -use crate::next_solver::{DbInterner, ErrorGuaranteed}; use crate::{ - Adjust, Adjustment, AdtId, AutoBorrow, CallableDefId, CallableSig, DeclContext, DeclOrigin, - IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval, + Adjust, Adjustment, AutoBorrow, CallableDefId, DeclContext, DeclOrigin, + IncorrectGenericsLenKind, Rawness, TraitEnvironment, + autoderef::overloaded_deref_ty, + consteval_nextsolver, generics::generics, infer::{ AllowTwoPhase, BreakableKind, @@ -38,18 +37,20 @@ use crate::{ pat::contains_explicit_ref_binding, }, lang_items::lang_items_for_bin_op, - lower::{ - ParamLoweringMode, lower_to_chalk_mutability, + lower_nextsolver::{ + LifetimeElisionKind, lower_mutability, path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings}, }, - mapping::{ToChalk, from_chalk}, method_resolution::{self, VisibleFromModule}, next_solver::{ - infer::traits::ObligationCause, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind, + TypeError, + infer::{ + DefineOpaqueTypes, InferOk, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, }, - primitive::{self, UintTy}, - static_lifetime, to_chalk_trait_id, traits::FnTrait, }; @@ -64,27 +65,30 @@ pub(crate) enum ExprIsRead { No, } -impl<'db> InferenceContext<'db> { +impl<'db> InferenceContext<'_, 'db> { pub(crate) fn infer_expr( &mut self, tgt_expr: ExprId, - expected: &Expectation, + expected: &Expectation<'db>, is_read: ExprIsRead, - ) -> Ty { + ) -> Ty<'db> { let ty = self.infer_expr_inner(tgt_expr, expected, is_read); if let Some(expected_ty) = expected.only_has_type(&mut self.table) { - let could_unify = self.unify(&ty, &expected_ty); + let could_unify = self.unify(ty, expected_ty); if !could_unify { - self.result.type_mismatches.insert( - tgt_expr.into(), - TypeMismatch { expected: expected_ty, actual: ty.clone() }, - ); + self.result + .type_mismatches + .insert(tgt_expr.into(), TypeMismatch { expected: expected_ty, actual: ty }); } } ty } - pub(crate) fn infer_expr_no_expect(&mut self, tgt_expr: ExprId, is_read: ExprIsRead) -> Ty { + pub(crate) fn infer_expr_no_expect( + &mut self, + tgt_expr: ExprId, + is_read: ExprIsRead, + ) -> Ty<'db> { self.infer_expr_inner(tgt_expr, &Expectation::None, is_read) } @@ -93,9 +97,9 @@ impl<'db> InferenceContext<'db> { pub(super) fn infer_expr_coerce( &mut self, expr: ExprId, - expected: &Expectation, + expected: &Expectation<'db>, is_read: ExprIsRead, - ) -> Ty { + ) -> Ty<'db> { let ty = self.infer_expr_inner(expr, expected, is_read); if let Some(target) = expected.only_has_type(&mut self.table) { let coerce_never = if self.expr_guaranteed_to_constitute_read_for_never(expr, is_read) { @@ -103,19 +107,12 @@ impl<'db> InferenceContext<'db> { } else { CoerceNever::No }; - 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), + match self.coerce(expr.into(), ty, target, AllowTwoPhase::No, coerce_never) { + Ok(res) => res, Err(_) => { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: target.clone(), actual: ty.clone() }, - ); + self.result + .type_mismatches + .insert(expr.into(), TypeMismatch { expected: target, actual: ty }); target } } @@ -255,42 +252,34 @@ impl<'db> InferenceContext<'db> { fn infer_expr_coerce_never( &mut self, expr: ExprId, - expected: &Expectation, + expected: &Expectation<'db>, is_read: ExprIsRead, - ) -> Ty { + ) -> Ty<'db> { let ty = self.infer_expr_inner(expr, expected, is_read); // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from `!` to `expected`. if ty.is_never() { if let Some(adjustments) = self.result.expr_adjustments.get(&expr) { return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments { - target.clone() + *target } else { self.err_ty() }; } if let Some(target) = expected.only_has_type(&mut self.table) { - 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) + self.coerce(expr.into(), ty, target, AllowTwoPhase::No, CoerceNever::Yes) + .expect("never-to-any coercion should always succeed") } else { ty } } else { if let Some(expected_ty) = expected.only_has_type(&mut self.table) { - let could_unify = self.unify(&ty, &expected_ty); + let could_unify = self.unify(ty, expected_ty); if !could_unify { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: expected_ty, actual: ty.clone() }, - ); + self.result + .type_mismatches + .insert(expr.into(), TypeMismatch { expected: expected_ty, actual: ty }); } } ty @@ -301,9 +290,9 @@ impl<'db> InferenceContext<'db> { fn infer_expr_inner( &mut self, tgt_expr: ExprId, - expected: &Expectation, + expected: &Expectation<'db>, is_read: ExprIsRead, - ) -> Ty { + ) -> Ty<'db> { self.db.unwind_if_revision_cancelled(); let expr = &self.body[tgt_expr]; @@ -314,7 +303,7 @@ impl<'db> InferenceContext<'db> { let expected = &expected.adjust_for_branches(&mut self.table); self.infer_expr_coerce_never( condition, - &Expectation::HasType(self.result.standard_types.bool_.clone()), + &Expectation::HasType(self.types.bool), ExprIsRead::Yes, ); @@ -327,27 +316,15 @@ impl<'db> InferenceContext<'db> { coercion_sites[1] = else_branch; } let mut coerce = CoerceMany::with_coercion_sites( - expected - .coercion_target_type(&mut self.table) - .to_nextsolver(self.table.interner), + expected.coercion_target_type(&mut self.table), &coercion_sites, ); - coerce.coerce( - self, - &ObligationCause::new(), - then_branch, - then_ty.to_nextsolver(self.table.interner), - ); + coerce.coerce(self, &ObligationCause::new(), then_branch, then_ty); 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, - &ObligationCause::new(), - else_branch, - else_ty.to_nextsolver(self.table.interner), - ); + coerce.coerce(self, &ObligationCause::new(), else_branch, else_ty); self.diverges = condition_diverges | then_diverges & else_diverges; } None => { @@ -356,7 +333,7 @@ impl<'db> InferenceContext<'db> { } } - coerce.complete(self).to_chalk(self.table.interner) + coerce.complete(self) } &Expr::Let { pat, expr } => { let child_is_read = if self.pat_guaranteed_to_constitute_read_for_never(pat) { @@ -367,10 +344,10 @@ impl<'db> InferenceContext<'db> { let input_ty = self.infer_expr(expr, &Expectation::none(), child_is_read); self.infer_top_pat( pat, - &input_ty, + input_ty, Some(DeclContext { origin: DeclOrigin::LetExpr }), ); - self.result.standard_types.bool_.clone() + self.types.bool } Expr::Block { statements, tail, label, id } => { self.infer_block(tgt_expr, *id, statements, *tail, *label, expected) @@ -390,12 +367,12 @@ impl<'db> InferenceContext<'db> { &Expr::Loop { body, label } => { // FIXME: should be: // let ty = expected.coercion_target_type(&mut self.table); - let ty = self.table.new_type_var(); + let ty = self.table.next_ty_var(); let (breaks, ()) = self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| { this.infer_expr( body, - &Expectation::HasType(TyBuilder::unit()), + &Expectation::HasType(this.types.unit), ExprIsRead::Yes, ); }); @@ -405,7 +382,7 @@ impl<'db> InferenceContext<'db> { self.diverges = Diverges::Maybe; breaks } - None => self.result.standard_types.never.clone(), + None => self.types.never, } } Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => self @@ -438,32 +415,30 @@ impl<'db> InferenceContext<'db> { if arms.is_empty() { self.diverges = Diverges::Always; - self.result.standard_types.never.clone() + self.types.never } else { 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.table.structurally_resolve_type(&input_ty); - self.infer_top_pat(arm.pat, &input_ty, None); + let input_ty = self.table.structurally_resolve_type(input_ty); + self.infer_top_pat(arm.pat, input_ty, None); } let expected = expected.adjust_for_branches(&mut self.table); let result_ty = match &expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. - Expectation::HasType(ty) if *ty != self.result.standard_types.unit => { - ty.clone() - } - _ => self.table.new_type_var(), + Expectation::HasType(ty) if *ty != self.types.unit => *ty, + _ => self.table.next_ty_var(), }; - let mut coerce = CoerceMany::new(result_ty.to_nextsolver(self.table.interner)); + let mut coerce = CoerceMany::new(result_ty); for arm in arms.iter() { if let Some(guard_expr) = arm.guard { self.diverges = Diverges::Maybe; self.infer_expr_coerce_never( guard_expr, - &Expectation::HasType(self.result.standard_types.bool_.clone()), + &Expectation::HasType(self.types.bool), ExprIsRead::Yes, ); } @@ -471,17 +446,12 @@ impl<'db> InferenceContext<'db> { let arm_ty = self.infer_expr_inner(arm.expr, &expected, ExprIsRead::Yes); all_arms_diverge &= self.diverges; - coerce.coerce( - self, - &ObligationCause::new(), - arm.expr, - arm_ty.to_nextsolver(self.table.interner), - ); + coerce.coerce(self, &ObligationCause::new(), arm.expr, arm_ty); } self.diverges = matchee_diverges | all_arms_diverge; - coerce.complete(self).to_chalk(self.table.interner) + coerce.complete(self) } } Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr), @@ -493,13 +463,13 @@ impl<'db> InferenceContext<'db> { bad_value_break: false, }); }; - self.result.standard_types.never.clone() + self.types.never } &Expr::Break { expr, label } => { 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().to_chalk(self.table.interner), + Some(coerce) => coerce.expected_ty(), None => { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { expr: tgt_expr, @@ -517,7 +487,7 @@ impl<'db> InferenceContext<'db> { ExprIsRead::Yes, ) } else { - TyBuilder::unit() + self.types.unit }; match find_breakable(&mut self.breakables, label) { @@ -527,7 +497,7 @@ impl<'db> InferenceContext<'db> { self, &ObligationCause::new(), expr.unwrap_or(tgt_expr), - val_ty.to_nextsolver(self.table.interner), + val_ty, ); // Avoiding borrowck @@ -546,12 +516,12 @@ impl<'db> InferenceContext<'db> { }); } } - self.result.standard_types.never.clone() + self.types.never } &Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr), &Expr::Become { expr } => self.infer_expr_become(expr), Expr::Yield { expr } => { - if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() { + if let Some((resume_ty, yield_ty)) = self.resume_yield_tys { if let Some(expr) = expr { self.infer_expr_coerce( *expr, @@ -559,11 +529,11 @@ impl<'db> InferenceContext<'db> { ExprIsRead::Yes, ); } else { - let unit = self.result.standard_types.unit.clone(); + let unit = self.types.unit; let _ = self.coerce( tgt_expr.into(), - unit.to_nextsolver(self.table.interner), - yield_ty.to_nextsolver(self.table.interner), + unit, + yield_ty, AllowTwoPhase::No, CoerceNever::Yes, ); @@ -571,33 +541,30 @@ impl<'db> InferenceContext<'db> { resume_ty } else { // FIXME: report error (yield expr in non-coroutine) - self.result.standard_types.unknown.clone() + self.types.error } } Expr::Yeet { expr } => { if let &Some(expr) = expr { self.infer_expr_no_expect(expr, ExprIsRead::Yes); } - self.result.standard_types.never.clone() + self.types.never } Expr::RecordLit { path, fields, spread, .. } => { let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false); if let Some(t) = expected.only_has_type(&mut self.table) { - self.unify(&ty, &t); + self.unify(ty, t); } - let substs = ty - .as_adt() - .map(|(_, s)| s.clone()) - .unwrap_or_else(|| Substitution::empty(Interner)); + let substs = ty.as_adt().map(|(_, s)| s).unwrap_or(self.types.empty_args); if let Some(variant) = def_id { self.write_variant_resolution(tgt_expr.into(), variant); } match def_id { _ if fields.is_empty() => {} Some(def) => { - let field_types = self.db.field_types(def); + let field_types = self.db.field_types_ns(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); for field in fields.iter() { @@ -628,7 +595,7 @@ impl<'db> InferenceContext<'db> { } }; let field_ty = field_def.map_or(self.err_ty(), |it| { - field_types[it].clone().substitute(Interner, &substs) + field_types[it].instantiate(self.interner(), &substs) }); // Field type might have some unknown types @@ -649,7 +616,7 @@ impl<'db> InferenceContext<'db> { } } if let Some(expr) = spread { - self.infer_expr(*expr, &Expectation::has_type(ty.clone()), ExprIsRead::Yes); + self.infer_expr(*expr, &Expectation::has_type(ty), ExprIsRead::Yes); } ty } @@ -660,21 +627,13 @@ impl<'db> InferenceContext<'db> { } Expr::Cast { expr, type_ref } => { let cast_ty = self.make_body_ty(*type_ref); - let expr_ty = self.infer_expr( - *expr, - &Expectation::Castable(cast_ty.clone()), - ExprIsRead::Yes, - ); - self.deferred_cast_checks.push(CastCheck::new( - tgt_expr, - *expr, - expr_ty, - cast_ty.clone(), - )); + let expr_ty = + self.infer_expr(*expr, &Expectation::Castable(cast_ty), ExprIsRead::Yes); + self.deferred_cast_checks.push(CastCheck::new(tgt_expr, *expr, expr_ty, cast_ty)); cast_ty } Expr::Ref { expr, rawness, mutability } => { - let mutability = lower_to_chalk_mutability(*mutability); + let mutability = lower_mutability(*mutability); let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected .only_has_type(&mut self.table) .as_ref() @@ -688,24 +647,23 @@ impl<'db> InferenceContext<'db> { // FIXME: record type error - expected reference but found ptr, // which cannot be coerced } - Expectation::rvalue_hint(self, Ty::clone(exp_inner)) + Expectation::rvalue_hint(self, exp_inner) } else { Expectation::none() }; let inner_ty = self.infer_expr_inner(*expr, &expectation, ExprIsRead::Yes); match rawness { - Rawness::RawPtr => TyKind::Raw(mutability, inner_ty), + Rawness::RawPtr => Ty::new_ptr(self.interner(), inner_ty, mutability), Rawness::Ref => { - let lt = self.table.new_lifetime_var(); - TyKind::Ref(mutability, lt, inner_ty) + let lt = self.table.next_region_var(); + Ty::new_ref(self.interner(), lt, inner_ty, mutability) } } - .intern(Interner) } &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.table.structurally_resolve_type(&inner_ty); + let inner_ty = self.table.try_structurally_resolve_type(inner_ty); // FIXME: Note down method resolution her match op { UnaryOp::Deref => { @@ -716,49 +674,38 @@ impl<'db> InferenceContext<'db> { { // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that // the mutability is not wrong, and will be fixed in `self.infer_mut`). - self.write_method_resolution( - tgt_expr, - deref_fn, - Substitution::empty(Interner), - ); + self.write_method_resolution(tgt_expr, deref_fn, self.types.empty_args); } - 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)) + if let Some(derefed) = inner_ty.builtin_deref(self.db, true) { + self.table.try_structurally_resolve_type(derefed) } else { - let infer_ok = overloaded_deref_ty( - &self.table, - inner_ty.to_nextsolver(self.table.interner), - ); + let infer_ok = overloaded_deref_ty(&self.table, inner_ty); match infer_ok { - Some(infer_ok) => self - .table - .register_infer_ok(infer_ok) - .to_chalk(self.table.interner), + Some(infer_ok) => self.table.register_infer_ok(infer_ok), None => self.err_ty(), } } } UnaryOp::Neg => { - match inner_ty.kind(Interner) { + match inner_ty.kind() { // Fast path for builtins - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) - | TyKind::InferenceVar( - _, - TyVariableKind::Integer | TyVariableKind::Float, - ) => inner_ty, + TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => inner_ty, // Otherwise we resolve via the std::ops::Neg trait _ => self .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), } } UnaryOp::Not => { - match inner_ty.kind(Interner) { + match inner_ty.kind() { // Fast path for builtins - TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_)) - | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty, + TyKind::Bool + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => inner_ty, // Otherwise we resolve via the std::ops::Not trait _ => self .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), @@ -768,18 +715,10 @@ impl<'db> InferenceContext<'db> { } Expr::BinaryOp { lhs, rhs, op } => match op { Some(BinaryOp::LogicOp(_)) => { - let bool_ty = self.result.standard_types.bool_.clone(); - self.infer_expr_coerce( - *lhs, - &Expectation::HasType(bool_ty.clone()), - ExprIsRead::Yes, - ); + let bool_ty = self.types.bool; + self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty), ExprIsRead::Yes); let lhs_diverges = self.diverges; - self.infer_expr_coerce( - *rhs, - &Expectation::HasType(bool_ty.clone()), - ExprIsRead::Yes, - ); + self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty), ExprIsRead::Yes); // Depending on the LHS' value, the RHS can never execute. self.diverges = lhs_diverges; bool_ty @@ -826,14 +765,14 @@ impl<'db> InferenceContext<'db> { let is_destructuring_assignment = lhs_ty.is_none(); if let Some(lhs_ty) = lhs_ty { - self.write_pat_ty(target, lhs_ty.clone()); + self.write_pat_ty(target, lhs_ty); self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No); } else { let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes); let resolver_guard = self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); self.inside_assignment = true; - self.infer_top_pat(target, &rhs_ty, None); + self.infer_top_pat(target, rhs_ty, None); self.inside_assignment = false; self.resolver.reset_to_guard(resolver_guard); } @@ -844,43 +783,49 @@ impl<'db> InferenceContext<'db> { // assignments into blocks. self.table.new_maybe_never_var() } else { - self.result.standard_types.unit.clone() + self.types.unit } } Expr::Range { lhs, rhs, range_type } => { let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes)); - let rhs_expect = lhs_ty - .as_ref() - .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); + let rhs_expect = + lhs_ty.as_ref().map_or_else(Expectation::none, |ty| Expectation::has_type(*ty)); let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect, ExprIsRead::Yes)); + let single_arg_adt = |adt, ty: Ty<'db>| { + Ty::new_adt( + self.interner(), + adt, + GenericArgs::new_from_iter(self.interner(), [ty.into()]), + ) + }; match (range_type, lhs_ty, rhs_ty) { (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { - Some(adt) => TyBuilder::adt(self.db, adt).build(), + Some(adt) => Ty::new_adt(self.interner(), adt, self.types.empty_args), None => self.err_ty(), }, (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), + Some(adt) => single_arg_adt(adt, ty), None => self.err_ty(), }, (RangeOp::Inclusive, None, Some(ty)) => { match self.resolve_range_to_inclusive() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), + Some(adt) => single_arg_adt(adt, ty), None => self.err_ty(), } } (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), + Some(adt) => single_arg_adt(adt, ty), None => self.err_ty(), }, (RangeOp::Inclusive, Some(_), Some(ty)) => { match self.resolve_range_inclusive() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), + Some(adt) => single_arg_adt(adt, ty), None => self.err_ty(), } } (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { - Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), + Some(adt) => single_arg_adt(adt, ty), None => self.err_ty(), }, (RangeOp::Inclusive, _, None) => self.err_ty(), @@ -891,8 +836,7 @@ impl<'db> InferenceContext<'db> { 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().to_nextsolver(self.table.interner)); + let canonicalized = self.canonicalize(base_ty); let receiver_adjustments = method_resolution::resolve_indexing_op( &mut self.table, canonicalized, @@ -905,142 +849,133 @@ impl<'db> InferenceContext<'db> { // mutability will be fixed up in `InferenceContext::infer_mut`; adj.push(Adjustment::borrow( + self.interner(), Mutability::Not, - self_ty.clone(), - self.table.new_lifetime_var(), + self_ty, + self.table.next_region_var(), )); self.write_expr_adj(*base, adj.into_boxed_slice()); if let Some(func) = index_trait .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::index)) { - let subst = TyBuilder::subst_for_def(self.db, index_trait, None); - if subst.remaining() != 2 { - return self.err_ty(); - } - let subst = subst.push(self_ty.clone()).push(index_ty.clone()).build(); + let subst = GenericArgs::new_from_iter( + self.interner(), + [self_ty.into(), index_ty.into()], + ); self.write_method_resolution(tgt_expr, func, subst); } let assoc = self.resolve_ops_index_output(); - self.resolve_associated_type_with_params( - self_ty, - assoc, - &[index_ty.cast(Interner)], - ) + self.resolve_associated_type_with_params(self_ty, assoc, &[index_ty.into()]) } else { self.err_ty() } } Expr::Tuple { exprs, .. } => { - let mut tys = match expected - .only_has_type(&mut self.table) - .as_ref() - .map(|t| t.kind(Interner)) - { - Some(TyKind::Tuple(_, substs)) => substs - .iter(Interner) - .map(|a| a.assert_ty_ref(Interner).clone()) - .chain(repeat_with(|| self.table.new_type_var())) - .take(exprs.len()) - .collect::>(), - _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(), - }; + let mut tys = + match expected.only_has_type(&mut self.table).as_ref().map(|t| t.kind()) { + Some(TyKind::Tuple(substs)) => substs + .iter() + .chain(repeat_with(|| self.table.next_ty_var())) + .take(exprs.len()) + .collect::>(), + _ => (0..exprs.len()).map(|_| self.table.next_ty_var()).collect(), + }; for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { - *ty = self.infer_expr_coerce( - *expr, - &Expectation::has_type(ty.clone()), - ExprIsRead::Yes, - ); + *ty = + self.infer_expr_coerce(*expr, &Expectation::has_type(*ty), ExprIsRead::Yes); } - TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner) + Ty::new_tup(self.interner(), &tys) } Expr::Array(array) => self.infer_expr_array(array, expected), Expr::Literal(lit) => match lit { - Literal::Bool(..) => self.result.standard_types.bool_.clone(), - Literal::String(..) => { - TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner)) - .intern(Interner) - } + Literal::Bool(..) => self.types.bool, + Literal::String(..) => self.types.static_str_ref, Literal::ByteString(bs) => { - let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); + let byte_type = self.types.u8; - let len = consteval::usize_const( + let len = consteval_nextsolver::usize_const( self.db, Some(bs.len() as u128), self.resolver.krate(), ); - let array_type = TyKind::Array(byte_type, len).intern(Interner); - TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner) + let array_type = Ty::new_array_with_const_len(self.interner(), byte_type, len); + Ty::new_ref(self.interner(), self.types.re_static, array_type, Mutability::Not) } - Literal::CString(..) => TyKind::Ref( - Mutability::Not, - static_lifetime(), + Literal::CString(..) => Ty::new_ref( + self.interner(), + self.types.re_static, self.resolve_lang_item(LangItem::CStr) .and_then(LangItemTarget::as_struct) .map_or_else( || self.err_ty(), |strukt| { - TyKind::Adt(AdtId(strukt.into()), Substitution::empty(Interner)) - .intern(Interner) + Ty::new_adt(self.interner(), strukt.into(), self.types.empty_args) }, ), - ) - .intern(Interner), - Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner), + Mutability::Not, + ), + Literal::Char(..) => self.types.char, Literal::Int(_v, ty) => match ty { - Some(int_ty) => { - TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty))) - .intern(Interner) - } + Some(int_ty) => match int_ty { + hir_def::builtin_type::BuiltinInt::Isize => self.types.isize, + hir_def::builtin_type::BuiltinInt::I8 => self.types.i8, + hir_def::builtin_type::BuiltinInt::I16 => self.types.i16, + hir_def::builtin_type::BuiltinInt::I32 => self.types.i32, + hir_def::builtin_type::BuiltinInt::I64 => self.types.i64, + hir_def::builtin_type::BuiltinInt::I128 => self.types.i128, + }, 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)) => { - Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) - } - Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { - Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.usize) } _ => None, }; - opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + opt_ty.unwrap_or_else(|| self.table.next_int_var()) } }, Literal::Uint(_v, ty) => match ty { - Some(int_ty) => { - TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty))) - .intern(Interner) - } + Some(int_ty) => match int_ty { + hir_def::builtin_type::BuiltinUint::Usize => self.types.usize, + hir_def::builtin_type::BuiltinUint::U8 => self.types.u8, + hir_def::builtin_type::BuiltinUint::U16 => self.types.u16, + hir_def::builtin_type::BuiltinUint::U32 => self.types.u32, + hir_def::builtin_type::BuiltinUint::U64 => self.types.u64, + hir_def::builtin_type::BuiltinUint::U128 => self.types.u128, + }, None => { let expected_ty = expected.to_option(&mut self.table); - 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)) => { - Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) - } - Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { - Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.usize) } _ => None, }; - opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + opt_ty.unwrap_or_else(|| self.table.next_int_var()) } }, Literal::Float(_v, ty) => match ty { - Some(float_ty) => { - TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty))) - .intern(Interner) - } + Some(float_ty) => match float_ty { + hir_def::builtin_type::BuiltinFloat::F16 => self.types.f16, + hir_def::builtin_type::BuiltinFloat::F32 => self.types.f32, + hir_def::builtin_type::BuiltinFloat::F64 => self.types.f64, + hir_def::builtin_type::BuiltinFloat::F128 => self.types.f128, + }, None => { - let opt_ty = expected.to_option(&mut self.table).filter(|ty| { - matches!(ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) - }); - opt_ty.unwrap_or_else(|| self.table.new_float_var()) + let opt_ty = expected + .to_option(&mut self.table) + .filter(|ty| matches!(ty.kind(), TyKind::Float(_))); + opt_ty.unwrap_or_else(|| self.table.next_float_var()) } }, }, @@ -1048,13 +983,10 @@ impl<'db> InferenceContext<'db> { // Underscore expression is an error, we render a specialized diagnostic // to let the user know what type is expected though. let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty()); - self.push_diagnostic(InferenceDiagnostic::TypedHole { - expr: tgt_expr, - expected: expected.clone(), - }); + self.push_diagnostic(InferenceDiagnostic::TypedHole { expr: tgt_expr, expected }); expected } - Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), + Expr::OffsetOf(_) => self.types.usize, Expr::InlineAsm(asm) => { let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| { let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes); @@ -1067,27 +999,29 @@ impl<'db> InferenceContext<'db> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = this.table.structurally_resolve_type(&ty); - match ty.kind(Interner) { + let ty = this.table.structurally_resolve_type(ty); + match ty.kind() { TyKind::FnDef(def, parameters) => { - let fnptr_ty = TyKind::Function( - CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(), - ) - .intern(Interner); + let fnptr_ty = Ty::new_fn_ptr( + this.interner(), + this.interner() + .fn_sig(def) + .instantiate(this.interner(), parameters), + ); _ = this.coerce( expr.into(), - ty.to_nextsolver(this.table.interner), - fnptr_ty.to_nextsolver(this.table.interner), + ty, + fnptr_ty, AllowTwoPhase::No, CoerceNever::Yes, ); } - TyKind::Ref(mutbl, _, base_ty) => { - let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner); + TyKind::Ref(_, base_ty, mutbl) => { + let ptr_ty = Ty::new_ptr(this.interner(), base_ty, mutbl); _ = this.coerce( expr.into(), - ty.to_nextsolver(this.table.interner), - ptr_ty.to_nextsolver(this.table.interner), + ty, + ptr_ty, AllowTwoPhase::No, CoerceNever::Yes, ); @@ -1113,7 +1047,7 @@ impl<'db> InferenceContext<'db> { AsmOperand::Label(expr) => { self.infer_expr( expr, - &Expectation::HasType(self.result.standard_types.unit.clone()), + &Expectation::HasType(self.types.unit), ExprIsRead::No, ); } @@ -1123,17 +1057,13 @@ impl<'db> InferenceContext<'db> { // FIXME: `sym` should report for things that are not functions or statics. AsmOperand::Sym(_) => (), }); - if diverge { - self.result.standard_types.never.clone() - } else { - self.result.standard_types.unit.clone() - } + if diverge { self.types.never } else { self.types.unit } } }; // use a new type variable if we got unknown here let ty = self.insert_type_vars_shallow(ty); - self.write_expr_ty(tgt_expr, ty.clone()); - if self.resolve_ty_shallow(&ty).is_never() + self.write_expr_ty(tgt_expr, ty); + if self.shallow_resolve(ty).is_never() && self.expr_guaranteed_to_constitute_read_for_never(tgt_expr, is_read) { // Any expression that produces a value of type `!` must have diverged @@ -1142,7 +1072,7 @@ impl<'db> InferenceContext<'db> { ty } - fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty { + fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> { let g = self.resolver.update_to_inner_scope(self.db, self.owner, scope_id); let ty = match self.infer_path(path, id) { Some(ty) => ty, @@ -1164,32 +1094,24 @@ impl<'db> InferenceContext<'db> { id: &Option, statements: &[Statement], tail: &Option, - ) -> Ty { - let ret_ty = self.table.new_type_var(); + ) -> Ty<'db> { + let ret_ty = self.table.next_ty_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.to_nextsolver(self.table.interner))); + let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty); + let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(ret_ty)); // 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( - 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), + match this.coerce(tgt_expr.into(), ty, target, AllowTwoPhase::No, CoerceNever::Yes) + { + Ok(res) => res, Err(_) => { - this.result.type_mismatches.insert( - tgt_expr.into(), - TypeMismatch { expected: target.clone(), actual: ty.clone() }, - ); + this.result + .type_mismatches + .insert(tgt_expr.into(), TypeMismatch { expected: target, actual: ty }); target } } @@ -1207,57 +1129,67 @@ impl<'db> InferenceContext<'db> { pub(crate) fn lower_async_block_type_impl_trait( &mut self, - inner_ty: Ty, + inner_ty: Ty<'db>, tgt_expr: ExprId, - ) -> Ty { + ) -> Ty<'db> { // Use the first type parameter as the output type of future. // existential type AsyncBlockImplTrait: Future let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr); let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)).intern(Interner) + Ty::new_alias( + self.interner(), + AliasTyKind::Opaque, + AliasTy::new( + self.interner(), + opaque_ty_id, + GenericArgs::new_from_iter(self.interner(), [inner_ty.into()]), + ), + ) } pub(crate) fn write_fn_trait_method_resolution( &mut self, fn_x: FnTrait, - derefed_callee: &Ty, - adjustments: &mut Vec, - callee_ty: &Ty, - params: &[Ty], + derefed_callee: Ty<'db>, + adjustments: &mut Vec>, + callee_ty: Ty<'db>, + params: &[Ty<'db>], tgt_expr: ExprId, ) { match fn_x { FnTrait::FnOnce | FnTrait::AsyncFnOnce => (), FnTrait::FnMut | FnTrait::AsyncFnMut => { - if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) { + if let TyKind::Ref(lt, inner, Mutability::Mut) = derefed_callee.kind() { if adjustments .last() .map(|it| matches!(it.kind, Adjust::Borrow(_))) .unwrap_or(true) { // prefer reborrow to move - adjustments - .push(Adjustment { kind: Adjust::Deref(None), target: inner.clone() }); + adjustments.push(Adjustment { kind: Adjust::Deref(None), target: inner }); adjustments.push(Adjustment::borrow( + self.interner(), Mutability::Mut, - inner.clone(), - lt.clone(), + inner, + lt, )) } } else { adjustments.push(Adjustment::borrow( + self.interner(), Mutability::Mut, - derefed_callee.clone(), - self.table.new_lifetime_var(), + derefed_callee, + self.table.next_region_var(), )); } } FnTrait::Fn | FnTrait::AsyncFn => { - if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) { + if !matches!(derefed_callee.kind(), TyKind::Ref(_, _, Mutability::Not)) { adjustments.push(Adjustment::borrow( + self.interner(), Mutability::Not, - derefed_callee.clone(), - self.table.new_lifetime_var(), + derefed_callee, + self.table.next_region_var(), )); } } @@ -1267,57 +1199,48 @@ impl<'db> InferenceContext<'db> { }; let trait_data = trait_.trait_items(self.db); if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) { - let subst = TyBuilder::subst_for_def(self.db, trait_, None) - .push(callee_ty.clone()) - .push(TyBuilder::tuple_with(params.iter().cloned())) - .build(); + let subst = GenericArgs::new_from_iter( + self.interner(), + [ + callee_ty.into(), + Ty::new_tup_from_iter(self.interner(), params.iter().copied()).into(), + ], + ); self.write_method_resolution(tgt_expr, func, subst); } } - fn infer_expr_array( - &mut self, - array: &Array, - expected: &Expectation, - ) -> chalk_ir::Ty { - let elem_ty = match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) { - Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(), - _ => self.table.new_type_var(), + fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty<'db> { + let elem_ty = match expected.to_option(&mut self.table).as_ref().map(|t| t.kind()) { + Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st, + _ => self.table.next_ty_var(), }; let krate = self.resolver.krate(); - let expected = Expectation::has_type(elem_ty.clone()); + let expected = Expectation::has_type(elem_ty); let (elem_ty, len) = match array { Array::ElementList { elements, .. } if elements.is_empty() => { - (elem_ty, consteval::usize_const(self.db, Some(0), krate)) + (elem_ty, consteval_nextsolver::usize_const(self.db, Some(0), krate)) } Array::ElementList { elements, .. } => { - let mut coerce = CoerceMany::with_coercion_sites( - elem_ty.to_nextsolver(self.table.interner), - elements, - ); + let mut coerce = CoerceMany::with_coercion_sites(elem_ty, elements); for &expr in elements.iter() { let cur_elem_ty = self.infer_expr_inner(expr, &expected, ExprIsRead::Yes); - coerce.coerce( - self, - &ObligationCause::new(), - expr, - cur_elem_ty.to_nextsolver(self.table.interner), - ); + coerce.coerce(self, &ObligationCause::new(), expr, cur_elem_ty); } ( - coerce.complete(self).to_chalk(self.table.interner), - consteval::usize_const(self.db, Some(elements.len() as u128), krate), + coerce.complete(self), + consteval_nextsolver::usize_const(self.db, Some(elements.len() as u128), krate), ) } &Array::Repeat { initializer, repeat } => { self.infer_expr_coerce( initializer, - &Expectation::has_type(elem_ty.clone()), + &Expectation::has_type(elem_ty), ExprIsRead::Yes, ); - let usize = TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner); + let usize = self.types.usize; match self.body[repeat] { Expr::Underscore => { self.write_expr_ty(repeat, usize); @@ -1325,20 +1248,12 @@ impl<'db> InferenceContext<'db> { _ => _ = self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes), } - ( - elem_ty, - consteval::eval_to_const( - repeat, - ParamLoweringMode::Placeholder, - self, - DebruijnIndex::INNERMOST, - ), - ) + (elem_ty, consteval_nextsolver::eval_to_const(repeat, self)) } }; // Try to evaluate unevaluated constant, and insert variable if is not possible. let len = self.table.insert_const_vars_shallow(len); - TyKind::Array(elem_ty, len).intern(Interner) + Ty::new_array_with_const_len(self.interner(), elem_ty, len) } pub(super) fn infer_return(&mut self, expr: ExprId) { @@ -1346,21 +1261,15 @@ impl<'db> InferenceContext<'db> { .return_coercion .as_mut() .expect("infer_return called outside function body") - .expected_ty() - .to_chalk(self.table.interner); + .expected_ty(); 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, - &ObligationCause::new(), - expr, - return_expr_ty.to_nextsolver(self.table.interner), - ); + coerce_many.coerce(self, &ObligationCause::new(), expr, return_expr_ty); self.return_coercion = Some(coerce_many); } - fn infer_expr_return(&mut self, ret: ExprId, expr: Option) -> Ty { + fn infer_expr_return(&mut self, ret: ExprId, expr: Option) -> Ty<'db> { match self.return_coercion { Some(_) => { if let Some(expr) = expr { @@ -1378,23 +1287,20 @@ impl<'db> InferenceContext<'db> { } } } - self.result.standard_types.never.clone() + self.types.never } - fn infer_expr_become(&mut self, expr: ExprId) -> Ty { + fn infer_expr_become(&mut self, expr: ExprId) -> Ty<'db> { match &self.return_coercion { Some(return_coercion) => { - let ret_ty = return_coercion.expected_ty().to_chalk(self.table.interner); + let ret_ty = return_coercion.expected_ty(); - let call_expr_ty = self.infer_expr_inner( - expr, - &Expectation::HasType(ret_ty.clone()), - ExprIsRead::Yes, - ); + let call_expr_ty = + self.infer_expr_inner(expr, &Expectation::HasType(ret_ty), ExprIsRead::Yes); // NB: this should *not* coerce. // tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`). - self.unify(&call_expr_ty, &ret_ty); + self.unify(call_expr_ty, ret_ty); } None => { // FIXME: diagnose `become` outside of functions @@ -1402,10 +1308,10 @@ impl<'db> InferenceContext<'db> { } } - self.result.standard_types.never.clone() + self.types.never } - fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty { + fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation<'db>) -> Ty<'db> { if let Some(box_id) = self.resolve_boxed_box() { let table = &mut self.table; let inner_exp = expected @@ -1414,16 +1320,22 @@ impl<'db> InferenceContext<'db> { .and_then(|e| e.as_adt()) .filter(|(e_adt, _)| e_adt == &box_id) .map(|(_, subts)| { - let g = subts.at(Interner, 0); - Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner))) + let g = subts.type_at(0); + Expectation::rvalue_hint(self, g) }) .unwrap_or_else(Expectation::none); let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp, ExprIsRead::Yes); - TyBuilder::adt(self.db, box_id) - .push(inner_ty) - .fill_with_defaults(self.db, || self.table.new_type_var()) - .build() + Ty::new_adt( + self.interner(), + box_id, + GenericArgs::fill_with_defaults( + self.interner(), + box_id.into(), + [inner_ty.into()], + |_, _, id, _| self.table.next_var_for_param(id), + ), + ) } else { self.err_ty() } @@ -1435,7 +1347,7 @@ impl<'db> InferenceContext<'db> { op: BinaryOp, rhs: ExprId, tgt_expr: ExprId, - ) -> Ty { + ) -> Ty<'db> { let lhs_expectation = Expectation::none(); let is_read = if matches!(op, BinaryOp::Assignment { .. }) { ExprIsRead::Yes @@ -1443,24 +1355,24 @@ impl<'db> InferenceContext<'db> { ExprIsRead::No }; let lhs_ty = self.infer_expr(lhs, &lhs_expectation, is_read); - let rhs_ty = self.table.new_type_var(); + let rhs_ty = self.table.next_ty_var(); let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| { let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?; let func = trait_id.trait_items(self.db).method_by_name(&name)?; Some((trait_id, func)) }); - let (trait_, func) = match trait_func { - Some(it) => it, + let func = match trait_func { + Some((_, it)) => it, None => { // HACK: `rhs_ty` is a general inference variable with no clue at all at this // point. Passing `lhs_ty` as both operands just to check if `lhs_ty` is a builtin // type applicable to `op`. - let ret_ty = if self.is_builtin_binop(&lhs_ty, &lhs_ty, op) { + let ret_ty = if self.is_builtin_binop(lhs_ty, lhs_ty, op) { // Assume both operands are builtin so we can continue inference. No guarantee // on the correctness, rustc would complain as necessary lang items don't seem // to exist anyway. - self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op) + self.enforce_builtin_binop_types(lhs_ty, rhs_ty, op) } else { self.err_ty() }; @@ -1473,59 +1385,53 @@ impl<'db> InferenceContext<'db> { // HACK: We can use this substitution for the function because the function itself doesn't // have its own generic parameters. - let subst = TyBuilder::subst_for_def(self.db, trait_, None); - if subst.remaining() != 2 { - return Ty::new(Interner, TyKind::Error); - } - let subst = subst.push(lhs_ty.clone()).push(rhs_ty.clone()).build(); + let args = GenericArgs::new_from_iter(self.interner(), [lhs_ty.into(), rhs_ty.into()]); - self.write_method_resolution(tgt_expr, func, subst.clone()); + self.write_method_resolution(tgt_expr, func, args); - let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); - let method_ty = - self.db.value_ty(func.into()).unwrap().instantiate(interner, args).to_chalk(interner); - self.register_obligations_for_call(&method_ty); + let method_ty = self.db.value_ty(func.into()).unwrap().instantiate(self.interner(), args); + self.register_obligations_for_call(method_ty); - self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()), ExprIsRead::Yes); + self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty), ExprIsRead::Yes); - let ret_ty = match method_ty.callable_sig(self.db) { + let ret_ty = match method_ty.callable_sig(self.interner()) { Some(sig) => { - let p_left = &sig.params()[0]; + let sig = sig.skip_binder(); + let p_left = sig.inputs_and_output.as_slice()[0]; if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) - && let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner) + && let TyKind::Ref(lt, _, mtbl) = p_left.kind() { self.write_expr_adj( lhs, Box::new([Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), - target: p_left.clone(), + kind: Adjust::Borrow(AutoBorrow::Ref(lt, mtbl)), + target: p_left, }]), ); } - let p_right = &sig.params()[1]; + let p_right = sig.inputs_and_output.as_slice()[1]; if matches!(op, BinaryOp::CmpOp(..)) - && let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner) + && let TyKind::Ref(lt, _, mtbl) = p_right.kind() { self.write_expr_adj( rhs, Box::new([Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), - target: p_right.clone(), + kind: Adjust::Borrow(AutoBorrow::Ref(lt, mtbl)), + target: p_right, }]), ); } - sig.ret().clone() + sig.output() } None => self.err_ty(), }; let ret_ty = self.process_remote_user_written_ty(ret_ty); - if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) { + if self.is_builtin_binop(lhs_ty, rhs_ty, op) { // 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); + let builtin_ret = self.enforce_builtin_binop_types(lhs_ty, rhs_ty, op); + self.unify(builtin_ret, ret_ty); builtin_ret } else { ret_ty @@ -1539,8 +1445,8 @@ impl<'db> InferenceContext<'db> { statements: &[Statement], tail: Option, label: Option, - expected: &Expectation, - ) -> Ty { + expected: &Expectation<'db>, + ) -> Ty<'db> { let coerce_ty = expected.coercion_target_type(&mut self.table); let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr); let prev_env = block_id.map(|block_id| { @@ -1557,7 +1463,7 @@ impl<'db> InferenceContext<'db> { let decl_ty = type_ref .as_ref() .map(|&tr| this.make_body_ty(tr)) - .unwrap_or_else(|| this.table.new_type_var()); + .unwrap_or_else(|| this.table.next_ty_var()); let ty = if let Some(expr) = initializer { // If we have a subpattern that performs a read, we want to consider this @@ -1571,13 +1477,13 @@ impl<'db> InferenceContext<'db> { let ty = if contains_explicit_ref_binding(this.body, *pat) { this.infer_expr( *expr, - &Expectation::has_type(decl_ty.clone()), + &Expectation::has_type(decl_ty), target_is_read, ) } else { this.infer_expr_coerce( *expr, - &Expectation::has_type(decl_ty.clone()), + &Expectation::has_type(decl_ty), target_is_read, ) }; @@ -1590,13 +1496,13 @@ impl<'db> InferenceContext<'db> { origin: DeclOrigin::LocalDecl { has_else: else_branch.is_some() }, }; - this.infer_top_pat(*pat, &ty, Some(decl)); + this.infer_top_pat(*pat, ty, Some(decl)); if let Some(expr) = else_branch { let previous_diverges = mem::replace(&mut this.diverges, Diverges::Maybe); this.infer_expr_coerce( *expr, - &Expectation::HasType(this.result.standard_types.never.clone()), + &Expectation::HasType(this.types.never), ExprIsRead::Yes, ); this.diverges = previous_diverges; @@ -1608,7 +1514,7 @@ impl<'db> InferenceContext<'db> { } else { this.infer_expr_coerce( expr, - &Expectation::HasType(this.result.standard_types.unit.clone()), + &Expectation::HasType(this.types.unit), ExprIsRead::Yes, ); } @@ -1642,8 +1548,8 @@ impl<'db> InferenceContext<'db> { if this .coerce( expr.into(), - this.result.standard_types.unit.to_nextsolver(this.table.interner), - t.to_nextsolver(this.table.interner), + this.types.unit, + t, AllowTwoPhase::No, coerce_never, ) @@ -1651,15 +1557,12 @@ impl<'db> InferenceContext<'db> { { this.result.type_mismatches.insert( expr.into(), - TypeMismatch { - expected: t.clone(), - actual: this.result.standard_types.unit.clone(), - }, + TypeMismatch { expected: t, actual: this.types.unit }, ); } t } else { - this.result.standard_types.unit.clone() + this.types.unit } } }); @@ -1673,32 +1576,30 @@ impl<'db> InferenceContext<'db> { fn lookup_field( &mut self, - receiver_ty: &Ty, + receiver_ty: Ty<'db>, name: &Name, - ) -> Option<(Ty, Either, Vec, bool)> { - let interner = self.table.interner; - let mut autoderef = self.table.autoderef(receiver_ty.to_nextsolver(self.table.interner)); + ) -> Option<(Ty<'db>, Either, Vec>, bool)> { + let interner = self.interner(); + let mut autoderef = self.table.autoderef(receiver_ty); let mut private_field = None; let res = autoderef.by_ref().find_map(|(derefed_ty, _)| { let (field_id, parameters) = match derefed_ty.kind() { - crate::next_solver::TyKind::Tuple(substs) => { + TyKind::Tuple(substs) => { return name.as_tuple_index().and_then(|idx| { 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, + self.tuple_field_accesses_rev.insert_full(substs).0 as u32, ), index: idx as u32, }), - ty.to_chalk(interner), + ty, ) }) }); } - crate::next_solver::TyKind::Adt(adt, parameters) => match adt.def_id().0 { + 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 }; @@ -1713,18 +1614,16 @@ impl<'db> InferenceContext<'db> { }, _ => 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.clone())); + private_field = Some((field_id, parameters)); } return None; } - let ty = self.db.field_types(field_id.parent)[field_id.local_id] - .clone() - .substitute(Interner, ¶meters); + let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id] + .instantiate(interner, parameters); Some((Either::Left(field_id), ty)) }); @@ -1738,9 +1637,8 @@ impl<'db> InferenceContext<'db> { None => { let (field_id, subst) = private_field?; let adjustments = autoderef.adjust_steps(); - let ty = self.db.field_types(field_id.parent)[field_id.local_id] - .clone() - .substitute(Interner, &subst); + let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id] + .instantiate(self.interner(), subst); let ty = self.process_remote_user_written_ty(ty); (ty, Either::Left(field_id), adjustments, false) @@ -1753,8 +1651,8 @@ impl<'db> InferenceContext<'db> { tgt_expr: ExprId, receiver: ExprId, name: &Name, - expected: &Expectation, - ) -> Ty { + expected: &Expectation<'db>, + ) -> Ty<'db> { // Field projections don't constitute reads. let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::No); @@ -1764,7 +1662,7 @@ impl<'db> InferenceContext<'db> { return self.err_ty(); } - match self.lookup_field(&receiver_ty, name) { + match self.lookup_field(receiver_ty, name) { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); self.result.field_resolutions.insert(tgt_expr, field_id); @@ -1780,8 +1678,7 @@ impl<'db> InferenceContext<'db> { 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); let resolved = method_resolution::lookup_method( self.db, &canonicalized_receiver, @@ -1792,28 +1689,24 @@ impl<'db> InferenceContext<'db> { ); self.push_diagnostic(InferenceDiagnostic::UnresolvedField { expr: tgt_expr, - receiver: receiver_ty.clone(), + receiver: receiver_ty, name: name.clone(), method_with_same_name_exists: resolved.is_some(), }); match resolved { Some((adjust, func, _)) => { let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty); - let substs = self.substs_for_method_call(tgt_expr, func.into(), None); + let args = self.substs_for_method_call(tgt_expr, func.into(), None); self.write_expr_adj(receiver, adjustments.into_boxed_slice()); - self.write_method_resolution(tgt_expr, func, substs.clone()); + self.write_method_resolution(tgt_expr, func, args); - let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = - substs.to_nextsolver(interner); self.check_method_call( tgt_expr, &[], self.db .value_ty(func.into()) .unwrap() - .instantiate(interner, args) - .to_chalk(interner), + .instantiate(self.interner(), args), ty, expected, ) @@ -1829,47 +1722,42 @@ impl<'db> InferenceContext<'db> { tgt_expr: ExprId, callee: ExprId, args: &[ExprId], - expected: &Expectation, - ) -> Ty { + expected: &Expectation<'db>, + ) -> Ty<'db> { let callee_ty = self.infer_expr(callee, &Expectation::none(), ExprIsRead::Yes); - let interner = self.table.interner; - let mut derefs = self.table.autoderef(callee_ty.to_nextsolver(interner)); + let interner = self.interner(); + let mut derefs = self.table.autoderef(callee_ty); let (res, derefed_callee) = loop { let Some((callee_deref_ty, _)) = derefs.next() else { - break (None, callee_ty.clone()); + break (None, callee_ty); }; - let callee_deref_ty = callee_deref_ty.to_chalk(interner); - if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) { + if let Some(res) = derefs.table.callable_sig(callee_deref_ty, args.len()) { break (Some(res), callee_deref_ty); } }; // if the function is unresolved, we use is_varargs=true to // suppress the arg count diagnostic here - let is_varargs = - derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs) || res.is_none(); + let is_varargs = derefed_callee.callable_sig(interner).is_some_and(|sig| sig.c_variadic()) + || res.is_none(); let (param_tys, ret_ty) = match res { Some((func, params, ret_ty)) => { - 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, + derefed_callee, &mut adjustments, - &callee_ty, - ¶ms_chalk, + callee_ty, + ¶ms, tgt_expr, ); } - if let &TyKind::Closure(c, _) = - self.table.resolve_completely(callee_ty.clone()).kind(Interner) - { + if let TyKind::Closure(c, _) = self.table.resolve_completely(callee_ty).kind() { self.add_current_closure_dependency(c.into()); self.deferred_closures.entry(c.into()).or_default().push(( - derefed_callee.clone(), - callee_ty.clone(), - params_chalk, + derefed_callee, + callee_ty, + params.clone(), tgt_expr, )); } @@ -1879,9 +1767,9 @@ impl<'db> InferenceContext<'db> { None => { self.push_diagnostic(InferenceDiagnostic::ExpectedFunction { call_expr: tgt_expr, - found: callee_ty.clone(), + found: callee_ty, }); - (Vec::new(), crate::next_solver::Ty::new_error(interner, ErrorGuaranteed)) + (Vec::new(), Ty::new_error(interner, ErrorGuaranteed)) } }; let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args); @@ -1901,14 +1789,14 @@ impl<'db> InferenceContext<'db> { &mut self, tgt_expr: ExprId, args: &[ExprId], - callee_ty: Ty, - param_tys: &[crate::next_solver::Ty<'db>], - ret_ty: crate::next_solver::Ty<'db>, + callee_ty: Ty<'db>, + param_tys: &[Ty<'db>], + ret_ty: Ty<'db>, indices_to_skip: &[u32], is_varargs: bool, - expected: &Expectation, - ) -> Ty { - self.register_obligations_for_call(&callee_ty); + expected: &Expectation<'db>, + ) -> Ty<'db> { + self.register_obligations_for_call(callee_ty); self.check_call_arguments( tgt_expr, @@ -1919,7 +1807,7 @@ impl<'db> InferenceContext<'db> { indices_to_skip, is_varargs, ); - self.table.normalize_associated_types_in_ns(ret_ty).to_chalk(self.table.interner) + self.table.normalize_associated_types_in(ret_ty) } fn infer_method_call( @@ -1928,16 +1816,13 @@ impl<'db> InferenceContext<'db> { receiver: ExprId, args: &[ExprId], method_name: &Name, - generic_args: Option<&GenericArgs>, - expected: &Expectation, - ) -> Ty { + generic_args: Option<&HirGenericArgs>, + expected: &Expectation<'db>, + ) -> Ty<'db> { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes); - let receiver_ty = self.table.structurally_resolve_type(&receiver_ty); + let receiver_ty = self.table.try_structurally_resolve_type(receiver_ty); - if matches!( - receiver_ty.kind(Interner), - TyKind::Error | TyKind::InferenceVar(_, TyVariableKind::General) - ) { + if matches!(receiver_ty.kind(), TyKind::Error(_) | TyKind::Infer(InferTy::TyVar(_))) { // 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 { @@ -1947,8 +1832,7 @@ impl<'db> InferenceContext<'db> { return receiver_ty; } - let canonicalized_receiver = - self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner)); + let canonicalized_receiver = self.canonicalize(receiver_ty); let resolved = method_resolution::lookup_method( self.db, @@ -1970,18 +1854,16 @@ impl<'db> InferenceContext<'db> { let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty); self.write_expr_adj(receiver, adjustments.into_boxed_slice()); - let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args); - self.write_method_resolution(tgt_expr, func, substs.clone()); + let gen_args = self.substs_for_method_call(tgt_expr, func.into(), generic_args); + self.write_method_resolution(tgt_expr, func, gen_args); let interner = DbInterner::new_with(self.db, None, None); - let gen_args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); self.check_method_call( tgt_expr, args, self.db .value_ty(func.into()) .expect("we have a function def") - .instantiate(interner, gen_args) - .to_chalk(interner), + .instantiate(interner, gen_args), ty, expected, ) @@ -1989,7 +1871,7 @@ impl<'db> InferenceContext<'db> { // Failed to resolve, report diagnostic and try to resolve as call to field access or // assoc function None => { - let field_with_same_name_exists = match self.lookup_field(&receiver_ty, method_name) + let field_with_same_name_exists = match self.lookup_field(receiver_ty, method_name) { Some((ty, field_id, adjustments, _public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); @@ -2017,48 +1899,46 @@ impl<'db> InferenceContext<'db> { self.push_diagnostic(InferenceDiagnostic::UnresolvedMethodCall { expr: tgt_expr, - receiver: receiver_ty.clone(), + receiver: receiver_ty, name: method_name.clone(), - field_with_same_name: field_with_same_name_exists.clone(), + field_with_same_name: field_with_same_name_exists, assoc_func_with_same_name, }); let recovered = match assoc_func_with_same_name { Some(f) => { - let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args); + let args = self.substs_for_method_call(tgt_expr, f.into(), generic_args); let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = - substs.to_nextsolver(interner); let f = self .db .value_ty(f.into()) .expect("we have a function def") - .instantiate(interner, args) - .to_chalk(interner); - let sig = f.callable_sig(self.db).expect("we have a function def"); + .instantiate(interner, args); + let sig = f.callable_sig(self.interner()).expect("we have a function def"); Some((f, sig, true)) } None => field_with_same_name_exists.and_then(|field_ty| { - let callable_sig = field_ty.callable_sig(self.db)?; + let callable_sig = field_ty.callable_sig(self.interner())?; Some((field_ty, callable_sig, false)) }), }; match recovered { - Some((callee_ty, sig, strip_first)) => self.check_call( - tgt_expr, - args, - callee_ty, - &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, - ), + Some((callee_ty, sig, strip_first)) => { + let sig = sig.skip_binder(); + self.check_call( + tgt_expr, + args, + callee_ty, + sig.inputs_and_output + .inputs() + .get(strip_first as usize..) + .unwrap_or(&[]), + sig.output(), + &[], + true, + expected, + ) + } None => { for &arg in args.iter() { self.infer_expr_no_expect(arg, ExprIsRead::Yes); @@ -2074,39 +1954,38 @@ impl<'db> InferenceContext<'db> { &mut self, tgt_expr: ExprId, args: &[ExprId], - method_ty: Ty, - receiver_ty: Ty, - expected: &Expectation, - ) -> Ty { - self.register_obligations_for_call(&method_ty); - let interner = self.table.interner; + method_ty: Ty<'db>, + receiver_ty: Ty<'db>, + expected: &Expectation<'db>, + ) -> Ty<'db> { + self.register_obligations_for_call(method_ty); 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].to_nextsolver(interner), - sig.params()[1..] - .iter() - .map(|param| param.to_nextsolver(interner)) - .collect(), - ) - } else { - (crate::next_solver::Ty::new_error(interner, ErrorGuaranteed), Vec::new()) - }, - sig.ret().to_nextsolver(interner), - sig.is_varargs, - ), + match method_ty.callable_sig(self.interner()) { + Some(sig) => { + let sig = sig.skip_binder(); + ( + if !sig.inputs_and_output.inputs().is_empty() { + ( + sig.inputs_and_output.as_slice()[0], + sig.inputs_and_output.inputs()[1..].to_vec(), + ) + } else { + (self.types.error, Vec::new()) + }, + sig.output(), + sig.c_variadic, + ) + } None => { 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.table.unify_ns(formal_receiver_ty, receiver_ty.to_nextsolver(interner)); + self.table.unify(formal_receiver_ty, receiver_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) + self.table.normalize_associated_types_in(ret_ty) } /// Generic function that factors out common logic from function calls, @@ -2115,18 +1994,16 @@ impl<'db> InferenceContext<'db> { &mut self, 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>, + formal_input_tys: &[Ty<'db>], + formal_output: Ty<'db>, // Expected output from the parent expression or statement - expectation: &Expectation, + expectation: &Expectation<'db>, // 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 @@ -2145,14 +2022,9 @@ impl<'db> InferenceContext<'db> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = ObligationCause::new(); - ocx.sup( - &origin, - self.table.trait_env.env, - expected_output.to_nextsolver(interner), - formal_output, - )?; + ocx.sup(&origin, self.table.trait_env.env, expected_output, formal_output)?; if !ocx.select_where_possible().is_empty() { - return Err(crate::next_solver::TypeError::Mismatch); + return Err(TypeError::Mismatch); } // Record all the argument types, with the args @@ -2200,9 +2072,9 @@ impl<'db> InferenceContext<'db> { // 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 demand_compatible = |this: &mut InferenceContext<'_, 'db>, idx| { + let formal_input_ty: Ty<'db> = formal_input_tys[idx]; + let expected_input_ty: Ty<'db> = expected_input_tys[idx]; let provided_arg = provided_args[idx]; debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty); @@ -2210,19 +2082,14 @@ impl<'db> InferenceContext<'db> { // 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 expectation = Expectation::rvalue_hint(this, expected_input_ty); - let checked_ty = this - .infer_expr_inner(provided_arg, &expectation, ExprIsRead::Yes) - .to_nextsolver(interner); + let checked_ty = this.infer_expr_inner(provided_arg, &expectation, ExprIsRead::Yes); // 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); + let coerced_ty = expectation.only_has_type(&mut this.table).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 @@ -2259,7 +2126,7 @@ impl<'db> InferenceContext<'db> { // If neither check failed, the types are compatible match formal_ty_error { - Ok(crate::next_solver::infer::InferOk { obligations, value: () }) => { + Ok(InferOk { obligations, value: () }) => { this.table.register_predicates(obligations); Ok(()) } @@ -2313,13 +2180,9 @@ impl<'db> InferenceContext<'db> { && 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: expected.to_chalk(interner), - actual: found.to_chalk(interner), - }, - ); + self.result + .type_mismatches + .insert((*arg).into(), TypeMismatch { expected, actual: found }); } } } @@ -2331,14 +2194,14 @@ impl<'db> InferenceContext<'db> { &mut self, expr: ExprId, def: GenericDefId, - generic_args: Option<&GenericArgs>, - ) -> Substitution { - struct LowererCtx<'a, 'b> { - ctx: &'a mut InferenceContext<'b>, + generic_args: Option<&HirGenericArgs>, + ) -> GenericArgs<'db> { + struct LowererCtx<'a, 'b, 'db> { + ctx: &'a mut InferenceContext<'b, 'db>, expr: ExprId, } - impl GenericArgsLowerer for LowererCtx<'_, '_> { + impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, 'db> { fn report_len_mismatch( &mut self, def: GenericDefId, @@ -2373,21 +2236,22 @@ impl<'db> InferenceContext<'db> { &mut self, param_id: GenericParamId, param: GenericParamDataRef<'_>, - arg: &GenericArg, - ) -> crate::GenericArg { + arg: &HirGenericArg, + ) -> GenericArg<'db> { match (param, arg) { - (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { - self.ctx.make_body_lifetime(*lifetime).cast(Interner) + ( + GenericParamDataRef::LifetimeParamData(_), + HirGenericArg::Lifetime(lifetime), + ) => self.ctx.make_body_lifetime(*lifetime).into(), + (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => { + self.ctx.make_body_ty(*type_ref).into() } - (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { - self.ctx.make_body_ty(*type_ref).cast(Interner) - } - (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { + (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => { let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); }; - let const_ty = self.ctx.db.const_param_ty(const_id); - self.ctx.make_body_const(*konst, const_ty).cast(Interner) + let const_ty = self.ctx.db.const_param_ty_ns(const_id); + self.ctx.make_body_const(*konst, const_ty).into() } _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), } @@ -2395,12 +2259,12 @@ impl<'db> InferenceContext<'db> { fn provided_type_like_const( &mut self, - const_ty: Ty, + const_ty: Ty<'db>, arg: TypeLikeConst<'_>, - ) -> crate::Const { + ) -> Const<'db> { match arg { TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path, const_ty), - TypeLikeConst::Infer => self.ctx.table.new_const_var(const_ty), + TypeLikeConst::Infer => self.ctx.table.next_const_var(), } } @@ -2410,35 +2274,15 @@ impl<'db> InferenceContext<'db> { param_id: GenericParamId, _param: GenericParamDataRef<'_>, _infer_args: bool, - _preceding_args: &[crate::GenericArg], - ) -> crate::GenericArg { + _preceding_args: &[GenericArg<'db>], + ) -> GenericArg<'db> { // Always create an inference var, even when `infer_args == false`. This helps with diagnostics, // and I think it's also required in the presence of `impl Trait` (that must be inferred). - match param_id { - GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner), - GenericParamId::ConstParamId(const_id) => self - .ctx - .table - .new_const_var(self.ctx.db.const_param_ty(const_id)) - .cast(Interner), - GenericParamId::LifetimeParamId(_) => { - self.ctx.table.new_lifetime_var().cast(Interner) - } - } + self.ctx.table.next_var_for_param(param_id) } - fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg { - match param_id { - GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner), - GenericParamId::ConstParamId(const_id) => self - .ctx - .table - .new_const_var(self.ctx.db.const_param_ty(const_id)) - .cast(Interner), - GenericParamId::LifetimeParamId(_) => { - self.ctx.table.new_lifetime_var().cast(Interner) - } - } + fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db> { + self.ctx.table.next_var_for_param(param_id) } fn report_elided_lifetimes_in_path( @@ -2472,36 +2316,34 @@ impl<'db> InferenceContext<'db> { ) } - fn register_obligations_for_call(&mut self, callable_ty: &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); + fn register_obligations_for_call(&mut self, callable_ty: Ty<'db>) { + let callable_ty = self.table.try_structurally_resolve_type(callable_ty); + if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() { let generic_predicates = - self.db.generic_predicates(GenericDefId::from_callable(self.db, def)); - for predicate in generic_predicates.iter() { - let (predicate, binders) = predicate - .clone() - .substitute(Interner, parameters) - .into_value_and_skipped_binders(); - always!(binders.len(Interner) == 0); // quantified where clauses not yet handled - self.push_obligation(predicate.cast(Interner)); + self.db.generic_predicates_ns(GenericDefId::from_callable(self.db, fn_def.0)); + if let Some(predicates) = generic_predicates.instantiate(self.interner(), parameters) { + let interner = self.interner(); + let param_env = self.table.trait_env.env; + self.table.register_predicates(predicates.map(|predicate| { + Obligation::new(interner, ObligationCause::new(), param_env, predicate) + })); } // add obligation for trait implementation, if this is a trait method - match def { + match fn_def.0 { CallableDefId::FunctionId(f) => { if let ItemContainerId::TraitId(trait_) = f.lookup(self.db).container { // construct a TraitRef let trait_params_len = generics(self.db, trait_.into()).len(); - let substs = Substitution::from_iter( - Interner, - // The generic parameters for the trait come after those for the - // function. - ¶meters.as_slice(Interner)[..trait_params_len], - ); - self.push_obligation( - TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } - .cast(Interner), + let substs = GenericArgs::new_from_iter( + self.interner(), + parameters.as_slice()[..trait_params_len].iter().copied(), ); + self.table.register_predicate(Obligation::new( + self.interner(), + ObligationCause::new(), + self.table.trait_env.env, + TraitRef::new(self.interner(), trait_.into(), substs), + )); } } CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} @@ -2510,11 +2352,10 @@ impl<'db> InferenceContext<'db> { } /// Returns the argument indices to skip. - fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> { - let (func, subst) = match callee.kind(Interner) { - TyKind::FnDef(fn_id, subst) => { - let callable = CallableDefId::from_chalk(self.db, *fn_id); - let func = match callable { + fn check_legacy_const_generics(&mut self, callee: Ty<'db>, args: &[ExprId]) -> Box<[u32]> { + let (func, _subst) = match callee.kind() { + TyKind::FnDef(callable, subst) => { + let func = match callable.0 { CallableDefId::FunctionId(f) => f, _ => return Default::default(), }; @@ -2542,15 +2383,10 @@ impl<'db> InferenceContext<'db> { } // check legacy const parameters - for (subst_idx, arg_idx) in legacy_const_generics_indices.iter().copied().enumerate() { - let arg = match subst.at(Interner, subst_idx).constant(Interner) { - Some(c) => c, - None => continue, // not a const parameter? - }; + for arg_idx in legacy_const_generics_indices.iter().copied() { if arg_idx >= args.len() as u32 { continue; } - let _ty = arg.data(Interner).ty.clone(); let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly self.infer_expr(args[arg_idx as usize], &expected, ExprIsRead::Yes); // FIXME: evaluate and unify with the const @@ -2561,17 +2397,19 @@ impl<'db> InferenceContext<'db> { } /// Dereferences a single level of immutable referencing. - fn deref_ty_if_possible(&mut self, ty: &Ty) -> Ty { - let ty = self.table.structurally_resolve_type(ty); - match ty.kind(Interner) { - TyKind::Ref(Mutability::Not, _, inner) => self.table.structurally_resolve_type(inner), + fn deref_ty_if_possible(&mut self, ty: Ty<'db>) -> Ty<'db> { + let ty = self.table.try_structurally_resolve_type(ty); + match ty.kind() { + TyKind::Ref(_, inner, Mutability::Not) => { + self.table.try_structurally_resolve_type(inner) + } _ => ty, } } /// Enforces expectations on lhs type and rhs type depending on the operator and returns the /// output type of the binary op. - fn enforce_builtin_binop_types(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> Ty { + fn enforce_builtin_binop_types(&mut self, lhs: Ty<'db>, rhs: Ty<'db>, op: BinaryOp) -> Ty<'db> { // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447). let lhs = self.deref_ty_if_possible(lhs); let rhs = self.deref_ty_if_possible(rhs); @@ -2583,9 +2421,9 @@ impl<'db> InferenceContext<'db> { let output_ty = match op { BinaryOp::LogicOp(_) => { - let bool_ = self.result.standard_types.bool_.clone(); - self.unify(&lhs, &bool_); - self.unify(&rhs, &bool_); + let bool_ = self.types.bool; + self.unify(lhs, bool_); + self.unify(rhs, bool_); bool_ } @@ -2596,14 +2434,14 @@ impl<'db> InferenceContext<'db> { BinaryOp::ArithOp(_) => { // LHS, RHS, and result will have the same type - self.unify(&lhs, &rhs); + self.unify(lhs, rhs); lhs } BinaryOp::CmpOp(_) => { // LHS and RHS will have the same type - self.unify(&lhs, &rhs); - self.result.standard_types.bool_.clone() + self.unify(lhs, rhs); + self.types.bool } BinaryOp::Assignment { op: None } => { @@ -2614,10 +2452,10 @@ impl<'db> InferenceContext<'db> { BinaryOp::Assignment { .. } => unreachable!("handled above"), }; - if is_assign { self.result.standard_types.unit.clone() } else { output_ty } + if is_assign { self.types.unit } else { output_ty } } - fn is_builtin_binop(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> bool { + fn is_builtin_binop(&mut self, lhs: Ty<'db>, rhs: Ty<'db>, op: BinaryOp) -> bool { // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447). let lhs = self.deref_ty_if_possible(lhs); let rhs = self.deref_ty_if_possible(rhs); @@ -2644,27 +2482,25 @@ impl<'db> InferenceContext<'db> { BinaryOp::ArithOp(ArithOp::BitAnd | ArithOp::BitOr | ArithOp::BitXor) => { lhs.is_integral() && rhs.is_integral() || lhs.is_floating_point() && rhs.is_floating_point() - || matches!( - (lhs.kind(Interner), rhs.kind(Interner)), - (TyKind::Scalar(Scalar::Bool), TyKind::Scalar(Scalar::Bool)) - ) + || matches!((lhs.kind(), rhs.kind()), (TyKind::Bool, TyKind::Bool)) } BinaryOp::CmpOp(_) => { let is_scalar = |kind| { matches!( kind, - &TyKind::Scalar(_) + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) | TyKind::FnDef(..) - | TyKind::Function(_) - | TyKind::Raw(..) - | TyKind::InferenceVar( - _, - TyVariableKind::Integer | TyVariableKind::Float - ) + | TyKind::FnPtr(..) + | TyKind::RawPtr(..) + | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) ) }; - is_scalar(lhs.kind(Interner)) && is_scalar(rhs.kind(Interner)) + is_scalar(lhs.kind()) && is_scalar(rhs.kind()) } BinaryOp::Assignment { op: None } => { @@ -2679,27 +2515,15 @@ impl<'db> InferenceContext<'db> { pub(super) fn with_breakable_ctx( &mut self, kind: BreakableKind, - ty: Option, + ty: Option>, label: Option, cb: impl FnOnce(&mut Self) -> T, - ) -> (Option, T) { + ) -> (Option>, T) { self.breakables.push({ - BreakableContext { - kind, - may_break: false, - coerce: ty.map(|ty| CoerceMany::new(ty.to_nextsolver(self.table.interner))), - label, - } + BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), 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).to_chalk(self.table.interner)) - } else { - None - }, - res, - ) + (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete(self)) } else { None }, res) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs index 2022447ad4339..b1c9146cc8b85 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs @@ -28,7 +28,7 @@ pub(crate) enum DivergingFallbackBehavior { ToNever, } -impl<'db> InferenceContext<'db> { +impl<'db> InferenceContext<'_, 'db> { pub(super) fn type_inference_fallback(&mut self) { debug!( "type-inference-fallback start obligations: {:#?}", @@ -324,7 +324,7 @@ impl<'db> InferenceContext<'db> { FxHashMap::with_capacity_and_hasher(diverging_vids.len(), FxBuildHasher); for &diverging_vid in &diverging_vids { - let diverging_ty = Ty::new_var(self.table.interner, diverging_vid); + let diverging_ty = Ty::new_var(self.interner(), diverging_vid); let root_vid = self.table.infer_ctxt.root_var(diverging_vid); let can_reach_non_diverging = Dfs::new(&coercion_graph, root_vid.as_u32().into()) .iter(&coercion_graph) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index c798e9e050a18..9edbc9dda0f10 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -1,7 +1,6 @@ //! Finds if an expression is an immutable context or a mutable context, which is used in selecting //! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar. -use chalk_ir::{Mutability, cast::Cast}; use hir_def::{ hir::{ Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement, @@ -11,14 +10,19 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::sym; +use rustc_ast_ir::Mutability; +use rustc_type_ir::inherent::IntoKind; +use crate::next_solver::infer::traits::{Obligation, ObligationCause}; +use crate::next_solver::{GenericArgs, TraitRef}; use crate::{ - Adjust, Adjustment, AutoBorrow, Interner, OverloadedDeref, TyBuilder, TyKind, + Adjust, Adjustment, AutoBorrow, OverloadedDeref, infer::{Expectation, InferenceContext, expr::ExprIsRead}, - lower::lower_to_chalk_mutability, + lower_nextsolver::lower_mutability, + next_solver::TyKind, }; -impl InferenceContext<'_> { +impl<'db> InferenceContext<'_, 'db> { pub(crate) fn infer_mut_body(&mut self) { self.infer_mut_expr(self.body.body_expr, Mutability::Not); } @@ -141,8 +145,8 @@ impl InferenceContext<'_> { target, }) = base_adjustments { - if let TyKind::Ref(_, _, ty) = target.kind(Interner) { - base_ty = Some(ty.clone()); + if let TyKind::Ref(_, ty, _) = target.kind() { + base_ty = Some(ty); } *mutability = Mutability::Mut; } @@ -150,15 +154,24 @@ impl InferenceContext<'_> { // Apply `IndexMut` obligation for non-assignee expr if let Some(base_ty) = base_ty { let index_ty = if let Some(ty) = self.result.type_of_expr.get(index) { - ty.clone() + *ty } else { self.infer_expr(index, &Expectation::none(), ExprIsRead::Yes) }; - let trait_ref = TyBuilder::trait_ref(self.db, index_trait) - .push(base_ty) - .fill(|_| index_ty.clone().cast(Interner)) - .build(); - self.push_obligation(trait_ref.cast(Interner)); + let trait_ref = TraitRef::new( + self.interner(), + index_trait.into(), + GenericArgs::new_from_iter( + self.interner(), + [base_ty.into(), index_ty.into()], + ), + ); + self.table.register_predicate(Obligation::new( + self.interner(), + ObligationCause::new(), + self.table.trait_env.env, + trait_ref, + )); } } self.infer_mut_expr(base, mutability); @@ -173,8 +186,8 @@ impl InferenceContext<'_> { { let ty = self.result.type_of_expr.get(*expr); let is_mut_ptr = ty.is_some_and(|ty| { - let ty = self.table.resolve_ty_shallow(ty); - matches!(ty.kind(Interner), chalk_ir::TyKind::Raw(Mutability::Mut, _)) + let ty = self.table.shallow_resolve(*ty); + matches!(ty.kind(), TyKind::RawPtr(_, Mutability::Mut)) }); if is_mut_ptr { mutability = Mutability::Not; @@ -200,7 +213,7 @@ impl InferenceContext<'_> { self.infer_mut_expr(*expr, Mutability::Not); } Expr::Ref { expr, rawness: _, mutability } => { - let mutability = lower_to_chalk_mutability(*mutability); + let mutability = lower_mutability(*mutability); self.infer_mut_expr(*expr, mutability); } Expr::BinaryOp { lhs, rhs, op: Some(BinaryOp::Assignment { .. }) } => { 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 6e11fa942bdfb..9f2f86dd3ef50 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 @@ -8,37 +8,35 @@ use hir_def::{ hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, }; use hir_expand::name::Name; +use rustc_ast_ir::Mutability; +use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _}; 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, - consteval::{self, try_const_usize, usize_const}, + DeclContext, DeclOrigin, InferenceDiagnostic, + consteval_nextsolver::{self, try_const_usize, usize_const}, infer::{ - BindingMode, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, - expr::ExprIsRead, + AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, + coerce::CoerceNever, expr::ExprIsRead, }, - lower::lower_to_chalk_mutability, - primitive::UintTy, - static_lifetime, + lower_nextsolver::lower_mutability, + next_solver::{GenericArgs, Ty, TyKind}, }; -impl InferenceContext<'_> { +impl<'db> InferenceContext<'_, 'db> { /// Infers type for tuple struct pattern or its corresponding assignee expression. /// /// Ellipses found in the original pattern or expression must be filtered out. pub(super) fn infer_tuple_struct_pat_like( &mut self, path: Option<&Path>, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, id: PatId, ellipsis: Option, subs: &[PatId], decl: Option, - ) -> Ty { + ) -> Ty<'db> { let (ty, def) = self.resolve_variant(id.into(), path, true); let var_data = def.map(|it| it.fields(self.db)); if let Some(variant) = def { @@ -56,12 +54,12 @@ impl InferenceContext<'_> { } } - self.unify(&ty, expected); + self.unify(ty, expected); match def { _ if subs.is_empty() => {} Some(def) => { - let field_types = self.db.field_types(def); + let field_types = self.db.field_types_ns(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); @@ -85,10 +83,10 @@ impl InferenceContext<'_> { { // FIXME(DIAGNOSE): private tuple field } - let f = field_types[local_id].clone(); + let f = field_types[local_id]; let expected_ty = match substs { - Some(substs) => f.substitute(Interner, substs), - None => f.substitute(Interner, &Substitution::empty(Interner)), + Some(substs) => f.instantiate(self.interner(), substs), + None => f.instantiate(self.interner(), &[]), }; self.process_remote_user_written_ty(expected_ty) } @@ -96,13 +94,13 @@ impl InferenceContext<'_> { } }; - self.infer_pat(subpat, &expected_ty, default_bm, decl); + self.infer_pat(subpat, expected_ty, default_bm, decl); } } None => { let err_ty = self.err_ty(); for &inner in subs { - self.infer_pat(inner, &err_ty, default_bm, decl); + self.infer_pat(inner, err_ty, default_bm, decl); } } } @@ -114,23 +112,23 @@ impl InferenceContext<'_> { pub(super) fn infer_record_pat_like( &mut self, path: Option<&Path>, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, id: PatId, subs: impl ExactSizeIterator, decl: Option, - ) -> Ty { + ) -> Ty<'db> { let (ty, def) = self.resolve_variant(id.into(), path, false); if let Some(variant) = def { self.write_variant_resolution(id.into(), variant); } - self.unify(&ty, expected); + self.unify(ty, expected); match def { _ if subs.len() == 0 => {} Some(def) => { - let field_types = self.db.field_types(def); + let field_types = self.db.field_types_ns(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); @@ -149,10 +147,10 @@ impl InferenceContext<'_> { variant: def, }); } - let f = field_types[local_id].clone(); + let f = field_types[local_id]; let expected_ty = match substs { - Some(substs) => f.substitute(Interner, substs), - None => f.substitute(Interner, &Substitution::empty(Interner)), + Some(substs) => f.instantiate(self.interner(), substs), + None => f.instantiate(self.interner(), &[]), }; self.process_remote_user_written_ty(expected_ty) } @@ -167,13 +165,13 @@ impl InferenceContext<'_> { } }; - self.infer_pat(inner, &expected_ty, default_bm, decl); + self.infer_pat(inner, expected_ty, default_bm, decl); } } None => { let err_ty = self.err_ty(); for (_, inner) in subs { - self.infer_pat(inner, &err_ty, default_bm, decl); + self.infer_pat(inner, err_ty, default_bm, decl); } } } @@ -186,16 +184,16 @@ impl InferenceContext<'_> { /// Ellipses found in the original pattern or expression must be filtered out. pub(super) fn infer_tuple_pat_like( &mut self, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, ellipsis: Option, subs: &[PatId], decl: Option, - ) -> Ty { + ) -> Ty<'db> { let expected = self.table.structurally_resolve_type(expected); - let expectations = match expected.as_tuple() { - Some(parameters) => parameters.as_slice(Interner), - _ => &[], + let expectations = match expected.kind() { + TyKind::Tuple(parameters) => parameters, + _ => self.types.empty_tys, }; let ((pre, post), n_uncovered_patterns) = match ellipsis { @@ -204,10 +202,8 @@ impl InferenceContext<'_> { } None => ((subs, &[][..]), 0), }; - let mut expectations_iter = expectations - .iter() - .map(|a| a.assert_ty_ref(Interner).clone()) - .chain(repeat_with(|| self.table.new_type_var())); + let mut expectations_iter = + expectations.iter().chain(repeat_with(|| self.table.next_ty_var())); let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + subs.len()); @@ -215,31 +211,35 @@ impl InferenceContext<'_> { // Process pre for (ty, pat) in inner_tys.iter_mut().zip(pre) { - *ty = self.infer_pat(*pat, ty, default_bm, decl); + *ty = self.infer_pat(*pat, *ty, default_bm, decl); } // Process post for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) { - *ty = self.infer_pat(*pat, ty, default_bm, decl); + *ty = self.infer_pat(*pat, *ty, default_bm, decl); } - TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) - .intern(Interner) + Ty::new_tup_from_iter(self.interner(), inner_tys.into_iter()) } /// The resolver needs to be updated to the surrounding expression when inside assignment /// (because there, `Pat::Path` can refer to a variable). - pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty, decl: Option) { + pub(super) fn infer_top_pat( + &mut self, + pat: PatId, + expected: Ty<'db>, + decl: Option, + ) { self.infer_pat(pat, expected, BindingMode::default(), decl); } fn infer_pat( &mut self, pat: PatId, - expected: &Ty, + expected: Ty<'db>, mut default_bm: BindingMode, decl: Option, - ) -> Ty { + ) -> Ty<'db> { let mut expected = self.table.structurally_resolve_type(expected); if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { @@ -251,9 +251,9 @@ impl InferenceContext<'_> { default_bm = BindingMode::Move; } else if self.is_non_ref_pat(self.body, pat) { let mut pat_adjustments = Vec::new(); - while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - pat_adjustments.push(expected.clone()); - expected = self.table.structurally_resolve_type(inner); + while let TyKind::Ref(_lifetime, inner, mutability) = expected.kind() { + pat_adjustments.push(expected); + expected = self.table.try_structurally_resolve_type(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), @@ -273,25 +273,21 @@ impl InferenceContext<'_> { let ty = match &self.body[pat] { Pat::Tuple { args, ellipsis } => { - self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args, decl) + self.infer_tuple_pat_like(expected, default_bm, *ellipsis, args, decl) } Pat::Or(pats) => { for pat in pats.iter() { - self.infer_pat(*pat, &expected, default_bm, decl); + self.infer_pat(*pat, expected, default_bm, decl); } - expected.clone() + expected + } + &Pat::Ref { pat, mutability } => { + self.infer_ref_pat(pat, lower_mutability(mutability), expected, default_bm, decl) } - &Pat::Ref { pat, mutability } => self.infer_ref_pat( - pat, - lower_to_chalk_mutability(mutability), - &expected, - default_bm, - decl, - ), Pat::TupleStruct { path: p, args: subpats, ellipsis } => self .infer_tuple_struct_pat_like( p.as_deref(), - &expected, + expected, default_bm, pat, *ellipsis, @@ -300,29 +296,26 @@ impl InferenceContext<'_> { ), Pat::Record { path: p, args: fields, ellipsis: _ } => { let subs = fields.iter().map(|f| (f.name.clone(), f.pat)); - self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs, decl) + self.infer_record_pat_like(p.as_deref(), expected, default_bm, pat, subs, decl) } 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()); + let ty_inserted_vars = self.insert_type_vars_shallow(ty); match self.coerce( pat.into(), - expected.to_nextsolver(self.table.interner), - ty_inserted_vars.to_nextsolver(self.table.interner), + expected, + ty_inserted_vars, AllowTwoPhase::No, CoerceNever::Yes, ) { Ok(coerced_ty) => { - self.write_pat_ty(pat, coerced_ty.to_chalk(self.table.interner)); + self.write_pat_ty(pat, coerced_ty); return self.pat_ty_after_adjustment(pat); } Err(_) => { self.result.type_mismatches.insert( pat.into(), - TypeMismatch { - expected: expected.clone(), - actual: ty_inserted_vars.clone(), - }, + TypeMismatch { expected, actual: ty_inserted_vars }, ); self.write_pat_ty(pat, ty); // We return `expected` to prevent cascading errors. I guess an alternative is to @@ -332,81 +325,77 @@ impl InferenceContext<'_> { } } Pat::Bind { id, subpat } => { - return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected, decl); + return self.infer_bind_pat(pat, *id, default_bm, *subpat, expected, decl); } Pat::Slice { prefix, slice, suffix } => { - self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm, decl) + self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl) } - Pat::Wild => expected.clone(), + Pat::Wild => expected, Pat::Range { .. } => { // FIXME: do some checks here. - expected.clone() + expected } &Pat::Lit(expr) => { // Don't emit type mismatches again, the expression lowering already did that. - let ty = self.infer_lit_pat(expr, &expected); + let ty = self.infer_lit_pat(expr, expected); self.write_pat_ty(pat, ty); return self.pat_ty_after_adjustment(pat); } Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { let (inner_ty, alloc_ty) = match expected.as_adt() { - Some((adt, subst)) if adt == box_adt => ( - subst.at(Interner, 0).assert_ty_ref(Interner).clone(), - subst.as_slice(Interner).get(1).and_then(|a| a.ty(Interner).cloned()), - ), - _ => (self.result.standard_types.unknown.clone(), None), + Some((adt, subst)) if adt == box_adt => { + (subst.type_at(0), subst.as_slice().get(1).and_then(|a| a.as_type())) + } + _ => (self.types.error, None), }; - let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm, decl); - let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty); - - if let Some(alloc_ty) = alloc_ty { - b = b.push(alloc_ty); - } - b.fill_with_defaults(self.db, || self.table.new_type_var()).build() + let inner_ty = self.infer_pat(*inner, inner_ty, default_bm, decl); + Ty::new_adt( + self.interner(), + box_adt, + GenericArgs::fill_with_defaults( + self.interner(), + box_adt.into(), + std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)), + |_, _, id, _| self.table.next_var_for_param(id), + ), + ) } None => self.err_ty(), }, Pat::ConstBlock(expr) => { let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); - let result = self.infer_expr( - *expr, - &Expectation::has_type(expected.clone()), - ExprIsRead::Yes, - ); + let result = + self.infer_expr(*expr, &Expectation::has_type(expected), ExprIsRead::Yes); self.inside_assignment = old_inside_assign; result } Pat::Expr(expr) => { let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); // LHS of assignment doesn't constitute reads. - let result = self.infer_expr_coerce( - *expr, - &Expectation::has_type(expected.clone()), - ExprIsRead::No, - ); + let result = + self.infer_expr_coerce(*expr, &Expectation::has_type(expected), ExprIsRead::No); // We are returning early to avoid the unifiability check below. let lhs_ty = self.insert_type_vars_shallow(result); let ty = match self.coerce( pat.into(), - expected.to_nextsolver(self.table.interner), - lhs_ty.to_nextsolver(self.table.interner), + expected, + lhs_ty, AllowTwoPhase::No, CoerceNever::Yes, ) { - Ok(ty) => ty.to_chalk(self.table.interner), + Ok(ty) => ty, Err(_) => { - self.result.type_mismatches.insert( - pat.into(), - TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() }, - ); + self.result + .type_mismatches + .insert(pat.into(), TypeMismatch { expected, actual: lhs_ty }); // `rhs_ty` is returned so no further type mismatches are // reported because of this mismatch. expected } }; - self.write_pat_ty(pat, ty.clone()); + self.write_pat_ty(pat, ty); self.inside_assignment = old_inside_assign; return ty; } @@ -415,46 +404,43 @@ impl InferenceContext<'_> { // use a new type variable if we got error type here let ty = self.insert_type_vars_shallow(ty); // FIXME: This never check is odd, but required with out we do inference right now - if !expected.is_never() && !self.unify(&ty, &expected) { - self.result - .type_mismatches - .insert(pat.into(), TypeMismatch { expected, actual: ty.clone() }); + if !expected.is_never() && !self.unify(ty, expected) { + self.result.type_mismatches.insert(pat.into(), TypeMismatch { expected, actual: ty }); } self.write_pat_ty(pat, ty); self.pat_ty_after_adjustment(pat) } - fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty { - self.result + fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty<'db> { + *self + .result .pat_adjustments .get(&pat) .and_then(|it| it.first()) .unwrap_or(&self.result.type_of_pat[pat]) - .clone() } fn infer_ref_pat( &mut self, inner_pat: PatId, mutability: Mutability, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, decl: Option, - ) -> Ty { - let (expectation_type, expectation_lt) = match expected.as_reference() { - Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime), - None => { - let inner_ty = self.table.new_type_var(); - let inner_lt = self.table.new_lifetime_var(); - let ref_ty = - TyKind::Ref(mutability, inner_lt.clone(), inner_ty.clone()).intern(Interner); + ) -> Ty<'db> { + let (expectation_type, expectation_lt) = match expected.kind() { + TyKind::Ref(lifetime, inner_ty, _exp_mut) => (inner_ty, lifetime), + _ => { + let inner_ty = self.table.next_ty_var(); + let inner_lt = self.table.next_region_var(); + let ref_ty = Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability); // Unification failure will be reported by the caller. - self.unify(&ref_ty, expected); + self.unify(ref_ty, expected); (inner_ty, inner_lt) } }; - let subty = self.infer_pat(inner_pat, &expectation_type, default_bm, decl); - TyKind::Ref(mutability, expectation_lt, subty).intern(Interner) + let subty = self.infer_pat(inner_pat, expectation_type, default_bm, decl); + Ty::new_ref(self.interner(), expectation_lt, subty, mutability) } fn infer_bind_pat( @@ -463,9 +449,9 @@ impl InferenceContext<'_> { binding: BindingId, default_bm: BindingMode, subpat: Option, - expected: &Ty, + expected: Ty<'db>, decl: Option, - ) -> Ty { + ) -> Ty<'db> { let Binding { mode, .. } = self.body[binding]; let mode = if mode == BindingAnnotation::Unannotated { default_bm @@ -476,31 +462,31 @@ impl InferenceContext<'_> { let inner_ty = match subpat { Some(subpat) => self.infer_pat(subpat, expected, default_bm, decl), - None => expected.clone(), + None => expected, }; let inner_ty = self.insert_type_vars_shallow(inner_ty); let bound_ty = match mode { BindingMode::Ref(mutability) => { - let inner_lt = self.table.new_lifetime_var(); - TyKind::Ref(mutability, inner_lt, inner_ty.clone()).intern(Interner) + let inner_lt = self.table.next_region_var(); + Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability) } - BindingMode::Move => inner_ty.clone(), + BindingMode::Move => inner_ty, }; - self.write_pat_ty(pat, inner_ty.clone()); + self.write_pat_ty(pat, inner_ty); self.write_binding_ty(binding, bound_ty); inner_ty } fn infer_slice_pat( &mut self, - expected: &Ty, + expected: Ty<'db>, prefix: &[PatId], - slice: &Option, + slice: Option, suffix: &[PatId], default_bm: BindingMode, decl: Option, - ) -> Ty { + ) -> Ty<'db> { 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 @@ -510,56 +496,61 @@ impl InferenceContext<'_> { && let Some(resolved_array_ty) = self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice) { - self.unify(&expected, &resolved_array_ty); + self.unify(expected, resolved_array_ty); } - let expected = self.table.structurally_resolve_type(&expected); - let elem_ty = match expected.kind(Interner) { - TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), + let expected = self.table.try_structurally_resolve_type(expected); + let elem_ty = match expected.kind() { + TyKind::Array(st, _) | TyKind::Slice(st) => st, _ => self.err_ty(), }; for &pat_id in prefix.iter().chain(suffix.iter()) { - self.infer_pat(pat_id, &elem_ty, default_bm, decl); + self.infer_pat(pat_id, elem_ty, default_bm, decl); } - if let &Some(slice_pat_id) = slice { - let rest_pat_ty = match expected.kind(Interner) { + if let Some(slice_pat_id) = slice { + let rest_pat_ty = match expected.kind() { TyKind::Array(_, length) => { let len = try_const_usize(self.db, length); let len = len.and_then(|len| len.checked_sub((prefix.len() + suffix.len()) as u128)); - TyKind::Array(elem_ty.clone(), usize_const(self.db, len, self.resolver.krate())) + Ty::new_array_with_const_len( + self.interner(), + elem_ty, + usize_const(self.db, len, self.resolver.krate()), + ) } - _ => TyKind::Slice(elem_ty.clone()), - } - .intern(Interner); - self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm, decl); + _ => Ty::new_slice(self.interner(), elem_ty), + }; + self.infer_pat(slice_pat_id, rest_pat_ty, default_bm, decl); } - match expected.kind(Interner) { - TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()), - _ => TyKind::Slice(elem_ty), + match expected.kind() { + TyKind::Array(_, const_) => { + Ty::new_array_with_const_len(self.interner(), elem_ty, const_) + } + _ => Ty::new_slice(self.interner(), elem_ty), } - .intern(Interner) } - fn infer_lit_pat(&mut self, expr: ExprId, expected: &Ty) -> Ty { + fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] - && let Some((inner, ..)) = expected.as_reference() + && let TyKind::Ref(_, inner, _) = expected.kind() { - 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); - let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner); - self.write_expr_ty(expr, ty.clone()); + let inner = self.table.try_structurally_resolve_type(inner); + if matches!(inner.kind(), TyKind::Slice(_)) { + let elem_ty = self.types.u8; + let slice_ty = Ty::new_slice(self.interner(), elem_ty); + let ty = + Ty::new_ref(self.interner(), self.types.re_static, slice_ty, Mutability::Not); + self.write_expr_ty(expr, ty); return ty; } } - self.infer_expr(expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes) + self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes) } fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool { @@ -593,17 +584,21 @@ impl InferenceContext<'_> { &mut self, before: &[PatId], suffix: &[PatId], - slice: &Option, - ) -> Option { - if !slice.is_none() { + slice: Option, + ) -> Option> { + if slice.is_some() { return None; } let len = before.len() + suffix.len(); - let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db)); - - let elem_ty = self.table.new_type_var(); - let array_ty = TyKind::Array(elem_ty, size).intern(Interner); + let size = consteval_nextsolver::usize_const( + self.db, + Some(len as u128), + self.owner.krate(self.db), + ); + + let elem_ty = self.table.next_ty_var(); + let array_ty = Ty::new_array_with_const_len(self.interner(), elem_ty, size); Some(array_ty) } 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 733f3c278806f..7517272362b2c 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 @@ -1,52 +1,50 @@ //! Path expression resolution. -use chalk_ir::cast::Cast; use hir_def::{ - AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, + AdtId, AssocItemId, GenericDefId, GenericParamId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, }; use hir_expand::name::Name; +use rustc_type_ir::inherent::{SliceLike, Ty as _}; use stdx::never; use crate::{ - InferenceDiagnostic, Interner, LifetimeElisionKind, Substitution, TraitRef, TraitRefExt, Ty, - TyBuilder, TyExt, TyKind, ValueTyDefId, - builder::ParamKind, - consteval, error_lifetime, + InferenceDiagnostic, ValueTyDefId, consteval_nextsolver, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, + lower_nextsolver::LifetimeElisionKind, method_resolution::{self, VisibleFromModule}, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + GenericArg, GenericArgs, TraitRef, Ty, + infer::traits::{Obligation, ObligationCause}, }, - to_chalk_trait_id, }; use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; -impl<'db> InferenceContext<'db> { - pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { +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) => { (value_def, generic_def, substs) } ValuePathResolution::NonGeneric(ty) => return Some(ty), }; - let substs = - self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs); + let args = self.process_remote_user_written_ty(substs); - self.add_required_obligations_for_value_path(generic_def, &substs); + self.add_required_obligations_for_value_path(generic_def, args); - let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner); + let ty = self.db.value_ty(value_def)?.instantiate(self.interner(), args); let ty = self.process_remote_user_written_ty(ty); Some(ty) } - fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { + fn resolve_value_path( + &mut self, + path: &Path, + id: ExprOrPatId, + ) -> Option> { let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?; let value_def: ValueTyDefId = match value { @@ -65,7 +63,7 @@ impl<'db> InferenceContext<'db> { } ValueNs::LocalBinding(pat) => { return match self.result.type_of_binding.get(pat) { - Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())), + Some(ty) => Some(ValuePathResolution::NonGeneric(*ty)), None => { never!("uninferred pattern?"); None @@ -73,17 +71,12 @@ impl<'db> InferenceContext<'db> { }; } ValueNs::ImplSelf(impl_id) => { - let generics = crate::generics::generics(self.db, impl_id.into()); - let interner = DbInterner::new_with(self.db, None, None); - let substs = generics.placeholder_subst(self.db); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = - self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); + let ty = self.db.impl_self_ty(impl_id).instantiate_identity(); return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { Some(ValuePathResolution::GenericDef( struct_id.into(), struct_id.into(), - substs.clone(), + substs, )) } else { // FIXME: report error, invalid Self reference @@ -91,15 +84,14 @@ impl<'db> InferenceContext<'db> { }; } ValueNs::GenericParam(it) => { - return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it))); + return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty_ns(it))); } }; let generic_def = value_def.to_generic_def_id(self.db); if let GenericDefId::StaticId(_) = generic_def { - let interner = DbInterner::new_with(self.db, None, None); // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type. - let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner); + let ty = self.db.value_ty(value_def)?.skip_binder(); return Some(ValuePathResolution::NonGeneric(ty)); }; @@ -111,57 +103,34 @@ impl<'db> InferenceContext<'db> { } path_ctx.substs_from_path(value_def, true, false) }); - let substs = substs.as_slice(Interner); - - if let ValueNs::EnumVariantId(_) = value { - let mut it = substs - .iter() - .chain(self_subst.as_ref().map_or(&[][..], |s| s.as_slice(Interner))) - .cloned(); - let builder = TyBuilder::subst_for_def(self.db, generic_def, None); - let substs = builder - .fill(|x| { - it.next().unwrap_or_else(|| match x { - ParamKind::Type => { - self.result.standard_types.unknown.clone().cast(Interner) - } - ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - }) - .build(); - return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)); - } - - let parent_substs = self_subst.or_else(|| { - let generics = generics(self.db, generic_def); - let parent_params_len = generics.parent_generics()?.len(); - let parent_args = &substs[..parent_params_len]; - Some(Substitution::from_iter(Interner, parent_args)) - }); - let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner)); - let mut it = substs.iter().skip(parent_substs_len).cloned(); - let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs); - let substs = builder - .fill(|x| { - it.next().unwrap_or_else(|| match x { - ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner), - ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - }) - .build(); + let parent_substs_len = self_subst.map_or(0, |it| it.len()); + let substs = GenericArgs::fill_rest( + self.interner(), + generic_def.into(), + self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)), + |_, _, id, _| self.error_param(id), + ); Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)) } + fn error_param(&mut self, id: GenericParamId) -> GenericArg<'db> { + match id { + GenericParamId::TypeParamId(_) => self.types.error.into(), + GenericParamId::ConstParamId(id) => { + consteval_nextsolver::unknown_const_as_generic(self.db.const_param_ty_ns(id)) + } + GenericParamId::LifetimeParamId(_) => self.types.re_error.into(), + } + } + pub(super) fn resolve_value_path_inner( &mut self, path: &Path, id: ExprOrPatId, no_diagnostics: bool, - ) -> Option<(ValueNs, Option>)> { + ) -> Option<(ValueNs, Option>)> { // Don't use `self.make_ty()` here as we need `orig_ns`. let mut ctx = TyLoweringContext::new( self.db, @@ -211,7 +180,7 @@ impl<'db> InferenceContext<'db> { let (resolution, substs) = match (def, is_before_last) { (TypeNs::TraitId(trait_), true) => { - let self_ty = self.table.new_type_var(); + let self_ty = self.table.next_ty_var(); let trait_ref = path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty, true); drop_ctx(ctx, no_diagnostics); @@ -225,7 +194,7 @@ impl<'db> InferenceContext<'db> { path_ctx.ignore_last_segment(); let (ty, _) = path_ctx.lower_partly_resolved_path(def, true); drop_ctx(ctx, no_diagnostics); - if ty.is_unknown() { + if ty.is_ty_error() { return None; } @@ -241,21 +210,25 @@ impl<'db> InferenceContext<'db> { return Some((value, self_subst)); #[inline] - fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) { + fn drop_ctx(mut ctx: TyLoweringContext<'_, '_>, no_diagnostics: bool) { if no_diagnostics { ctx.forget_diagnostics(); } } } - fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) { - let predicates = self.db.generic_predicates(def); - for predicate in predicates.iter() { - let (predicate, binders) = - predicate.clone().substitute(Interner, &subst).into_value_and_skipped_binders(); - // Quantified where clauses are not yet handled. - stdx::always!(binders.is_empty(Interner)); - self.push_obligation(predicate.cast(Interner)); + fn add_required_obligations_for_value_path( + &mut self, + def: GenericDefId, + subst: GenericArgs<'db>, + ) { + let predicates = self.db.generic_predicates_ns(def); + let interner = self.interner(); + let param_env = self.table.trait_env.env; + if let Some(predicates) = predicates.instantiate(self.interner(), subst) { + self.table.register_predicates(predicates.map(|predicate| { + Obligation::new(interner, ObligationCause::new(), param_env, predicate) + })); } // We need to add `Self: Trait` obligation when `def` is a trait assoc item. @@ -267,21 +240,27 @@ impl<'db> InferenceContext<'db> { if let ItemContainerId::TraitId(trait_) = container { let parent_len = generics(self.db, def).parent_generics().map_or(0, |g| g.len_self()); - let parent_subst = - Substitution::from_iter(Interner, subst.iter(Interner).take(parent_len)); - let trait_ref = - TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: parent_subst }; - self.push_obligation(trait_ref.cast(Interner)); + let parent_subst = GenericArgs::new_from_iter( + interner, + subst.as_slice()[..parent_len].iter().copied(), + ); + let trait_ref = TraitRef::new(interner, trait_.into(), parent_subst); + self.table.register_predicate(Obligation::new( + interner, + ObligationCause::new(), + param_env, + trait_ref, + )); } } fn resolve_trait_assoc_item( &mut self, - trait_ref: TraitRef, + trait_ref: TraitRef<'db>, segment: PathSegment<'_>, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - let trait_ = trait_ref.hir_trait_id(); + ) -> Option<(ValueNs, GenericArgs<'db>)> { + let trait_ = trait_ref.def_id.0; let item = trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { @@ -309,25 +288,25 @@ impl<'db> InferenceContext<'db> { AssocItemId::TypeAliasId(_) => unreachable!(), }; - self.write_assoc_resolution(id, item, trait_ref.substitution.clone()); - Some((def, trait_ref.substitution)) + self.write_assoc_resolution(id, item, trait_ref.args); + Some((def, trait_ref.args)) } fn resolve_ty_assoc_item( &mut self, - ty: Ty, + ty: Ty<'db>, name: &Name, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - if let TyKind::Error = ty.kind(Interner) { + ) -> Option<(ValueNs, GenericArgs<'db>)> { + if ty.is_ty_error() { return None; } - if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) { + if let Some(result) = self.resolve_enum_variant_on_ty(ty, name, id) { return Some(result); } - let canonical_ty = self.canonicalize(ty.clone().to_nextsolver(self.table.interner)); + let canonical_ty = self.canonicalize(ty); let mut not_visible = None; let res = method_resolution::iterate_method_candidates( @@ -362,24 +341,28 @@ impl<'db> InferenceContext<'db> { }; let substs = match container { ItemContainerId::ImplId(impl_id) => { - let interner = DbInterner::new_with(self.db, None, None); - let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None) - .fill_with_inference_vars(&mut self.table) - .build(); - let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner); + let impl_substs = self.table.fresh_args_for_item(impl_id.into()); let impl_self_ty = - self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); - self.unify(&impl_self_ty, &ty); + self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs); + self.unify(impl_self_ty, ty); impl_substs } ItemContainerId::TraitId(trait_) => { // we're picking this method - let trait_ref = TyBuilder::trait_ref(self.db, trait_) - .push(ty.clone()) - .fill_with_inference_vars(&mut self.table) - .build(); - self.push_obligation(trait_ref.clone().cast(Interner)); - trait_ref.substitution + let args = GenericArgs::fill_rest( + self.interner(), + trait_.into(), + [ty.into()], + |_, _, id, _| self.table.next_var_for_param(id), + ); + let trait_ref = TraitRef::new(self.interner(), trait_.into(), args); + self.table.register_predicate(Obligation::new( + self.interner(), + ObligationCause::new(), + self.table.trait_env.env, + trait_ref, + )); + args } ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { never!("assoc item contained in module/extern block"); @@ -387,7 +370,7 @@ impl<'db> InferenceContext<'db> { } }; - self.write_assoc_resolution(id, item, substs.clone()); + self.write_assoc_resolution(id, item, substs); if !visible { self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item }); } @@ -396,11 +379,11 @@ impl<'db> InferenceContext<'db> { fn resolve_enum_variant_on_ty( &mut self, - ty: &Ty, + ty: Ty<'db>, name: &Name, id: ExprOrPatId, - ) -> Option<(ValueNs, Substitution)> { - let ty = self.table.structurally_resolve_type(ty); + ) -> Option<(ValueNs, GenericArgs<'db>)> { + let ty = self.table.try_structurally_resolve_type(ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, @@ -408,14 +391,14 @@ impl<'db> InferenceContext<'db> { let enum_data = enum_id.enum_variants(self.db); let variant = enum_data.variant(name)?; self.write_variant_resolution(id, variant.into()); - Some((ValueNs::EnumVariantId(variant), subst.clone())) + Some((ValueNs::EnumVariantId(variant), subst)) } } #[derive(Debug)] -enum ValuePathResolution { +enum ValuePathResolution<'db> { // It's awkward to wrap a single ID in two enums, but we need both and this saves fallible // conversion between them + `unwrap()`. - GenericDef(ValueTyDefId, GenericDefId, Substitution), - NonGeneric(Ty), + GenericDef(ValueTyDefId, GenericDefId, GenericArgs<'db>), + NonGeneric(Ty<'db>), } 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 108cf5b1a2b8e..89bab4e59c94c 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 @@ -2,49 +2,46 @@ use std::fmt; -use chalk_ir::{ - CanonicalVarKind, TyVariableKind, cast::Cast, fold::TypeFoldable, interner::HasInterner, -}; -use either::Either; +use chalk_ir::cast::Cast; +use hir_def::GenericParamId; use hir_def::{AdtId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::{DebruijnIndex, InferConst, InferTy, RegionVid}; use rustc_type_ir::{ - TyVid, TypeVisitableExt, UpcastFrom, - inherent::{IntoKind, Span, Term as _, Ty as _}, - relate::{Relate, solver_relating::RelateExt}, + TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UpcastFrom, + inherent::{Const as _, IntoKind, Ty as _}, solve::{Certainty, GoalSource}, }; use smallvec::SmallVec; use triomphe::Arc; -use super::{InferResult, InferenceContext, TypeError}; +use crate::next_solver::{Binder, ConstKind, GenericArgs, RegionKind, SolverDefId}; use crate::{ - AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData, - InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, TraitEnvironment, Ty, - TyExt, TyKind, VariableKind, - consteval::unknown_const, - db::HirDatabase, - fold_generic_args, fold_tys_and_consts, + Interner, TraitEnvironment, + db::{HirDatabase, InternedOpaqueTyId}, + infer::InferenceContext, next_solver::{ - self, ClauseKind, DbInterner, ErrorGuaranteed, Predicate, PredicateKind, SolverDefIds, - Term, TraitRef, - fulfill::FulfillmentCtxt, + self, AliasTy, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, Predicate, + PredicateKind, Region, SolverDefIds, TraitRef, Ty, TyKind, TypingMode, + fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ - DbInternerInferExt, InferCtxt, InferOk, + DbInternerInferExt, DefineOpaqueTypes, InferCtxt, InferOk, InferResult, + at::ToTrace, snapshot::CombinedSnapshot, - traits::{Obligation, ObligationCause}, + traits::{Obligation, ObligationCause, PredicateObligation}, }, inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, mapping::{ChalkToNextSolver, NextSolverToChalk}, + obligation_ctxt::ObligationCtxt, }, traits::{ FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, }, }; -impl<'db> InferenceContext<'db> { +impl<'db> InferenceContext<'_, 'db> { pub(super) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where T: rustc_type_ir::TypeFoldable>, @@ -77,7 +74,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { return; } - let db = self.ctx.interner; + 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 @@ -121,9 +118,9 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { pub fn could_unify( db: &dyn HirDatabase, env: Arc>, - tys: &Canonical<(Ty, Ty)>, + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, ) -> bool { - unify(db, env, tys).is_some() + could_unify_impl(db, env, tys, |ctxt| ctxt.select_where_possible()) } /// Check if types unify eagerly making sure there are no unresolved goals. @@ -133,94 +130,65 @@ pub fn could_unify( pub fn could_unify_deeply( db: &dyn HirDatabase, env: Arc>, - tys: &Canonical<(Ty, Ty)>, + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, ) -> bool { - let mut table = InferenceTable::new(db, env); - let vars = make_substitutions(tys, &mut table); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); - 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.select_obligations_where_possible(); - let ty1_with_vars = table.resolve_completely(ty1_with_vars); - let ty2_with_vars = table.resolve_completely(ty2_with_vars); - table.unify_deeply(&ty1_with_vars, &ty2_with_vars) + could_unify_impl(db, env, tys, |ctxt| ctxt.select_all_or_error()) } -pub(crate) fn unify( +fn could_unify_impl( db: &dyn HirDatabase, env: Arc>, - tys: &Canonical<(Ty, Ty)>, -) -> Option { - let mut table = InferenceTable::new(db, env); - let vars = make_substitutions(tys, &mut table); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner); - let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner); - if !table.unify(&ty1_with_vars, &ty2_with_vars) { - return None; - } - // 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.data(Interner) { - GenericArgData::Ty(ty) => ty.inference_var(Interner), - GenericArgData::Lifetime(lt) => lt.inference_var(Interner), - GenericArgData::Const(c) => c.inference_var(Interner), - } == Some(iv)) - }; - let fallback = |iv, kind, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else( - || TyKind::Error.intern(Interner).cast(Interner), - |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner), - ), - chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else( - || crate::error_lifetime().cast(Interner), - |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner), - ), - chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else( - || crate::unknown_const(ty.clone()).cast(Interner), - |i| BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner), - ), - }; - Some(Substitution::from_iter( - Interner, - vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)), - )) + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, + select: for<'a, 'db> fn(&mut ObligationCtxt<'a, 'db>) -> Vec>, +) -> bool { + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things), + // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT + // and async blocks. + let infcx = interner.infer_ctxt().build(TypingMode::Analysis { + defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), + }); + let cause = ObligationCause::dummy(); + let at = infcx.at(&cause, env.env); + let vars = make_substitutions(tys, &infcx); + let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner).to_nextsolver(interner); + let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner).to_nextsolver(interner); + let mut ctxt = ObligationCtxt::new(&infcx); + let can_unify = at + .eq(DefineOpaqueTypes::No, ty1_with_vars, ty2_with_vars) + .map(|infer_ok| ctxt.register_infer_ok_obligations(infer_ok)) + .is_ok(); + can_unify && select(&mut ctxt).is_empty() } fn make_substitutions( - tys: &chalk_ir::Canonical<(chalk_ir::Ty, chalk_ir::Ty)>, - table: &mut InferenceTable<'_>, -) -> chalk_ir::Substitution { - Substitution::from_iter( + tys: &crate::Canonical<(crate::Ty, crate::Ty)>, + infcx: &InferCtxt<'_>, +) -> crate::Substitution { + let interner = infcx.interner; + crate::Substitution::from_iter( Interner, tys.binders.iter(Interner).map(|it| match &it.kind { - chalk_ir::VariableKind::Ty(_) => table.new_type_var().cast(Interner), + chalk_ir::VariableKind::Ty(_) => infcx.next_ty_var().to_chalk(interner).cast(Interner), // FIXME: maybe wrong? - chalk_ir::VariableKind::Lifetime => table.new_type_var().cast(Interner), - chalk_ir::VariableKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner), + chalk_ir::VariableKind::Lifetime => { + infcx.next_ty_var().to_chalk(interner).cast(Interner) + } + chalk_ir::VariableKind::Const(_ty) => { + infcx.next_const_var().to_chalk(interner).cast(Interner) + } }), ) } -bitflags::bitflags! { - #[derive(Default, Clone, Copy)] - pub(crate) struct TypeVariableFlags: u8 { - const DIVERGING = 1 << 0; - const INTEGER = 1 << 1; - const FLOAT = 1 << 2; - } -} - #[derive(Clone)] pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) interner: DbInterner<'db>, pub(crate) trait_env: Arc>, - pub(crate) tait_coercion_table: Option>, + pub(crate) tait_coercion_table: Option>>, pub(crate) infer_ctxt: InferCtxt<'db>, pub(super) fulfillment_cx: FulfillmentCtxt<'db>, - pub(super) diverging_type_vars: FxHashSet>, + pub(super) diverging_type_vars: FxHashSet>, } pub(crate) struct InferenceTableSnapshot<'db> { @@ -236,7 +204,6 @@ impl<'db> InferenceTable<'db> { }); InferenceTable { db, - interner, trait_env, tait_coercion_table: None, fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), @@ -245,15 +212,22 @@ impl<'db> InferenceTable<'db> { } } + #[inline] + pub(crate) fn interner(&self) -> DbInterner<'db> { + self.infer_ctxt.interner + } + + pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'db>) -> bool { + self.infer_ctxt.type_is_copy_modulo_regions(self.trait_env.env, ty) + } + 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, + PredicateKind::Clause(ClauseKind::Trait(data)) => data.def_id().0 == sized_did, _ => false, } }) @@ -309,28 +283,24 @@ impl<'db> InferenceTable<'db> { } } - fn type_matches_expected_vid( - &self, - expected_vid: TyVid, - ty: crate::next_solver::Ty<'db>, - ) -> bool { + fn type_matches_expected_vid(&self, expected_vid: TyVid, ty: Ty<'db>) -> bool { let ty = self.shallow_resolve(ty); match ty.kind() { - crate::next_solver::TyKind::Infer(rustc_type_ir::TyVar(found_vid)) => { + TyKind::Infer(rustc_type_ir::TyVar(found_vid)) => { self.infer_ctxt.root_var(expected_vid) == self.infer_ctxt.root_var(found_vid) } _ => false, } } - pub(super) fn set_diverging(&mut self, ty: crate::next_solver::Ty<'db>) { + pub(super) fn set_diverging(&mut self, ty: Ty<'db>) { self.diverging_type_vars.insert(ty); } pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> where - T: rustc_type_ir::TypeFoldable>, + T: TypeFoldable>, { // try to resolve obligations before canonicalizing, since this might // result in new knowledge about variables @@ -338,26 +308,11 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.canonicalize_response(t) } - /// 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. - pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T - where - 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 + pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: rustc_type_ir::TypeFoldable> + Clone, + T: TypeFoldable> + Clone, { let ty = self.resolve_vars_with_obligations(ty); self.infer_ctxt @@ -370,176 +325,130 @@ impl<'db> InferenceTable<'db> { /// the inference variables pub(crate) fn eagerly_normalize_and_resolve_shallow_in(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: TypeFoldable>, { - fn eagerly_resolve_ty( - table: &mut InferenceTable<'_>, - ty: Ty, - mut tys: SmallVec<[Ty; N]>, - ) -> Ty { - if tys.contains(&ty) { - return ty; - } - tys.push(ty.clone()); - - match ty.kind(Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - let ty = table.normalize_projection_ty(proj_ty.clone()); - eagerly_resolve_ty(table, ty, tys) - } - TyKind::InferenceVar(..) => { - let ty = table.resolve_ty_shallow(&ty); - eagerly_resolve_ty(table, ty, tys) - } - _ => ty, - } - } - - fold_tys_and_consts( - ty, - |e, _| match e { - Either::Left(ty) => { - Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new())) - } - 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: same as `normalize_associated_types_in` - 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, - ) - } - - pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { - 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<'db>, - ) -> crate::next_solver::Ty<'db> { - 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 { - 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 { - self.diverging_type_vars.insert(ty.to_nextsolver(self.interner)); - } - ty + let ty = self.resolve_vars_with_obligations(ty); + let ty = self.normalize_associated_types_in(ty); + self.resolve_vars_with_obligations(ty) } - pub(crate) fn new_type_var(&mut self) -> Ty { - self.new_var(TyVariableKind::General, false) + pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> { + self.infer_ctxt + .at(&ObligationCause::new(), self.trait_env.env) + .structurally_normalize_ty(alias, &mut self.fulfillment_cx) + .unwrap_or(alias) } - pub(crate) fn next_ty_var(&mut self) -> crate::next_solver::Ty<'db> { + pub(crate) fn next_ty_var(&mut self) -> Ty<'db> { self.infer_ctxt.next_ty_var() } - pub(crate) fn new_integer_var(&mut self) -> Ty { - self.new_var(TyVariableKind::Integer, false) + pub(crate) fn next_const_var(&mut self) -> Const<'db> { + self.infer_ctxt.next_const_var() } - pub(crate) fn new_float_var(&mut self) -> Ty { - self.new_var(TyVariableKind::Float, false) + pub(crate) fn next_int_var(&mut self) -> Ty<'db> { + self.infer_ctxt.next_int_var() } - pub(crate) fn new_maybe_never_var(&mut self) -> Ty { - self.new_var(TyVariableKind::General, true) + pub(crate) fn next_float_var(&mut self) -> Ty<'db> { + self.infer_ctxt.next_float_var() } - pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const { - let var = self.infer_ctxt.next_const_vid(); - let var = InferenceVar::from(var.as_u32()); - var.to_const(Interner, ty) + pub(crate) fn new_maybe_never_var(&mut self) -> Ty<'db> { + let var = self.next_ty_var(); + self.set_diverging(var); + var } - pub(crate) fn new_lifetime_var(&mut self) -> Lifetime { - let var = self.infer_ctxt.next_region_vid(); - let var = InferenceVar::from(var.as_u32()); - var.to_lifetime(Interner) + pub(crate) fn next_region_var(&mut self) -> Region<'db> { + self.infer_ctxt.next_region_var() } - pub(crate) fn next_region_var(&mut self) -> crate::next_solver::Region<'db> { - self.infer_ctxt.next_region_var() + pub(crate) fn next_var_for_param(&mut self, id: GenericParamId) -> GenericArg<'db> { + match id { + GenericParamId::TypeParamId(_) => self.next_ty_var().into(), + GenericParamId::ConstParamId(_) => self.next_const_var().into(), + GenericParamId::LifetimeParamId(_) => self.next_region_var().into(), + } } pub(crate) fn resolve_with_fallback( &mut self, t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, + fallback_ty: &mut dyn FnMut(DebruijnIndex, InferTy) -> Ty<'db>, + fallback_const: &mut dyn FnMut(DebruijnIndex, InferConst) -> Const<'db>, + fallback_region: &mut dyn FnMut(DebruijnIndex, RegionVid) -> Region<'db>, ) -> T where - T: HasInterner + TypeFoldable, + T: TypeFoldable>, { - self.resolve_with_fallback_inner(t, &fallback) - } + struct Resolver<'a, 'db> { + table: &'a mut InferenceTable<'db>, + binder: DebruijnIndex, + fallback_ty: &'a mut dyn FnMut(DebruijnIndex, InferTy) -> Ty<'db>, + fallback_const: &'a mut dyn FnMut(DebruijnIndex, InferConst) -> Const<'db>, + fallback_region: &'a mut dyn FnMut(DebruijnIndex, RegionVid) -> Region<'db>, + } + + impl<'db> TypeFolder> for Resolver<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.table.interner() + } - pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind]) -> Substitution { - 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) + fn fold_binder(&mut self, t: Binder<'db, T>) -> Binder<'db, T> + where + T: TypeFoldable>, + { + self.binder.shift_in(1); + let result = t.super_fold_with(self); + self.binder.shift_out(1); + result + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + if !t.has_infer() { + return t; } - chalk_ir::VariableKind::Lifetime => self.new_lifetime_var().cast(Interner), - chalk_ir::VariableKind::Const(ty) => self.new_const_var(ty.clone()).cast(Interner), - }), - ) - } - pub(crate) fn instantiate_canonical(&mut self, canonical: Canonical) -> T - where - T: HasInterner + TypeFoldable + std::fmt::Debug, - { - let subst = self.fresh_subst(canonical.binders.as_slice(Interner)); - subst.apply(canonical.value, Interner) + if let TyKind::Infer(infer) = t.kind() { + (self.fallback_ty)(self.binder, infer) + } else { + t.super_fold_with(self) + } + } + + fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { + if !c.has_infer() { + return c; + } + + if let ConstKind::Infer(infer) = c.kind() { + (self.fallback_const)(self.binder, infer) + } else { + c.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if let RegionKind::ReVar(infer) = r.kind() { + (self.fallback_region)(self.binder, infer) + } else { + r + } + } + } + + t.fold_with(&mut Resolver { + table: self, + binder: DebruijnIndex::ZERO, + fallback_ty, + fallback_const, + fallback_region, + }) } - pub(crate) fn instantiate_canonical_ns( + pub(crate) fn instantiate_canonical( &mut self, canonical: rustc_type_ir::Canonical, T>, ) -> T @@ -549,112 +458,35 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.instantiate_canonical(&canonical).0 } - fn resolve_with_fallback_inner( - &mut self, - t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, - ) -> T + pub(crate) fn resolve_completely(&mut self, value: T) -> T where - T: HasInterner + TypeFoldable, + T: TypeFoldable>, { - let var_stack = &mut vec![]; - t.fold_with( - &mut resolve::Resolver { table: self, var_stack, fallback }, - DebruijnIndex::INNERMOST, - ) - } - - pub(crate) fn resolve_completely(&mut self, t: T) -> T - where - T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, - U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, - { - let value = t.to_nextsolver(self.interner); let value = self.infer_ctxt.resolve_vars_if_possible(value); let mut goals = vec![]; - let value = value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals)); // FIXME(next-solver): Handle `goals`. - value.to_chalk(self.interner) + value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals)) } /// 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 { - let result = match self.try_unify(ty1, ty2) { - Ok(r) => r, - Err(_) => return false, - }; - 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>>( - &mut self, - ty1: &T, - ty2: &T, - ) -> bool { - let result = match self.try_unify(ty1, ty2) { - Ok(r) => r, - Err(_) => return false, - }; - result.goals.into_iter().all(|goal| { - matches!(next_trait_solve_in_ctxt(&self.infer_ctxt, goal), Ok((_, Certainty::Yes))) - }) + pub(crate) fn unify>(&mut self, ty1: T, ty2: T) -> bool { + self.try_unify(ty1, ty2).map(|infer_ok| self.register_infer_ok(infer_ok)).is_ok() } /// 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>>( - &mut self, - t1: &T, - t2: &T, - ) -> 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(self.trait_env.env, lhs, variance, rhs, span) { - Ok(goals) => Ok(crate::infer::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 { - self.shallow_resolve(ty.to_nextsolver(self.interner)).to_chalk(self.interner) + pub(crate) fn try_unify>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> { + self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq( + DefineOpaqueTypes::Yes, + t1, + t2, + ) } - pub(crate) fn shallow_resolve( - &self, - ty: crate::next_solver::Ty<'db>, - ) -> crate::next_solver::Ty<'db> { + pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { self.infer_ctxt.shallow_resolve(ty) } @@ -662,8 +494,6 @@ impl<'db> InferenceTable<'db> { where T: rustc_type_ir::TypeFoldable>, { - use rustc_type_ir::TypeVisitableExt; - if !t.has_non_region_infer() { return t; } @@ -678,26 +508,18 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.resolve_vars_if_possible(t) } - pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty { - if let TyKind::Alias(chalk_ir::AliasTy::Projection(..)) = 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) + /// Create a `GenericArgs` full of infer vars for `def`. + pub(crate) fn fresh_args_for_item(&self, def: SolverDefId) -> GenericArgs<'db> { + self.infer_ctxt.fresh_args_for_item(def) } - fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> { - self.infer_ctxt - .at(&ObligationCause::new(), self.trait_env.env) - .structurally_normalize_term(term, &mut self.fulfillment_cx) - .unwrap_or(term) + /// Like `fresh_args_for_item()`, but first uses the args from `first`. + pub(crate) fn fill_rest_fresh_args( + &self, + def_id: SolverDefId, + first: impl IntoIterator>, + ) -> GenericArgs<'db> { + self.infer_ctxt.fill_rest_fresh_args(def_id, first) } /// Try to resolve `ty` to a structural type, normalizing aliases. @@ -705,11 +527,8 @@ impl<'db> InferenceTable<'db> { /// 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() { + pub(crate) fn try_structurally_resolve_type(&mut self, ty: Ty<'db>) -> Ty<'db> { + if let 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. @@ -719,13 +538,18 @@ impl<'db> InferenceTable<'db> { .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), + Err(_errors) => Ty::new_error(self.interner(), ErrorGuaranteed), } } else { self.resolve_vars_with_obligations(ty) } } + pub(crate) fn structurally_resolve_type(&mut self, ty: Ty<'db>) -> Ty<'db> { + self.try_structurally_resolve_type(ty) + // FIXME: Err if it still contain infer vars. + } + pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> { let ctxt_snapshot = self.infer_ctxt.start_snapshot(); let obligations = self.fulfillment_cx.clone(); @@ -794,7 +618,7 @@ impl<'db> InferenceTable<'db> { self.fulfillment_cx.register_predicate_obligation( &self.infer_ctxt, Obligation::new( - self.interner, + self.interner(), ObligationCause::new(), goal.param_env, goal.predicate, @@ -810,21 +634,11 @@ impl<'db> InferenceTable<'db> { value } - pub(crate) fn register_obligations( - &mut self, - obligations: Vec>>, - ) { - obligations.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); - } - pub(crate) fn select_obligations_where_possible(&mut self) { self.fulfillment_cx.select_where_possible(&self.infer_ctxt); } - pub(super) fn register_predicate( - &mut self, - obligation: crate::next_solver::infer::traits::PredicateObligation<'db>, - ) { + pub(super) fn register_predicate(&mut self, obligation: PredicateObligation<'db>) { if obligation.has_escaping_bound_vars() { panic!("escaping bound vars in predicate {:?}", obligation); } @@ -834,7 +648,7 @@ impl<'db> InferenceTable<'db> { pub(super) fn register_predicates(&mut self, obligations: I) where - I: IntoIterator>, + I: IntoIterator>, { obligations.into_iter().for_each(|obligation| { self.register_predicate(obligation); @@ -843,16 +657,14 @@ impl<'db> InferenceTable<'db> { pub(crate) fn callable_sig( &mut self, - ty: &Ty, + ty: Ty<'db>, num_args: usize, - ) -> Option<(Option, Vec>, crate::next_solver::Ty<'db>)> - { - match ty.callable_sig(self.db) { - Some(sig) => Some(( - None, - sig.params().iter().map(|param| param.to_nextsolver(self.interner)).collect(), - sig.ret().to_nextsolver(self.interner), - )), + ) -> Option<(Option, Vec>, Ty<'db>)> { + match ty.callable_sig(self.interner()) { + Some(sig) => { + let sig = sig.skip_binder(); + Some((None, sig.inputs_and_output.inputs().to_vec(), sig.output())) + } None => { let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?; Some((Some(f), args_ty, return_ty)) @@ -862,9 +674,9 @@ impl<'db> InferenceTable<'db> { fn callable_sig_from_fn_trait( &mut self, - ty: &Ty, + ty: Ty<'db>, num_args: usize, - ) -> Option<(FnTrait, Vec>, next_solver::Ty<'db>)> { + ) -> Option<(FnTrait, Vec>, 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]), @@ -877,8 +689,8 @@ impl<'db> InferenceTable<'db> { trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = next_solver::Ty::new_tup_from_iter( - self.interner, + let arg_ty = Ty::new_tup_from_iter( + self.interner(), std::iter::repeat_with(|| { let ty = self.next_ty_var(); arg_tys.push(ty); @@ -886,24 +698,23 @@ impl<'db> InferenceTable<'db> { }) .take(num_args), ); - let args = [ty.to_nextsolver(self.interner), arg_ty]; - let trait_ref = crate::next_solver::TraitRef::new(self.interner, fn_trait.into(), args); + let args = [ty, arg_ty]; + let trait_ref = TraitRef::new(self.interner(), fn_trait.into(), args); - let projection = crate::next_solver::Ty::new_alias( - self.interner, + let projection = Ty::new_alias( + self.interner(), rustc_type_ir::AliasTyKind::Projection, - crate::next_solver::AliasTy::new(self.interner, output_assoc_type.into(), args), + AliasTy::new(self.interner(), output_assoc_type.into(), args), ); - let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + let pred = Predicate::upcast_from(trait_ref, self.interner()); if !self.try_obligation(pred).no_solution() { self.register_obligation(pred); let return_ty = self.normalize_alias_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; - let trait_ref = - crate::next_solver::TraitRef::new(self.interner, fn_x_trait.into(), args); - let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + let trait_ref = TraitRef::new(self.interner(), fn_x_trait.into(), args); + let pred = Predicate::upcast_from(trait_ref, self.interner()); if !self.try_obligation(pred).no_solution() { return Some((fn_x, arg_tys, return_ty)); } @@ -916,40 +727,53 @@ impl<'db> InferenceTable<'db> { pub(super) fn insert_type_vars(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: TypeFoldable>, { - fold_generic_args( - ty, - |arg, _| match arg { - GenericArgData::Ty(ty) => GenericArgData::Ty(self.insert_type_vars_shallow(ty)), - // FIXME: insert lifetime vars once LifetimeData::InferenceVar - // and specific error variant for lifetimes start being constructed - GenericArgData::Lifetime(lt) => GenericArgData::Lifetime(lt), - GenericArgData::Const(c) => { - GenericArgData::Const(self.insert_const_vars_shallow(c)) + struct Folder<'a, 'db> { + table: &'a mut InferenceTable<'db>, + } + impl<'db> TypeFolder> for Folder<'_, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.table.interner() + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + if !ty.references_error() { + return ty; } - }, - DebruijnIndex::INNERMOST, - ) - } - /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. - pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { - match ty.kind(Interner) { - TyKind::Error => self.new_type_var(), - TyKind::InferenceVar(..) => { - let ty_resolved = self.structurally_resolve_type(&ty); - if ty_resolved.is_unknown() { self.new_type_var() } else { ty } + if ty.is_ty_error() { self.table.next_ty_var() } else { ty.super_fold_with(self) } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + if !ct.references_error() { + return ct; + } + + if ct.is_ct_error() { + self.table.next_const_var() + } else { + ct.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if r.is_error() { self.table.next_region_var() } else { r } } - _ => ty, } + + ty.fold_with(&mut Folder { table: self }) + } + + /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. + pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty<'db>) -> Ty<'db> { + if ty.is_ty_error() { self.next_ty_var() } else { ty } } /// Whenever you lower a user-written type, you should call this. - pub(crate) fn process_user_written_ty(&mut self, ty: T) -> T + pub(crate) 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>, + T: TypeFoldable>, { self.process_remote_user_written_ty(ty) // FIXME: Register a well-formed obligation. @@ -957,10 +781,9 @@ impl<'db> InferenceTable<'db> { /// 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 + pub(crate) 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>, + T: 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: @@ -971,44 +794,33 @@ impl<'db> InferenceTable<'db> { } /// 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); - match &data.value { - ConstValue::Concrete(cc) => match &cc.interned { - crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()), - // try to evaluate unevaluated const. Replace with new var if const eval failed. - crate::ConstScalar::UnevaluatedConst(id, subst) => { - if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) { - eval - } else { - self.new_const_var(data.ty.clone()) - } - } - _ => c, - }, - _ => c, - } + pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { + if c.is_ct_error() { self.next_const_var() } else { c } } /// Check if given type is `Sized` or not - pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { - fn short_circuit_trivial_tys(ty: &Ty) -> Option { - match ty.kind(Interner) { - TyKind::Scalar(..) + pub(crate) fn is_sized(&mut self, ty: Ty<'db>) -> bool { + fn short_circuit_trivial_tys(ty: Ty<'_>) -> Option { + match ty.kind() { + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) | TyKind::Ref(..) - | TyKind::Raw(..) + | TyKind::RawPtr(..) | TyKind::Never | TyKind::FnDef(..) | TyKind::Array(..) - | TyKind::Function(..) => Some(true), - TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false), + | TyKind::FnPtr(..) => Some(true), + TyKind::Slice(..) | TyKind::Str | TyKind::Dynamic(..) => Some(false), _ => None, } } - let mut ty = ty.clone(); + let mut ty = ty; ty = self.eagerly_normalize_and_resolve_shallow_in(ty); - if let Some(sized) = short_circuit_trivial_tys(&ty) { + if let Some(sized) = short_circuit_trivial_tys(ty) { return sized; } @@ -1019,9 +831,8 @@ impl<'db> InferenceTable<'db> { while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { let struct_data = id.fields(self.db); if let Some((last_field, _)) = struct_data.fields().iter().next_back() { - let last_field_ty = self.db.field_types(id.into())[last_field] - .clone() - .substitute(Interner, subst); + let last_field_ty = self.db.field_types_ns(id.into())[last_field] + .instantiate(self.interner(), subst); if structs.contains(&ty) { // A struct recursively contains itself as a tail field somewhere. return true; // Don't overload the users with too many errors. @@ -1031,7 +842,7 @@ impl<'db> InferenceTable<'db> { // as unsized by the chalk, so we do this manually. ty = last_field_ty; ty = self.eagerly_normalize_and_resolve_shallow_in(ty); - if let Some(sized) = short_circuit_trivial_tys(&ty) { + if let Some(sized) = short_circuit_trivial_tys(ty) { return sized; } } else { @@ -1044,8 +855,8 @@ impl<'db> InferenceTable<'db> { return false; }; let sized_pred = Predicate::upcast_from( - TraitRef::new(self.interner, sized.into(), [ty.to_nextsolver(self.interner)]), - self.interner, + TraitRef::new(self.interner(), sized.into(), [ty]), + self.interner(), ); self.try_obligation(sized_pred).certain() } @@ -1060,189 +871,14 @@ impl fmt::Debug for InferenceTable<'_> { } } -mod resolve { - use super::InferenceTable; - use crate::{ - Const, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, - VariableKind, next_solver::mapping::NextSolverToChalk, - }; - use chalk_ir::fold::{TypeFoldable, TypeFolder}; - use rustc_type_ir::{FloatVid, IntVid, TyVid}; - - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub(super) enum VarKind { - Ty(TyVariableKind), - Const, - } - - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - pub(super) struct Resolver< - 'a, - 'b, - F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, - > { - pub(super) table: &'a mut InferenceTable<'b>, - pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>, - pub(super) fallback: F, - } - impl TypeFolder for Resolver<'_, '_, F> - where - F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_inference_ty( - &mut self, - var: InferenceVar, - kind: TyVariableKind, - outer_binder: DebruijnIndex, - ) -> Ty { - 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 - return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) - .assert_ty_ref(Interner) - .clone(); - } - if let Ok(known_ty) = self.table.infer_ctxt.probe_ty_var(vid) { - 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); - self.var_stack.pop(); - result - } else { - (self.fallback)(var, VariableKind::Ty(kind), 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 - return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) - .assert_ty_ref(Interner) - .clone(); - } - if let Some(known_ty) = self.table.infer_ctxt.resolve_int_var(vid) { - 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); - self.var_stack.pop(); - result - } else { - (self.fallback)(var, VariableKind::Ty(kind), 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 - return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) - .assert_ty_ref(Interner) - .clone(); - } - if let Some(known_ty) = self.table.infer_ctxt.resolve_float_var(vid) { - 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); - self.var_stack.pop(); - result - } else { - (self.fallback)(var, VariableKind::Ty(kind), outer_binder) - .assert_ty_ref(Interner) - .clone() - } - } - } - } - - fn fold_inference_const( - &mut self, - ty: Ty, - var: InferenceVar, - outer_binder: DebruijnIndex, - ) -> Const { - let vid = self - .table - .infer_ctxt - .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); - let var = InferenceVar::from(vid.as_u32()); - if self.var_stack.contains(&(var, VarKind::Const)) { - // recursive - return (self.fallback)(var, VariableKind::Const(ty), outer_binder) - .assert_const_ref(Interner) - .clone(); - } - if let Ok(known_const) = self.table.infer_ctxt.probe_const_var(vid) { - 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); - self.var_stack.pop(); - result - } else { - (self.fallback)(var, VariableKind::Const(ty), outer_binder) - .assert_const_ref(Interner) - .clone() - } - } - - fn fold_inference_lifetime( - &mut self, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Lifetime { - // fall back all lifetimes to 'error -- currently we don't deal - // with any lifetimes, but we can sometimes get some lifetime - // variables through Chalk's unification, and this at least makes - // sure we don't leak them outside of inference - crate::error_lifetime() - } - } -} - mod resolve_completely { - use rustc_type_ir::{ - DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable, - inherent::{Const as _, Ty as _}, - }; + use rustc_type_ir::{DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable}; - use crate::next_solver::Region; use crate::{ infer::unify::InferenceTable, next_solver::{ - Const, DbInterner, ErrorGuaranteed, Goal, Predicate, Term, Ty, - infer::traits::ObligationCause, + Const, DbInterner, Goal, Predicate, Region, Term, Ty, + infer::{resolve::ReplaceInferWithError, traits::ObligationCause}, normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }, }; @@ -1291,17 +927,17 @@ mod resolve_completely { value }; - value.fold_with(&mut ReplaceInferWithError { interner: self.ctx.interner }) + value.fold_with(&mut ReplaceInferWithError::new(self.ctx.interner())) } } impl<'cx, 'db> TypeFolder> for Resolver<'cx, 'db> { fn cx(&self) -> DbInterner<'db> { - self.ctx.interner + self.ctx.interner() } fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - if r.is_var() { Region::error(self.ctx.interner) } else { r } + if r.is_var() { Region::error(self.ctx.interner()) } else { r } } fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { @@ -1320,34 +956,4 @@ mod resolve_completely { predicate.super_fold_with(self) } } - - struct ReplaceInferWithError<'db> { - interner: DbInterner<'db>, - } - - impl<'db> TypeFolder> for ReplaceInferWithError<'db> { - fn cx(&self) -> DbInterner<'db> { - self.interner - } - - fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { - if t.is_infer() { - Ty::new_error(self.interner, ErrorGuaranteed) - } else { - t.super_fold_with(self) - } - } - - fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { - if c.is_ct_infer() { - Const::new_error(self.interner, ErrorGuaranteed) - } else { - c.super_fold_with(self) - } - } - - fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - if r.is_var() { Region::error(self.interner) } else { r } - } - } } 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 4071b9a1d5e9d..d97d2af080732 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -19,15 +19,13 @@ use rustc_type_ir::{ }; use triomphe::Arc; -use crate::utils::ClosureSubst; use crate::{ - Interner, TraitEnvironment, + TraitEnvironment, consteval_nextsolver::try_const_usize, db::HirDatabase, next_solver::{ DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, - mapping::{ChalkToNextSolver, convert_args_for_result}, }, }; @@ -325,19 +323,12 @@ pub fn layout_of_ty_query<'db>( TyKind::Closure(id, args) => { let def = db.lookup_intern_closure(id.0); let infer = db.infer(def.0); - let (captures, _) = infer.closure_info(&id.0.into()); + let (captures, _) = infer.closure_info(id.0); let fields = captures .iter() .map(|it| { - let ty = it - .ty - .clone() - .substitute( - Interner, - &ClosureSubst(&convert_args_for_result(interner, args.inner())) - .parent_subst(db), - ) - .to_nextsolver(interner); + let ty = + it.ty.instantiate(interner, args.split_closure_args_untupled().parent_args); db.layout_of_ty(ty, trait_env.clone()) }) .collect::, _>>()?; 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 6960e230a6850..d6f0ed3dc0752 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 @@ -3,7 +3,7 @@ use either::Either; use hir_def::db::DefDatabase; use project_model::{Sysroot, toolchain_info::QueryConfig}; use rustc_hash::FxHashMap; -use rustc_type_ir::inherent::{GenericArgs as _, Ty as _}; +use rustc_type_ir::inherent::GenericArgs as _; use syntax::ToSmolStr; use test_fixture::WithFixture; use triomphe::Arc; @@ -11,7 +11,7 @@ use triomphe::Arc; use crate::{ db::HirDatabase, layout::{Layout, LayoutError}, - next_solver::{AdtDef, DbInterner, GenericArgs, mapping::ChalkToNextSolver}, + next_solver::{DbInterner, GenericArgs}, setup_tracing, test_db::TestDB, }; @@ -84,7 +84,7 @@ fn eval_goal( let goal_ty = match adt_or_type_alias_id { Either::Left(adt_id) => crate::next_solver::Ty::new_adt( interner, - AdtDef::new(adt_id, interner), + adt_id, GenericArgs::identity_for_item(interner, adt_id.into()), ), Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(), @@ -133,11 +133,8 @@ fn eval_expr( .unwrap() .0; let infer = db.infer(function_id.into()); - let goal_ty = infer.type_of_binding[b].clone(); - 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())) - }) + let goal_ty = infer.type_of_binding[b]; + salsa::attach(&db, || db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))) } #[track_caller] 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 281cf6b2d4b32..2aa9b8fa192d0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -64,7 +64,6 @@ use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, }; -use either::Either; use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness}; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; @@ -233,7 +232,7 @@ impl ComplexMemoryMap<'_> { } impl<'db> MemoryMap<'db> { - pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError> { + pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError<'db>> { match self { MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), MemoryMap::Complex(cm) => cm.vtable.ty(id), @@ -249,8 +248,8 @@ impl<'db> MemoryMap<'db> { /// allocator function as `f` and it will return a mapping of old addresses to new addresses. fn transform_addresses( &self, - mut f: impl FnMut(&[u8], usize) -> Result, - ) -> Result, MirEvalError> { + mut f: impl FnMut(&[u8], usize) -> Result>, + ) -> Result, MirEvalError<'db>> { let mut transform = |(addr, val): (&usize, &[u8])| { let addr = *addr; let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; @@ -646,7 +645,7 @@ impl TypeFoldable for CallableSig { #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum ImplTraitId { - ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), + ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), // FIXME(next-solver): Should be crate::nextsolver::ImplTraitIdx. TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), } @@ -713,102 +712,6 @@ pub(crate) fn fold_free_vars + TypeFoldable< t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST) } -pub(crate) fn fold_tys + TypeFoldable>( - t: T, - mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty, - binders: DebruijnIndex, -) -> T { - fold_tys_and_consts( - t, - |x, d| match x { - Either::Left(x) => Either::Left(for_ty(x, d)), - Either::Right(x) => Either::Right(x), - }, - binders, - ) -} - -pub(crate) fn fold_tys_and_consts + TypeFoldable>( - t: T, - f: impl FnMut(Either, DebruijnIndex) -> Either, - binders: DebruijnIndex, -) -> T { - use chalk_ir::fold::{TypeFolder, TypeSuperFoldable}; - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct TyFolder, DebruijnIndex) -> Either>(F); - impl, DebruijnIndex) -> Either> TypeFolder - for TyFolder - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder); - self.0(Either::Left(ty), outer_binder).left().unwrap() - } - - fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const { - self.0(Either::Right(c), outer_binder).right().unwrap() - } - } - t.fold_with(&mut TyFolder(f), binders) -} - -pub(crate) fn fold_generic_args + TypeFoldable>( - t: T, - f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData, - binders: DebruijnIndex, -) -> T { - use chalk_ir::fold::{TypeFolder, TypeSuperFoldable}; - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct TyFolder GenericArgData>(F); - impl GenericArgData> TypeFolder - for TyFolder - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder); - self.0(GenericArgData::Ty(ty), outer_binder) - .intern(Interner) - .ty(Interner) - .unwrap() - .clone() - } - - fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const { - self.0(GenericArgData::Const(c), outer_binder) - .intern(Interner) - .constant(Interner) - .unwrap() - .clone() - } - - fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime { - let lt = lt.super_fold_with(self.as_dyn(), outer_binder); - self.0(GenericArgData::Lifetime(lt), outer_binder) - .intern(Interner) - .lifetime(Interner) - .unwrap() - .clone() - } - } - t.fold_with(&mut TyFolder(f), binders) -} - /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also /// ensures there are no unbound variables or inference variables anywhere in /// the `t`. @@ -942,31 +845,31 @@ pub fn callable_sig_from_fn_trait<'db>( // - Self: FnOnce // - >::Output == ?ret_ty let args_ty = table.next_ty_var(); - let args = [self_ty.to_nextsolver(table.interner), args_ty]; - let trait_ref = crate::next_solver::TraitRef::new(table.interner, fn_once_trait.into(), args); + let args = [self_ty.to_nextsolver(table.interner()), args_ty]; + let trait_ref = crate::next_solver::TraitRef::new(table.interner(), fn_once_trait.into(), args); let projection = crate::next_solver::Ty::new_alias( - table.interner, + table.interner(), rustc_type_ir::AliasTyKind::Projection, - crate::next_solver::AliasTy::new(table.interner, output_assoc_type.into(), args), + crate::next_solver::AliasTy::new(table.interner(), output_assoc_type.into(), args), ); - let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner); + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner()); if !table.try_obligation(pred).no_solution() { table.register_obligation(pred); let return_ty = table.normalize_alias_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; let trait_ref = - crate::next_solver::TraitRef::new(table.interner, fn_x_trait.into(), args); + crate::next_solver::TraitRef::new(table.interner(), fn_x_trait.into(), args); if !table .try_obligation(crate::next_solver::Predicate::upcast_from( trait_ref, - table.interner, + table.interner(), )) .no_solution() { - let ret_ty = table.resolve_completely(return_ty.to_chalk(table.interner)); - let args_ty = table.resolve_completely(args_ty.to_chalk(table.interner)); + let ret_ty = table.resolve_completely(return_ty).to_chalk(table.interner()); + let args_ty = table.resolve_completely(args_ty).to_chalk(table.interner()); let params = args_ty .as_tuple()? .iter(Interner) 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 0c197b27034bf..a9b523a4a6edf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -25,14 +25,14 @@ use chalk_ir::{ use either::Either; use hir_def::{ AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, - TypeOrConstParamId, UnionId, VariantId, + GenericParamId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, + UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, lang_item::LangItem, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, - signatures::{FunctionSignature, TraitFlags}, + signatures::TraitFlags, type_ref::{ ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, @@ -124,26 +124,6 @@ pub enum LifetimeElisionKind { } impl LifetimeElisionKind { - #[inline] - pub(crate) fn for_const(const_parent: ItemContainerId) -> LifetimeElisionKind { - match const_parent { - ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => { - LifetimeElisionKind::Elided(static_lifetime()) - } - ItemContainerId::ImplId(_) => { - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true } - } - ItemContainerId::TraitId(_) => { - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false } - } - } - } - - #[inline] - pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind { - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() } - } - #[inline] pub(crate) fn for_fn_ret() -> LifetimeElisionKind { // FIXME: We should use the elided lifetime here, or `ElisionFailure`. @@ -268,7 +248,7 @@ pub enum ParamLoweringMode { Variable, } -impl<'a> TyLoweringContext<'a> { +impl<'db> TyLoweringContext<'db> { pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty { self.lower_ty_ext(type_ref).0 } @@ -512,7 +492,7 @@ impl<'a> TyLoweringContext<'a> { } #[inline] - fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static> { + fn on_path_diagnostic_callback<'a>(type_ref: TypeRefId) -> PathDiagnosticCallback<'a, 'db> { PathDiagnosticCallback { data: Either::Left(PathDiagnosticCallbackData(type_ref)), callback: |data, this, diag| { @@ -523,7 +503,7 @@ impl<'a> TyLoweringContext<'a> { } #[inline] - fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a> { + fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'db> { PathLoweringContext::new( self, Self::on_path_diagnostic_callback(path_id.type_ref()), @@ -559,7 +539,7 @@ impl<'a> TyLoweringContext<'a> { &mut self, path_id: PathId, explicit_self_ty: Ty, - ) -> Option<(TraitRef, PathLoweringContext<'_, 'a>)> { + ) -> Option<(TraitRef, PathLoweringContext<'_, '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. @@ -576,7 +556,7 @@ impl<'a> TyLoweringContext<'a> { &'b mut self, where_predicate: &'b WherePredicate, ignore_bindings: bool, - ) -> impl Iterator + use<'a, 'b> { + ) -> impl Iterator + use<'db, 'b> { match where_predicate { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { @@ -598,7 +578,7 @@ impl<'a> TyLoweringContext<'a> { bound: &'b TypeBound, self_ty: Ty, ignore_bindings: bool, - ) -> impl Iterator + use<'b, 'a> { + ) -> impl Iterator + use<'b, 'db> { let mut assoc_bounds = None; let mut clause = None; match bound { 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 da9dd21183e8f..cdac1c9829810 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 @@ -3,15 +3,15 @@ use chalk_ir::{BoundVar, cast::Cast, fold::Shift}; use either::Either; use hir_def::{ - GenericDefId, GenericParamId, Lookup, TraitId, + GenericDefId, GenericParamId, TraitId, expr_store::{ - ExpressionStore, HygieneId, + ExpressionStore, path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments}, }, hir::generics::{ GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, }, - resolver::{ResolveValueResult, TypeNs, ValueNs}, + resolver::TypeNs, signatures::TraitFlags, type_ref::{TypeRef, TypeRefId}, }; @@ -22,7 +22,7 @@ use crate::{ AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, IncorrectGenericsLenKind, Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, - TyLoweringContext, ValueTyDefId, WhereClause, + TyLoweringContext, WhereClause, consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, @@ -36,21 +36,22 @@ use crate::{ utils::associated_type_by_name_including_super_traits, }; -type CallbackData<'a> = Either< +type CallbackData<'a, 'db> = Either< super::PathDiagnosticCallbackData, - crate::infer::diagnostics::PathDiagnosticCallbackData<'a>, + crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>, >; // 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> { - pub(crate) data: CallbackData<'a>, - pub(crate) callback: fn(&CallbackData<'_>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic), +pub(crate) struct PathDiagnosticCallback<'a, 'db> { + pub(crate) data: CallbackData<'a, 'db>, + pub(crate) callback: + fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic), } pub(crate) struct PathLoweringContext<'a, 'b> { ctx: &'a mut TyLoweringContext<'b>, - on_diagnostic: PathDiagnosticCallback<'a>, + on_diagnostic: PathDiagnosticCallback<'a, 'b>, path: &'a Path, segments: PathSegments<'a>, current_segment_idx: usize, @@ -62,7 +63,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { #[inline] pub(crate) fn new( ctx: &'a mut TyLoweringContext<'b>, - on_diagnostic: PathDiagnosticCallback<'a>, + on_diagnostic: PathDiagnosticCallback<'a, 'b>, path: &'a Path, ) -> Self { let segments = path.segments(); @@ -109,20 +110,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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, @@ -390,103 +377,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 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(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const) - } - ValueNs::StaticId(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static) - } - ValueNs::LocalBinding(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable) - } - ValueNs::FunctionId(_) - | ValueNs::StructId(_) - | ValueNs::EnumVariantId(_) - | ValueNs::ConstId(_) => {} - } - } - ResolveValueResult::Partial(resolution, _, _) => { - self.handle_type_ns_resolution(resolution); - } - }; - Some(res) - } - fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty { let Some(res) = res else { return TyKind::Error.intern(Interner); @@ -556,62 +446,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner) } - /// 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, - ) -> Substitution { - 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 Substitution::empty(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, 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 84cd216b81218..98881004bb9a1 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::hir::generics::GenericParamDataRef; use hir_def::item_tree::FieldsShape; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, @@ -35,9 +36,9 @@ use hir_def::{ TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; -use hir_def::{ConstId, StaticId}; +use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId}; use hir_expand::name::Name; -use intern::sym; +use intern::{Symbol, sym}; use la_arena::{Arena, ArenaMap, Idx}; use path::{PathDiagnosticCallback, PathLoweringContext, builtin}; use rustc_ast_ir::Mutability; @@ -50,12 +51,14 @@ use rustc_type_ir::{ TypeVisitableExt, inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, }; +use rustc_type_ir::{TypeFoldable, TypeFolder, Upcast}; use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; use crate::ValueTyDefId; +use crate::next_solver::ParamConst; use crate::{ FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, @@ -79,11 +82,11 @@ pub struct ImplTraits<'db> { } #[derive(PartialEq, Eq, Debug, Hash)] -pub(crate) struct ImplTrait<'db> { +pub struct ImplTrait<'db> { pub(crate) predicates: Vec>, } -pub(crate) type ImplTraitIdx<'db> = Idx>; +pub type ImplTraitIdx<'db> = Idx>; #[derive(Debug, Default)] struct ImplTraitLoweringState<'db> { @@ -184,6 +187,8 @@ pub(crate) struct TyLoweringContext<'db, 'a> { pub(crate) unsized_types: FxHashSet>, pub(crate) diagnostics: Vec, lifetime_elision: LifetimeElisionKind<'db>, + /// We disallow referencing generic parameters that have an index greater than or equal to this number. + disallow_params_after: u32, } impl<'db, 'a> TyLoweringContext<'db, 'a> { @@ -208,6 +213,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { unsized_types: FxHashSet::default(), diagnostics: Vec::new(), lifetime_elision, + disallow_params_after: u32::MAX, } } @@ -243,6 +249,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self } + pub(crate) fn disallow_params_after(&mut self, after: u32) { + self.disallow_params_after = after; + } + pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); } @@ -265,7 +275,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.lower_ty_ext(type_ref).0 } - pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty<'db>) -> Const<'db> { + 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) => { @@ -323,6 +333,33 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.generics.get_or_init(|| generics(self.db, self.def)) } + fn type_param(&mut self, id: TypeParamId, index: u32, name: Symbol) -> Ty<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Ty::new_error(self.interner, ErrorGuaranteed) + } else { + Ty::new_param(self.interner, id, index, name) + } + } + + fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Const::error(self.interner) + } else { + Const::new_param(self.interner, ParamConst { id, index }) + } + } + + fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Region::error(self.interner) + } else { + Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + } + } + #[tracing::instrument(skip(self), ret)] pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { let interner = self.interner; @@ -351,8 +388,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TypeOrConstParamData::TypeParamData(ty) => ty, _ => unreachable!(), }; - Ty::new_param( - self.interner, + self.type_param( type_param_id, idx as u32, type_data @@ -367,7 +403,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } TypeRef::Array(array) => { let inner_ty = self.lower_ty(array.ty); - let const_len = self.lower_const(&array.len, Ty::new_usize(interner)); + 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) => { @@ -491,7 +527,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } #[inline] - fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static, 'db> { + fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> { PathDiagnosticCallback { data: Either::Left(PathDiagnosticCallbackData(type_ref)), callback: |data, this, diag| { @@ -515,7 +551,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { 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); + return ctx.lower_ty_relative_path(ty, res, false); } let mut ctx = self.at_path(path_id); @@ -545,7 +581,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TypeNs::TraitId(tr) => tr, _ => return None, }; - Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty), ctx)) + Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx)) } fn lower_trait_ref( @@ -869,7 +905,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ImplTrait { predicates } } - pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Region<'db> { + pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { LifetimeNs::Static => Region::new_static(self.interner), @@ -878,10 +914,7 @@ 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, id }, - ) + self.region_param(id, idx as u32) } }, None => Region::error(self.interner), @@ -983,7 +1016,7 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind TyDefId::BuiltinType(it) => EarlyBinder::bind(builtin(interner, it)), TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( interner, - AdtDef::new(it, interner), + it, GenericArgs::identity_for_item(interner, it.into()), )), TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, @@ -1748,6 +1781,113 @@ pub(crate) fn lower_generic_arg<'a, 'db, T>( } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericDefaults<'db>( + Option>>]>>, +); + +impl<'db> GenericDefaults<'db> { + #[inline] + pub fn get(&self, idx: usize) -> Option>> { + self.0.as_ref()?[idx] + } +} + +pub(crate) fn generic_defaults_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> GenericDefaults<'_> { + db.generic_defaults_ns_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + let generic_params = generics(db, def); + if generic_params.is_empty() { + return (GenericDefaults(None), None); + } + let resolver = def.resolver(db); + + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generic_params.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); + let mut idx = 0; + let mut has_any_default = false; + let mut defaults = generic_params + .iter_parents_with_store() + .map(|((id, p), store)| { + ctx.store = store; + let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); + has_any_default |= has_default; + idx += 1; + result + }) + .collect::>(); + ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + defaults.extend(generic_params.iter_self().map(|(id, p)| { + let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); + has_any_default |= has_default; + idx += 1; + result + })); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + let defaults = if has_any_default { + GenericDefaults(Some(Arc::from_iter(defaults))) + } else { + GenericDefaults(None) + }; + return (defaults, diagnostics); + + fn handle_generic_param<'db>( + ctx: &mut TyLoweringContext<'db, '_>, + idx: usize, + id: GenericParamId, + p: GenericParamDataRef<'_>, + generic_params: &Generics, + ) -> (Option>>, bool) { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden. + ctx.disallow_params_after(idx as u32); + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.map(|ty| ctx.lower_ty(ty)); + (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some()) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; + + let mut val = p.default.map(|c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.into() + }); + (val.map(EarlyBinder::bind), p.default.is_some()) + } + GenericParamDataRef::LifetimeParamData(_) => (None, false), + } + } +} + +pub(crate) fn generic_defaults_with_diagnostics_cycle_result( + _db: &dyn HirDatabase, + _def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + (GenericDefaults(None), None) +} + /// Build the signature of a callable item (function, struct or enum variant). pub(crate) fn callable_item_signature_query<'db>( db: &'db dyn HirDatabase, @@ -1804,7 +1944,7 @@ fn fn_sig_for_fn<'db>( 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); + let ty = Ty::new_adt(interner, adt, args); EarlyBinder::bind(ty) } 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 0a9f34c9dabd6..babc39694ff1c 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 @@ -51,15 +51,17 @@ use super::{ const_param_ty_query, ty_query, }; -type CallbackData<'a> = - Either>; +type CallbackData<'a, 'db> = Either< + PathDiagnosticCallbackData, + crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>, +>; // 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) data: CallbackData<'a, 'db>, pub(crate) callback: - fn(&CallbackData<'_>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic), + fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic), } pub(crate) struct PathLoweringContext<'a, 'b, 'db> { @@ -155,13 +157,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ty: Ty<'db>, // We need the original resolution to lower `Self::AssocTy` correctly res: Option, + infer_args: bool, ) -> (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) + (self.select_associated_type(res, infer_args), None) } _ => { // FIXME report error (ambiguous associated type) @@ -204,6 +207,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let trait_ref = self.lower_trait_ref_from_resolved_path( trait_, Ty::new_error(self.ctx.interner, ErrorGuaranteed), + false, ); tracing::debug!(?trait_ref); self.skip_resolved_segment(); @@ -276,8 +280,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { GenericParamDataRef::TypeParamData(p) => p, _ => unreachable!(), }; - Ty::new_param( - self.ctx.interner, + self.ctx.type_param( param_id, idx as u32, p.name @@ -293,7 +296,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { self.ctx.interner, adt.into(), ); - Ty::new_adt(self.ctx.interner, AdtDef::new(adt, self.ctx.interner), args) + Ty::new_adt(self.ctx.interner, adt, args) } TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args), @@ -308,7 +311,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { tracing::debug!(?ty); self.skip_resolved_segment(); - self.lower_ty_relative_path(ty, Some(resolution)) + self.lower_ty_relative_path(ty, Some(resolution), infer_args) } fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) { @@ -480,14 +483,19 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { // 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(_) => { + ValueNs::GenericParam(_) => { prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const) } ValueNs::StaticId(_) => { prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static) } - ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => {} - ValueNs::LocalBinding(_) => {} + ValueNs::LocalBinding(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable) + } + ValueNs::FunctionId(_) + | ValueNs::StructId(_) + | ValueNs::EnumVariantId(_) + | ValueNs::ConstId(_) => {} } } ResolveValueResult::Partial(resolution, _, _) => { @@ -498,7 +506,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { } #[tracing::instrument(skip(self), ret)] - fn select_associated_type(&mut self, res: Option) -> Ty<'db> { + fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty<'db> { let interner = self.ctx.interner; let Some(res) = res else { return Ty::new_error(self.ctx.interner, ErrorGuaranteed); @@ -516,7 +524,8 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { // 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 = + self.substs_from_path_segment(associated_ty.into(), infer_args, None, true); let substs = crate::next_solver::GenericArgs::new_from_iter( interner, @@ -715,12 +724,12 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { param: GenericParamDataRef<'_>, arg: &GenericArg, ) -> crate::next_solver::GenericArg<'db> { - match (param, arg) { + match (param, *arg) { (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { - self.ctx.ctx.lower_lifetime(*lifetime).into() + self.ctx.ctx.lower_lifetime(lifetime).into() } (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { - self.ctx.ctx.lower_ty(*type_ref).into() + self.ctx.ctx.lower_ty(type_ref).into() } (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { let GenericParamId::ConstParamId(const_id) = param_id else { @@ -859,8 +868,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { &mut self, resolved: TraitId, explicit_self_ty: Ty<'db>, + infer_args: bool, ) -> TraitRef<'db> { - let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty); + let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args); TraitRef::new_from_args(self.ctx.interner, resolved.into(), args) } @@ -868,8 +878,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { &mut self, resolved: TraitId, explicit_self_ty: Ty<'db>, + infer_args: bool, ) -> crate::next_solver::GenericArgs<'db> { - self.substs_from_path_segment(resolved.into(), false, Some(explicit_self_ty), false) + self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false) } pub(super) fn assoc_type_bindings_from_type_bound<'c>( @@ -1039,8 +1050,12 @@ fn check_generic_args_len<'db>( } 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. + if provided_lifetimes_count == 0 + && lifetime_args_len > 0 + && (!lowering_assoc_type_generics || infer_args) + { + // In generic associated types, we never allow inferring the lifetimes, but only in type context, that is + // when `infer_args == false`. In expression/pattern context we always allow inferring them, even for GATs. match lifetime_elision { &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => { ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path); 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 61d3091a0c1d0..086abc95917ef 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 @@ -8,39 +8,42 @@ use arrayvec::ArrayVec; use base_db::Crate; use chalk_ir::{UniverseIndex, WithKind, cast::Cast}; use hir_def::{ - AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, - ModuleId, TraitId, + AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, + ModuleId, TraitId, TypeAliasId, nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map}, signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags}, }; use hir_expand::name::Name; use intern::sym; +use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _}; +use rustc_type_ir::{ + FloatTy, IntTy, UintTy, + inherent::{ + AdtDef, BoundExistentialPredicates, GenericArgs as _, 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, VariableKind, WhereClause, + CanonicalVarKinds, DebruijnIndex, GenericArgData, InEnvironment, Interner, TraitEnvironment, + TyBuilder, VariableKind, 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, DbInterner, SolverDefId, + Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId, + TraitRef, Ty, TyKind, infer::{ DefineOpaqueTypes, traits::{ObligationCause, PredicateObligation}, }, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + mapping::NextSolverToChalk, obligation_ctxt::ObligationCtxt, }, - primitive::{FloatTy, IntTy, UintTy}, - to_chalk_trait_id, traits::next_trait_solve_canonical_in_ctxt, utils::all_super_traits, }; @@ -55,11 +58,15 @@ pub enum TyFingerprint { Never, Ref(Mutability), RawPtr(Mutability), - Scalar(Scalar), + Bool, + Char, + Int(IntTy), + Uint(UintTy), + Float(FloatTy), // These can have user-defined impls: Adt(hir_def::AdtId), Dyn(TraitId), - ForeignType(ForeignDefId), + ForeignType(TypeAliasId), // These only exist for trait impls Unit, Unnameable, @@ -71,140 +78,73 @@ impl TyFingerprint { /// types can have inherent impls: if we have some `struct S`, we can have /// an `impl S`, but not `impl &S`. Hence, this will return `None` for /// reference types and such. - pub fn for_inherent_impl(ty: &Ty) -> Option { - let fp = match ty.kind(Interner) { + pub fn for_inherent_impl<'db>(ty: Ty<'db>) -> Option { + let fp = match ty.kind() { TyKind::Str => TyFingerprint::Str, TyKind::Never => TyFingerprint::Never, TyKind::Slice(..) => TyFingerprint::Slice, TyKind::Array(..) => TyFingerprint::Array, - TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), - TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), - TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), - TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), - TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, + TyKind::Bool => TyFingerprint::Bool, + TyKind::Char => TyFingerprint::Char, + TyKind::Int(int) => TyFingerprint::Int(int), + TyKind::Uint(int) => TyFingerprint::Uint(int), + TyKind::Float(float) => TyFingerprint::Float(float), + TyKind::Adt(adt_def, _) => TyFingerprint::Adt(adt_def.def_id().0), + TyKind::RawPtr(_, mutability) => TyFingerprint::RawPtr(mutability), + TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(alias_id.0), + TyKind::Dynamic(bounds, _) => { + bounds.principal_def_id().map(|trait_| TyFingerprint::Dyn(trait_.0))? + } _ => return None, }; Some(fp) } /// Creates a TyFingerprint for looking up a trait impl. - pub fn for_trait_impl(ty: &Ty) -> Option { - let fp = match ty.kind(Interner) { + pub fn for_trait_impl<'db>(ty: Ty<'db>) -> Option { + let fp = match ty.kind() { TyKind::Str => TyFingerprint::Str, TyKind::Never => TyFingerprint::Never, TyKind::Slice(..) => TyFingerprint::Slice, TyKind::Array(..) => TyFingerprint::Array, - TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), - TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), - TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), - TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), - TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, - TyKind::Ref(mutability, _, _) => TyFingerprint::Ref(*mutability), - TyKind::Tuple(_, subst) => { - let first_ty = subst.interned().first().map(|arg| arg.assert_ty_ref(Interner)); + TyKind::Bool => TyFingerprint::Bool, + TyKind::Char => TyFingerprint::Char, + TyKind::Int(int) => TyFingerprint::Int(int), + TyKind::Uint(int) => TyFingerprint::Uint(int), + TyKind::Float(float) => TyFingerprint::Float(float), + TyKind::Adt(adt_def, _) => TyFingerprint::Adt(adt_def.def_id().0), + TyKind::RawPtr(_, mutability) => TyFingerprint::RawPtr(mutability), + TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(alias_id.0), + TyKind::Dynamic(bounds, _) => { + bounds.principal_def_id().map(|trait_| TyFingerprint::Dyn(trait_.0))? + } + TyKind::Ref(_, _, mutability) => TyFingerprint::Ref(mutability), + TyKind::Tuple(subst) => { + let first_ty = subst.as_slice().first(); match first_ty { - Some(ty) => return TyFingerprint::for_trait_impl(ty), + Some(ty) => return TyFingerprint::for_trait_impl(*ty), None => TyFingerprint::Unit, } } - 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(..) | TyKind::FnDef(_, _) | TyKind::Closure(_, _) | TyKind::Coroutine(..) + | TyKind::CoroutineClosure(..) | TyKind::CoroutineWitness(..) => TyFingerprint::Unnameable, - TyKind::Function(fn_ptr) => { - TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32) - } - TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) - | TyKind::Error => return None, - }; - Some(fp) - } - - /// Creates a TyFingerprint for looking up a trait impl. - 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, - 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) => TyFingerprint::ForeignType(crate::to_foreign_def_id(def.0)), - 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()?; - TyFingerprint::Dyn(trait_ref.0) - } - 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) + TyFingerprint::Function(sig.skip_binder().inputs_and_output.inner().len() as u32) } - TyKind::Alias(..) - | TyKind::Placeholder(_) + TyKind::Param(_) | TyKind::Bound(..) + | TyKind::Placeholder(..) | TyKind::Infer(_) | TyKind::Error(_) - | TyKind::Param(..) + | TyKind::Pat(..) | TyKind::UnsafeBinder(..) => return None, }; Some(fp) @@ -212,25 +152,25 @@ impl TyFingerprint { } pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ - TyFingerprint::Scalar(Scalar::Int(IntTy::I8)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I16)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I32)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I64)), - TyFingerprint::Scalar(Scalar::Int(IntTy::I128)), - TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)), - TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)), + TyFingerprint::Int(IntTy::I8), + TyFingerprint::Int(IntTy::I16), + TyFingerprint::Int(IntTy::I32), + TyFingerprint::Int(IntTy::I64), + TyFingerprint::Int(IntTy::I128), + TyFingerprint::Int(IntTy::Isize), + TyFingerprint::Uint(UintTy::U8), + TyFingerprint::Uint(UintTy::U16), + TyFingerprint::Uint(UintTy::U32), + TyFingerprint::Uint(UintTy::U64), + TyFingerprint::Uint(UintTy::U128), + TyFingerprint::Uint(UintTy::Usize), ]; pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 4] = [ - TyFingerprint::Scalar(Scalar::Float(FloatTy::F16)), - TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)), - TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), - TyFingerprint::Scalar(Scalar::Float(FloatTy::F128)), + TyFingerprint::Float(FloatTy::F16), + TyFingerprint::Float(FloatTy::F32), + TyFingerprint::Float(FloatTy::F64), + TyFingerprint::Float(FloatTy::F128), ]; type TraitFpMap = FxHashMap, Box<[ImplId]>>>; @@ -300,9 +240,8 @@ impl TraitImpls { Some(tr) => tr.skip_binder().def_id.0, None => continue, }; - let interner = DbInterner::new_with(db, None, None); - let self_ty = db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner); - let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty); + let self_ty = db.impl_self_ty(impl_id); + let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.instantiate_identity()); map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id); } @@ -415,8 +354,8 @@ impl InherentImpls { continue; } - let interner = DbInterner::new_with(db, None, None); - let self_ty = &db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner); + let self_ty = db.impl_self_ty(impl_id); + let self_ty = self_ty.instantiate_identity(); match is_inherent_impl_coherent(db, def_map, impl_id, self_ty) { true => { @@ -440,7 +379,7 @@ impl InherentImpls { } } - pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { + pub fn for_self_ty<'db>(&self, self_ty: Ty<'db>) -> &[ImplId] { match TyFingerprint::for_inherent_impl(self_ty) { Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), None => &[], @@ -476,9 +415,14 @@ pub(crate) fn incoherent_inherent_impl_crates( res } -pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option> { - match ty.kind(Interner) { - &TyKind::Adt(AdtId(def_id), _) => { +pub fn def_crates<'db>( + db: &'db dyn HirDatabase, + ty: Ty<'db>, + cur_crate: Crate, +) -> Option> { + match ty.kind() { + TyKind::Adt(adt_def, _) => { + let def_id = adt_def.def_id().0; let rustc_has_incoherent_inherent_impls = match def_id { hir_def::AdtId::StructId(id) => db .struct_signature(id) @@ -499,22 +443,22 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option { - let alias = from_foreign_def_id(id); + TyKind::Foreign(alias) => { + let alias = alias.0; Some( if db .type_alias_signature(alias) .flags .contains(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL) { - db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(id)) + db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(alias)) } else { smallvec![alias.module(db).krate()] }, ) } - TyKind::Dyn(_) => { - let trait_id = ty.dyn_trait()?; + TyKind::Dynamic(bounds, _) => { + let trait_id = bounds.principal_def_id()?.0; Some( if db .trait_signature(trait_id) @@ -530,11 +474,15 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option Some(db.incoherent_inherent_impl_crates( + | TyKind::RawPtr(..) => Some(db.incoherent_inherent_impl_crates( cur_crate, TyFingerprint::for_inherent_impl(ty).expect("fingerprint for primitive"), )), @@ -545,7 +493,7 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option( db: &'db dyn HirDatabase, - ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &Canonical<'db, Ty<'db>>, env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, @@ -626,23 +574,23 @@ pub struct ReceiverAdjustments { } impl ReceiverAdjustments { - pub(crate) fn apply( + pub(crate) fn apply<'db>( &self, - table: &mut InferenceTable<'_>, - mut ty: Ty, - ) -> (Ty, Vec) { + table: &mut InferenceTable<'db>, + mut ty: Ty<'db>, + ) -> (Ty<'db>, Vec>) { let mut adjust = Vec::new(); - let mut autoderef = table.autoderef(ty.to_nextsolver(table.interner)); + let mut autoderef = table.autoderef(ty); autoderef.next(); for _ in 0..self.autoderefs { match autoderef.next() { None => { never!("autoderef not possible for {:?}", ty); - ty = TyKind::Error.intern(Interner); + ty = Ty::new_error(table.interner(), ErrorGuaranteed); break; } Some((new_ty, _)) => { - ty = new_ty.to_chalk(autoderef.table.interner); + ty = new_ty; let mutbl = match self.autoref { Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m), Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not), @@ -654,26 +602,26 @@ impl ReceiverAdjustments { AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)), AutoderefKind::Builtin => None, }), - target: ty.clone(), + target: ty, }); } } } if let Some(autoref) = &self.autoref { - let lt = table.new_lifetime_var(); + let lt = table.next_region_var(); match autoref { AutorefOrPtrAdjustment::Autoref(m) => { - let a = Adjustment::borrow(*m, ty, lt); - ty = a.target.clone(); + let a = Adjustment::borrow(table.interner(), *m, ty, lt); + ty = a.target; adjust.push(a); } AutorefOrPtrAdjustment::ToConstPtr => { - if let TyKind::Raw(Mutability::Mut, pointee) = ty.kind(Interner) { + if let TyKind::RawPtr(pointee, Mutability::Mut) = ty.kind() { let a = Adjustment { kind: Adjust::Pointer(PointerCast::MutToConstPointer), - target: TyKind::Raw(Mutability::Not, pointee.clone()).intern(Interner), + target: Ty::new_ptr(table.interner(), pointee, Mutability::Not), }; - ty = a.target.clone(); + ty = a.target; adjust.push(a); } else { never!("`ToConstPtr` target is not a raw mutable pointer"); @@ -683,23 +631,20 @@ impl ReceiverAdjustments { } if self.unsize_array { ty = 'it: { - if let TyKind::Ref(m, l, inner) = ty.kind(Interner) - && let TyKind::Array(inner, _) = inner.kind(Interner) + if let TyKind::Ref(l, inner, m) = ty.kind() + && let TyKind::Array(inner, _) = inner.kind() { - break 'it TyKind::Ref( - *m, - l.clone(), - TyKind::Slice(inner.clone()).intern(Interner), - ) - .intern(Interner); + break 'it Ty::new_ref( + table.interner(), + l, + Ty::new_slice(table.interner(), inner), + m, + ); } // FIXME: report diagnostic if array unsizing happens without indirection. ty }; - adjust.push(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), - target: ty.clone(), - }); + adjust.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: ty }); } (ty, adjust) } @@ -713,7 +658,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: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &Canonical<'db, Ty<'db>>, db: &'db dyn HirDatabase, env: Arc>, traits_in_scope: &FxHashSet, @@ -744,17 +689,18 @@ pub(crate) fn iterate_method_candidates<'db, T>( } pub fn lookup_impl_const<'db>( - db: &'db dyn HirDatabase, + interner: DbInterner<'db>, env: Arc>, const_id: ConstId, - subs: Substitution, -) -> (ConstId, Substitution) { + subs: GenericArgs<'db>, +) -> (ConstId, GenericArgs<'db>) { + let db = interner.db; + let trait_id = match const_id.lookup(db).container { ItemContainerId::TraitId(id) => id, _ => return (const_id, subs), }; - let substitution = Substitution::from_iter(Interner, subs.iter(Interner)); - let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }; + let trait_ref = TraitRef::new(interner, trait_id.into(), subs); let const_signature = db.const_signature(const_id); let name = match const_signature.name.as_ref() { @@ -772,37 +718,30 @@ pub fn lookup_impl_const<'db>( /// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should /// call the method using the vtable. pub fn is_dyn_method<'db>( - db: &'db dyn HirDatabase, + interner: DbInterner<'db>, _env: Arc>, func: FunctionId, - fn_subst: Substitution, + fn_subst: GenericArgs<'db>, ) -> Option { + let db = interner.db; + let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else { return None; }; let trait_params = db.generic_params(trait_id.into()).len(); - let fn_params = fn_subst.len(Interner) - trait_params; - let trait_ref = TraitRef { - trait_id: to_chalk_trait_id(trait_id), - substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).take(trait_params)), - }; - let self_ty = trait_ref.self_type_parameter(Interner); - if let TyKind::Dyn(d) = self_ty.kind(Interner) { + let fn_params = fn_subst.len() - trait_params; + let trait_ref = TraitRef::new( + interner, + trait_id.into(), + GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)), + ); + let self_ty = trait_ref.self_ty(); + if let TyKind::Dynamic(d, _) = self_ty.kind() { + // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter + // what the generics are, we are sure that the method is come from the vtable. let is_my_trait_in_bounds = d - .bounds - .skip_binders() - .as_slice(Interner) - .iter() - .map(|it| it.skip_binders()) - .flat_map(|it| match it { - WhereClause::Implemented(tr) => { - all_super_traits(db, from_chalk_trait_id(tr.trait_id)) - } - _ => smallvec![], - }) - // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter - // what the generics are, we are sure that the method is come from the vtable. - .any(|x| x == trait_id); + .principal_def_id() + .is_some_and(|trait_| all_super_traits(db, trait_.0).contains(&trait_id)); if is_my_trait_in_bounds { return Some(fn_params); } @@ -817,16 +756,19 @@ pub(crate) fn lookup_impl_method_query<'db>( db: &'db dyn HirDatabase, env: Arc>, func: FunctionId, - fn_subst: Substitution, -) -> (FunctionId, Substitution) { + fn_subst: GenericArgs<'db>, +) -> (FunctionId, GenericArgs<'db>) { + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else { return (func, fn_subst); }; let trait_params = db.generic_params(trait_id.into()).len(); - let trait_ref = TraitRef { - trait_id: to_chalk_trait_id(trait_id), - substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).take(trait_params)), - }; + let trait_ref = TraitRef::new( + interner, + trait_id.into(), + GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)), + ); let name = &db.function_signature(func).name; let Some((impl_fn, impl_subst)) = @@ -839,28 +781,28 @@ pub(crate) fn lookup_impl_method_query<'db>( ( impl_fn, - Substitution::from_iter( - Interner, - impl_subst.iter(Interner).chain(fn_subst.iter(Interner).skip(trait_params)), + GenericArgs::new_from_iter( + interner, + impl_subst.iter().chain(fn_subst.iter().skip(trait_params)), ), ) } fn lookup_impl_assoc_item_for_trait_ref<'db>( - trait_ref: TraitRef, + trait_ref: TraitRef<'db>, db: &'db dyn HirDatabase, env: Arc>, name: &Name, -) -> Option<(AssocItemId, Substitution)> { - let hir_trait_id = trait_ref.hir_trait_id(); - let self_ty = trait_ref.self_type_parameter(Interner); - let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?; +) -> Option<(AssocItemId, GenericArgs<'db>)> { + let hir_trait_id = trait_ref.def_id.0; + let self_ty = trait_ref.self_ty(); + let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?; let impls = db.trait_impls_in_deps(env.krate); let trait_module = hir_trait_id.module(db); let type_module = match self_ty_fp { TyFingerprint::Adt(adt_id) => Some(adt_id.module(db)), - TyFingerprint::ForeignType(type_id) => Some(from_foreign_def_id(type_id).module(db)), + TyFingerprint::ForeignType(type_id) => Some(type_id.module(db)), TyFingerprint::Dyn(trait_id) => Some(trait_id.module(db)), _ => None, }; @@ -888,84 +830,85 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>( Some((item, impl_subst)) } -fn find_matching_impl( +fn find_matching_impl<'db>( mut impls: impl Iterator, - mut table: InferenceTable<'_>, - actual_trait_ref: TraitRef, -) -> Option<(&ImplItems, Substitution)> { + mut table: InferenceTable<'db>, + actual_trait_ref: TraitRef<'db>, +) -> Option<(&'db ImplItems, GenericArgs<'db>)> { let db = table.db; impls.find_map(|impl_| { table.run_in_snapshot(|table| { - let impl_substs = - TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build(); - let args: crate::next_solver::GenericArgs<'_> = - impl_substs.to_nextsolver(table.interner); + let impl_substs = table.fresh_args_for_item(impl_.into()); let trait_ref = db .impl_trait(impl_) .expect("non-trait method in find_matching_impl") - .instantiate(table.interner, args) - .to_chalk(table.interner); + .instantiate(table.interner(), impl_substs); - if !table.unify(&trait_ref, &actual_trait_ref) { + if !table.unify(trait_ref, actual_trait_ref) { return None; } - let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs) - .into_iter() - .map(|b| -> Goal { b.cast(Interner) }); - for goal in wcs { - let goal = goal.to_nextsolver(table.interner); - if table.try_obligation(goal).no_solution() { - return None; + if let Some(predicates) = + db.generic_predicates_ns(impl_.into()).instantiate(table.interner(), impl_substs) + { + for predicate in predicates { + if table.try_obligation(predicate.0).no_solution() { + return None; + } + table.register_obligation(predicate.0); } - table.register_obligation(goal); } - Some(( - impl_.impl_items(db), - table.resolve_completely::<_, crate::next_solver::GenericArgs<'_>>(impl_substs), - )) + Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) }) }) } -fn is_inherent_impl_coherent( - db: &dyn HirDatabase, +fn is_inherent_impl_coherent<'db>( + db: &'db dyn HirDatabase, def_map: &DefMap, impl_id: ImplId, - self_ty: &Ty, + self_ty: Ty<'db>, ) -> bool { - let self_ty = self_ty.kind(Interner); + let self_ty = self_ty.kind(); let impl_allowed = match self_ty { - TyKind::Tuple(_, _) + TyKind::Tuple(_) | TyKind::FnDef(_, _) | TyKind::Array(_, _) | TyKind::Never - | TyKind::Raw(_, _) + | TyKind::RawPtr(_, _) | TyKind::Ref(_, _, _) | TyKind::Slice(_) | TyKind::Str - | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(), + | TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) => def_map.is_rustc_coherence_is_core(), - &TyKind::Adt(AdtId(adt), _) => adt.module(db).krate() == def_map.krate(), - TyKind::Dyn(it) => it.principal_id().is_some_and(|trait_id| { - from_chalk_trait_id(trait_id).module(db).krate() == def_map.krate() - }), + TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate() == def_map.krate(), + TyKind::Dynamic(it, _) => it + .principal_def_id() + .is_some_and(|trait_id| trait_id.0.module(db).krate() == def_map.krate()), _ => true, }; impl_allowed || { let rustc_has_incoherent_inherent_impls = match self_ty { - TyKind::Tuple(_, _) + TyKind::Tuple(_) | TyKind::FnDef(_, _) | TyKind::Array(_, _) | TyKind::Never - | TyKind::Raw(_, _) + | TyKind::RawPtr(_, _) | TyKind::Ref(_, _, _) | TyKind::Slice(_) | TyKind::Str - | TyKind::Scalar(_) => true, + | TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) => true, - &TyKind::Adt(AdtId(adt), _) => match adt { + TyKind::Adt(adt_def, _) => match adt_def.def_id().0 { hir_def::AdtId::StructId(id) => db .struct_signature(id) .flags @@ -979,8 +922,8 @@ fn is_inherent_impl_coherent( .flags .contains(EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), }, - TyKind::Dyn(it) => it.principal_id().is_some_and(|trait_id| { - db.trait_signature(from_chalk_trait_id(trait_id)) + TyKind::Dynamic(it, _) => it.principal_def_id().is_some_and(|trait_id| { + db.trait_signature(trait_id.0) .flags .contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS) }), @@ -1012,8 +955,7 @@ fn is_inherent_impl_coherent( /// - All of /// - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type. /// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) -pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { - let substs = TyBuilder::placeholder_subst(db, impl_); +pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool { let Some(impl_trait) = db.impl_trait(impl_) else { // not a trait impl return true; @@ -1022,24 +964,25 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { let local_crate = impl_.lookup(db).container.krate(); let is_local = |tgt_crate| tgt_crate == local_crate; - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let trait_ref = impl_trait.instantiate(interner, args).to_chalk(interner); - let trait_id = from_chalk_trait_id(trait_ref.trait_id); + let trait_ref = impl_trait.instantiate_identity(); + let trait_id = trait_ref.def_id.0; if is_local(trait_id.module(db).krate()) { // trait to be implemented is local return true; } - let unwrap_fundamental = |mut ty: Ty| { + let unwrap_fundamental = |mut ty: Ty<'db>| { // Unwrap all layers of fundamental types with a loop. loop { - match ty.kind(Interner) { - TyKind::Ref(_, _, referenced) => ty = referenced.clone(), - &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => { + match ty.kind() { + TyKind::Ref(_, referenced, _) => ty = referenced, + TyKind::Adt(adt_def, subs) => { + let AdtId::StructId(s) = adt_def.def_id().0 else { + break ty; + }; let struct_signature = db.struct_signature(s); if struct_signature.flags.contains(StructFlags::FUNDAMENTAL) { - let next = subs.type_parameters(Interner).next(); + let next = subs.types().next(); match next { Some(it) => ty = it, None => break ty, @@ -1056,22 +999,20 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { // FIXME: param coverage // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) - let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| { - match unwrap_fundamental(ty).kind(Interner) { - &TyKind::Adt(AdtId(id), _) => is_local(id.module(db).krate()), - TyKind::Error => true, - TyKind::Dyn(it) => it - .principal_id() - .is_some_and(|trait_id| is_local(from_chalk_trait_id(trait_id).module(db).krate())), - _ => false, + let is_not_orphan = trait_ref.args.types().any(|ty| match unwrap_fundamental(ty).kind() { + TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate()), + TyKind::Error(_) => true, + TyKind::Dynamic(it, _) => { + it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate())) } + _ => false, }); #[allow(clippy::let_and_return)] is_not_orphan } pub fn iterate_path_candidates<'db>( - ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &Canonical<'db, Ty<'db>>, db: &'db dyn HirDatabase, env: Arc>, traits_in_scope: &FxHashSet, @@ -1093,7 +1034,7 @@ pub fn iterate_path_candidates<'db>( } pub fn iterate_method_candidates_dyn<'db>( - ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + ty: &Canonical<'db, Ty<'db>>, db: &'db dyn HirDatabase, env: Arc>, traits_in_scope: &FxHashSet, @@ -1132,7 +1073,7 @@ pub fn iterate_method_candidates_dyn<'db>( // types*. let mut table = InferenceTable::new(db, env); - let ty = table.instantiate_canonical_ns(*ty); + let ty = table.instantiate_canonical(*ty); let deref_chain = autoderef_method_receiver(&mut table, ty); deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| { @@ -1165,14 +1106,14 @@ 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: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + receiver_ty: Canonical<'db, Ty<'db>>, first_adjustment: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { - let interner = table.interner; + let interner = table.interner(); let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| { iterate_method_candidates_by_receiver( @@ -1187,11 +1128,7 @@ fn iterate_method_candidates_with_autoref<'db>( }; let mut maybe_reborrowed = first_adjustment.clone(); - 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, - }; + if let TyKind::Ref(_, _, m) = receiver_ty.value.kind() { // Prefer reborrow of references to move maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m)); maybe_reborrowed.autoderefs += 1; @@ -1199,15 +1136,10 @@ fn iterate_method_candidates_with_autoref<'db>( iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?; - let refed = next_solver::Canonical { + let refed = Canonical { max_universe: receiver_ty.max_universe, variables: receiver_ty.variables, - value: next_solver::Ty::new_ref( - interner, - next_solver::Region::error(interner), - receiver_ty.value, - rustc_ast_ir::Mutability::Not, - ), + value: Ty::new_ref(interner, Region::error(interner), receiver_ty.value, Mutability::Not), }; iterate_method_candidates_by_receiver( @@ -1215,15 +1147,10 @@ fn iterate_method_candidates_with_autoref<'db>( first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)), )?; - let ref_muted = next_solver::Canonical { + let ref_muted = Canonical { max_universe: receiver_ty.max_universe, variables: receiver_ty.variables, - value: next_solver::Ty::new_ref( - interner, - next_solver::Region::error(interner), - receiver_ty.value, - rustc_ast_ir::Mutability::Mut, - ), + value: Ty::new_ref(interner, Region::error(interner), receiver_ty.value, Mutability::Mut), }; iterate_method_candidates_by_receiver( @@ -1231,12 +1158,10 @@ 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 TyKind::RawPtr(ty, Mutability::Mut) = receiver_ty.value.kind() { let const_ptr_ty = rustc_type_ir::Canonical { max_universe: rustc_type_ir::UniverseIndex::ZERO, - value: next_solver::Ty::new_ptr(interner, ty, rustc_ast_ir::Mutability::Not), + value: Ty::new_ptr(interner, ty, Mutability::Not), variables: receiver_ty.variables, }; iterate_method_candidates_by_receiver( @@ -1290,30 +1215,27 @@ where #[tracing::instrument(skip_all, fields(name = ?name))] fn iterate_method_candidates_by_receiver<'db>( table: &mut InferenceTable<'db>, - receiver_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + receiver_ty: Canonical<'db, Ty<'db>>, receiver_adjustments: ReceiverAdjustments, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, 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(interner); + let receiver_ty = table.instantiate_canonical(receiver_ty); // 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.to_nextsolver(interner)) - .include_raw_pointers() - .use_receiver_trait(); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty) + .include_raw_pointers() + .use_receiver_trait(); while let Some((self_ty, _)) = autoderef.next() { iterate_inherent_methods( - &self_ty.to_chalk(interner), + self_ty, autoderef.table, name, - Some(&receiver_ty), + Some(receiver_ty), Some(receiver_adjustments.clone()), visible_from_module, LookupMode::MethodCall, @@ -1325,23 +1247,21 @@ fn iterate_method_candidates_by_receiver<'db>( ControlFlow::Continue(()) })?; table.run_in_snapshot(|table| { - let mut autoderef = - autoderef::Autoderef::new_no_tracking(table, receiver_ty.to_nextsolver(interner)) - .include_raw_pointers() - .use_receiver_trait(); + let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty) + .include_raw_pointers() + .use_receiver_trait(); while let Some((self_ty, _)) = autoderef.next() { - if matches!(self_ty.kind(), crate::next_solver::TyKind::Infer(rustc_type_ir::TyVar(_))) - { + if matches!(self_ty.kind(), TyKind::Infer(rustc_type_ir::TyVar(_))) { // don't try to resolve methods on unknown types return ControlFlow::Continue(()); } iterate_trait_method_candidates( - &self_ty.to_chalk(interner), + self_ty, autoderef.table, traits_in_scope, name, - Some(&receiver_ty), + Some(receiver_ty), Some(receiver_adjustments.clone()), LookupMode::MethodCall, &mut |adjustments, item, is_visible| { @@ -1355,7 +1275,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: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, + self_ty: &Canonical<'db, Ty<'db>>, db: &'db dyn HirDatabase, env: Arc>, traits_in_scope: &FxHashSet, @@ -1364,9 +1284,9 @@ fn iterate_method_candidates_for_self_ty<'db>( callback: &mut dyn MethodCandidateCallback, ) -> ControlFlow<()> { let mut table = InferenceTable::new(db, env); - let self_ty = table.instantiate_canonical_ns(*self_ty).to_chalk(table.interner); + let self_ty = table.instantiate_canonical(*self_ty); iterate_inherent_methods( - &self_ty, + self_ty, &mut table, name, None, @@ -1378,7 +1298,7 @@ fn iterate_method_candidates_for_self_ty<'db>( }, )?; iterate_trait_method_candidates( - &self_ty, + self_ty, &mut table, traits_in_scope, name, @@ -1392,19 +1312,19 @@ fn iterate_method_candidates_for_self_ty<'db>( } #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))] -fn iterate_trait_method_candidates( - self_ty: &Ty, - table: &mut InferenceTable<'_>, +fn iterate_trait_method_candidates<'db>( + self_ty: Ty<'db>, + table: &mut InferenceTable<'db>, traits_in_scope: &FxHashSet, name: Option<&Name>, - receiver_ty: Option<&Ty>, + receiver_ty: Option>, receiver_adjustments: Option, mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; - let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner)); + let canonical_self_ty = table.canonicalize(self_ty); let krate = table.trait_env.krate; 'traits: for &t in traits_in_scope { @@ -1416,7 +1336,7 @@ fn iterate_trait_method_candidates( // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for // arrays. if data.flags.contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH) - && matches!(self_ty.kind(Interner), TyKind::Array(..)) + && matches!(self_ty.kind(), TyKind::Array(..)) { // FIXME: this should really be using the edition of the method name's span, in case it // comes from a macro @@ -1426,9 +1346,9 @@ fn iterate_trait_method_candidates( } if data.flags.contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH) && matches!( - self_ty.kind(Interner), TyKind::Adt(AdtId(def), subst) - if is_box(table.db, *def) - && matches!(subst.at(Interner, 0).assert_ty_ref(Interner).kind(Interner), TyKind::Slice(..)) + self_ty.kind(), TyKind::Adt(adt_def, subst) + if is_box(table.db, adt_def.def_id().0) + && matches!(subst.type_at(0).kind(), TyKind::Slice(..)) ) { // FIXME: this should really be using the edition of the method name's span, in case it @@ -1472,11 +1392,11 @@ fn iterate_trait_method_candidates( } #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))] -fn iterate_inherent_methods( - self_ty: &Ty, - table: &mut InferenceTable<'_>, +fn iterate_inherent_methods<'db>( + self_ty: Ty<'db>, + table: &mut InferenceTable<'db>, name: Option<&Name>, - receiver_ty: Option<&Ty>, + receiver_ty: Option>, receiver_adjustments: Option, visible_from_module: VisibleFromModule, mode: LookupMode, @@ -1489,11 +1409,11 @@ fn iterate_inherent_methods( // its super traits are considered inherent methods. This matters because these methods have // higher priority than the other traits' methods, which would be considered in // `iterate_trait_method_candidates()` only after this function. - match self_ty.kind(Interner) { - TyKind::Placeholder(_) => { + match self_ty.kind() { + TyKind::Param(_) => { let env = table.trait_env.clone(); let traits = env - .traits_in_scope_from_clauses(self_ty.clone()) + .traits_in_scope_from_clauses(self_ty.to_chalk(table.interner())) .flat_map(|t| all_super_traits(db, t)); iterate_inherent_trait_methods( self_ty, @@ -1506,9 +1426,9 @@ fn iterate_inherent_methods( mode, )?; } - TyKind::Dyn(_) => { - if let Some(principal_trait) = self_ty.dyn_trait() { - let traits = all_super_traits(db, principal_trait); + TyKind::Dynamic(bounds, _) => { + if let Some(principal_trait) = bounds.principal_def_id() { + let traits = all_super_traits(db, principal_trait.0); iterate_inherent_trait_methods( self_ty, table, @@ -1568,11 +1488,11 @@ fn iterate_inherent_methods( return ControlFlow::Continue(()); #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))] - fn iterate_inherent_trait_methods( - self_ty: &Ty, - table: &mut InferenceTable<'_>, + fn iterate_inherent_trait_methods<'db>( + self_ty: Ty<'db>, + table: &mut InferenceTable<'db>, name: Option<&Name>, - receiver_ty: Option<&Ty>, + receiver_ty: Option>, receiver_adjustments: Option, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, traits: impl Iterator, @@ -1603,12 +1523,12 @@ fn iterate_inherent_methods( } #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))] - fn impls_for_self_ty( + fn impls_for_self_ty<'db>( impls: &InherentImpls, - self_ty: &Ty, - table: &mut InferenceTable<'_>, + self_ty: Ty<'db>, + table: &mut InferenceTable<'db>, name: Option<&Name>, - receiver_ty: Option<&Ty>, + receiver_ty: Option>, receiver_adjustments: Option, visible_from_module: Option, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, @@ -1639,10 +1559,10 @@ fn iterate_inherent_methods( /// Returns the receiver type for the index trait call. pub(crate) fn resolve_indexing_op<'db>( table: &mut InferenceTable<'db>, - ty: next_solver::Canonical<'db, next_solver::Ty<'db>>, + ty: Canonical<'db, Ty<'db>>, index_trait: TraitId, ) -> Option { - let ty = table.instantiate_canonical_ns(ty); + let ty = table.instantiate_canonical(ty); let deref_chain = autoderef_method_receiver(table, ty); for (ty, adj) in deref_chain { let goal = generic_implements_goal_ns(table, index_trait, ty); @@ -1670,10 +1590,10 @@ enum IsValidCandidate { } #[tracing::instrument(skip_all, fields(name))] -fn is_valid_impl_method_candidate( - table: &mut InferenceTable<'_>, - self_ty: &Ty, - receiver_ty: Option<&Ty>, +fn is_valid_impl_method_candidate<'db>( + table: &mut InferenceTable<'db>, + self_ty: Ty<'db>, + receiver_ty: Option>, visible_from_module: Option, name: Option<&Name>, impl_id: ImplId, @@ -1705,9 +1625,8 @@ fn is_valid_impl_method_candidate( let self_ty_matches = table.run_in_snapshot(|table| { let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id) .fill_with_inference_vars(table) - .build(DbInterner::conjure()) - .to_chalk(DbInterner::conjure()); - table.unify(&expected_self_ty, self_ty) + .build(table.interner()); + table.unify(expected_self_ty, self_ty) }); if !self_ty_matches { cov_mark::hit!(const_candidate_self_type_mismatch); @@ -1721,13 +1640,13 @@ fn is_valid_impl_method_candidate( /// Checks whether a given `AssocItemId` is applicable for `receiver_ty`. #[tracing::instrument(skip_all, fields(name))] -fn is_valid_trait_method_candidate( - table: &mut InferenceTable<'_>, +fn is_valid_trait_method_candidate<'db>( + table: &mut InferenceTable<'db>, trait_id: TraitId, name: Option<&Name>, - receiver_ty: Option<&Ty>, + receiver_ty: Option>, item: AssocItemId, - self_ty: &Ty, + self_ty: Ty<'db>, mode: LookupMode, ) -> IsValidCandidate { let db = table.db; @@ -1738,27 +1657,20 @@ fn is_valid_trait_method_candidate( check_that!(name.is_none_or(|n| n == &data.name)); table.run_in_snapshot(|table| { - let impl_subst = TyBuilder::subst_for_def(db, trait_id, None) - .fill_with_inference_vars(table) - .build(); - let expect_self_ty = impl_subst.at(Interner, 0).assert_ty_ref(Interner).clone(); + let impl_subst = table.fresh_args_for_item(trait_id.into()); + let expect_self_ty = impl_subst.type_at(0); - check_that!(table.unify(&expect_self_ty, self_ty)); + check_that!(table.unify(expect_self_ty, self_ty)); if let Some(receiver_ty) = receiver_ty { check_that!(data.has_self_param()); - let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst)) - .fill_with_inference_vars(table) - .build(); + let args = table.fill_rest_fresh_args(fn_id.into(), impl_subst); - let args: crate::next_solver::GenericArgs<'_> = - fn_subst.to_nextsolver(table.interner); let sig = db.callable_item_signature(fn_id.into()); let expected_receiver = sig .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0]) - .instantiate(table.interner, args) - .to_chalk(table.interner); + .instantiate(table.interner(), args); // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext` let variance = match mode { @@ -1767,16 +1679,8 @@ fn is_valid_trait_method_candidate( }; let res = table .infer_ctxt - .at( - &next_solver::infer::traits::ObligationCause::dummy(), - table.trait_env.env, - ) - .relate( - DefineOpaqueTypes::No, - expected_receiver.to_nextsolver(table.interner), - variance, - receiver_ty.to_nextsolver(table.interner), - ); + .at(&ObligationCause::dummy(), table.trait_env.env) + .relate(DefineOpaqueTypes::No, expected_receiver, variance, receiver_ty); let Ok(infer_ok) = res else { return IsValidCandidate::No; }; @@ -1788,7 +1692,7 @@ fn is_valid_trait_method_candidate( check_that!(ctxt.select_where_possible().is_empty()); } - check_that!(table.unify(receiver_ty, &expected_receiver)); + check_that!(table.unify(receiver_ty, expected_receiver)); } IsValidCandidate::Yes @@ -1805,13 +1709,13 @@ fn is_valid_trait_method_candidate( } #[tracing::instrument(skip_all, fields(name))] -fn is_valid_impl_fn_candidate( - table: &mut InferenceTable<'_>, +fn is_valid_impl_fn_candidate<'db>( + table: &mut InferenceTable<'db>, impl_id: ImplId, fn_id: FunctionId, name: Option<&Name>, - receiver_ty: Option<&Ty>, - self_ty: &Ty, + receiver_ty: Option>, + self_ty: Ty<'db>, visible_from_module: Option, item_name: &Name, ) -> IsValidCandidate { @@ -1829,34 +1733,28 @@ fn is_valid_impl_fn_candidate( table.run_in_snapshot(|table| { let _p = tracing::info_span!("subst_for_def").entered(); let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into()); - let expect_self_ty = db - .impl_self_ty(impl_id) - .instantiate(table.interner, &impl_subst) - .to_chalk(table.interner); + let expect_self_ty = db.impl_self_ty(impl_id).instantiate(table.interner(), &impl_subst); - check_that!(table.unify(&expect_self_ty, self_ty)); + check_that!(table.unify(expect_self_ty, self_ty)); if let Some(receiver_ty) = receiver_ty { let _p = tracing::info_span!("check_receiver_ty").entered(); check_that!(data.has_self_param()); - let fn_subst: crate::Substitution = - table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner); + let args = table.infer_ctxt.fresh_args_for_item(fn_id.into()); - let args: crate::next_solver::GenericArgs<'_> = fn_subst.to_nextsolver(table.interner); let sig = db.callable_item_signature(fn_id.into()); let expected_receiver = sig .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0]) - .instantiate(table.interner, args) - .to_chalk(table.interner); + .instantiate(table.interner(), args); - check_that!(table.unify(receiver_ty, &expected_receiver)); + check_that!(table.unify(receiver_ty, expected_receiver)); } // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. let predicates = db.generic_predicates_ns(impl_id.into()); - let Some(predicates) = predicates.instantiate(table.interner, impl_subst) else { + let Some(predicates) = predicates.instantiate(table.interner(), impl_subst) else { return IsValidCandidate::Yes; }; @@ -1864,7 +1762,7 @@ fn is_valid_impl_fn_candidate( ctxt.register_obligations(predicates.into_iter().map(|p| { PredicateObligation::new( - table.interner, + table.interner(), ObligationCause::new(), table.trait_env.env, p.0, @@ -1880,7 +1778,7 @@ fn is_valid_impl_fn_candidate( } pub fn implements_trait_unique<'db>( - ty: &Canonical, + ty: &crate::Canonical, db: &'db dyn HirDatabase, env: &TraitEnvironment<'db>, trait_: TraitId, @@ -1896,8 +1794,8 @@ fn generic_implements_goal<'db>( db: &'db dyn HirDatabase, env: &TraitEnvironment<'db>, trait_: TraitId, - self_ty: &Canonical, -) -> Canonical> { + self_ty: &crate::Canonical, +) -> crate::Canonical> { let binders = self_ty.binders.interned(); let trait_ref = TyBuilder::trait_ref(db, trait_) .push(self_ty.value.clone()) @@ -1920,7 +1818,7 @@ fn generic_implements_goal<'db>( &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), obligation, ); - Canonical { binders, value } + crate::Canonical { binders, value } } /// This creates Substs for a trait with the given Self type and type variables @@ -1929,23 +1827,23 @@ fn generic_implements_goal<'db>( fn generic_implements_goal_ns<'db>( table: &mut InferenceTable<'db>, trait_: TraitId, - self_ty: next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, -) -> next_solver::Canonical<'db, next_solver::Goal<'db, crate::next_solver::Predicate<'db>>> { + self_ty: Canonical<'db, Ty<'db>>, +) -> Canonical<'db, Goal<'db, Predicate<'db>>> { let args = table.infer_ctxt.fresh_args_for_item(SolverDefId::TraitId(trait_)); - let self_ty = table.instantiate_canonical_ns(self_ty); + let self_ty = table.instantiate_canonical(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, trait_ref); + let goal = Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref); table.canonicalize(goal) } fn autoderef_method_receiver<'db>( table: &mut InferenceTable<'db>, - ty: next_solver::Ty<'db>, -) -> Vec<(next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, ReceiverAdjustments)> { - let interner = table.interner; + ty: Ty<'db>, +) -> Vec<(Canonical<'db, Ty<'db>>, ReceiverAdjustments)> { + let interner = table.interner(); let mut deref_chain = Vec::new(); let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty).use_receiver_trait(); while let Some((ty, derefs)) = autoderef.next() { @@ -1958,9 +1856,9 @@ fn autoderef_method_receiver<'db>( if let Some((rustc_type_ir::Array(parameters, _), variables, max_universe, adj)) = deref_chain.last().map(|d| (d.0.value.kind(), d.0.variables, d.0.max_universe, d.1.clone())) { - let unsized_ty = next_solver::Ty::new_slice(interner, parameters); + let unsized_ty = Ty::new_slice(interner, parameters); deref_chain.push(( - next_solver::Canonical { max_universe, value: unsized_ty, variables }, + 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 6465099dffd7f..a05cc2a02b70e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -708,10 +708,10 @@ impl BorrowKind { } } - fn from_chalk(m: Mutability) -> Self { + fn from_rustc(m: rustc_ast_ir::Mutability) -> Self { match m { - Mutability::Not => BorrowKind::Shared, - Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, + rustc_ast_ir::Mutability::Not => BorrowKind::Shared, + rustc_ast_ir::Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, } } } 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 2c09fb9a89e78..08b1e03726d70 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 @@ -11,6 +11,8 @@ use rustc_hash::FxHashMap; use stdx::never; use triomphe::Arc; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags, db::{HirDatabase, InternedClosure}, @@ -61,16 +63,16 @@ pub struct BorrowckResult { pub borrow_regions: Vec, } -fn all_mir_bodies( - db: &dyn HirDatabase, +fn all_mir_bodies<'db>( + db: &'db dyn HirDatabase, def: DefWithBodyId, mut cb: impl FnMut(Arc), -) -> Result<(), MirLowerError> { - fn for_closure( - db: &dyn HirDatabase, +) -> Result<(), MirLowerError<'db>> { + fn for_closure<'db>( + db: &'db dyn HirDatabase, c: ClosureId, cb: &mut impl FnMut(Arc), - ) -> Result<(), MirLowerError> { + ) -> Result<(), MirLowerError<'db>> { match db.mir_body_for_closure(c.into()) { Ok(body) => { cb(body.clone()); @@ -88,10 +90,10 @@ fn all_mir_bodies( } } -pub fn borrowck_query( - db: &dyn HirDatabase, +pub fn borrowck_query<'db>( + db: &'db dyn HirDatabase, def: DefWithBodyId, -) -> Result, MirLowerError> { +) -> Result, MirLowerError<'db>> { let _p = tracing::info_span!("borrowck_query").entered(); let mut res = vec![]; all_mir_bodies(db, def, |body| { @@ -112,14 +114,17 @@ fn make_fetch_closure_field( |c: ClosureId, subst: &Substitution, f: usize| { let InternedClosure(def, _) = db.lookup_intern_closure(c.into()); let infer = db.infer(def); - let (captures, _) = infer.closure_info(&c); + let (captures, _) = infer.closure_info(c.into()); let parent_subst = ClosureSubst(subst).parent_subst(db); + let interner = DbInterner::new_with(db, None, None); + let parent_subst: crate::next_solver::GenericArgs<'_> = + parent_subst.to_nextsolver(interner); captures .get(f) .expect("broken closure field") .ty - .clone() - .substitute(Interner, &parent_subst) + .instantiate(interner, parent_subst) + .to_chalk(interner) } } 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 fa63baa5d2ab8..e46490e5262ee 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 @@ -32,6 +32,7 @@ use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, Interner, MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, @@ -102,13 +103,13 @@ impl<'db> VTableMap<'db> { id } - pub(crate) fn ty(&self, id: usize) -> Result> { + pub(crate) fn ty(&self, id: usize) -> Result<'db, crate::next_solver::Ty<'db>> { id.checked_sub(VTableMap::OFFSET) .and_then(|id| self.id_to_ty.get(id).copied()) .ok_or(MirEvalError::InvalidVTableId(id)) } - fn ty_of_bytes(&self, bytes: &[u8]) -> Result> { + fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, crate::next_solver::Ty<'db>> { let id = from_bytes!(usize, bytes); self.ty(id) } @@ -134,14 +135,14 @@ impl TlsData { self.keys.len() - 1 } - fn get_key(&mut self, key: usize) -> Result { + fn get_key(&mut self, key: usize) -> Result<'static, u128> { let r = self.keys.get(key).ok_or_else(|| { MirEvalError::UndefinedBehavior(format!("Getting invalid tls key {key}")) })?; Ok(*r) } - fn set_key(&mut self, key: usize, value: u128) -> Result<()> { + fn set_key(&mut self, key: usize, value: u128) -> Result<'static, ()> { let r = self.keys.get_mut(key).ok_or_else(|| { MirEvalError::UndefinedBehavior(format!("Setting invalid tls key {key}")) })?; @@ -202,6 +203,7 @@ pub struct Evaluator<'a> { stack_depth_limit: usize, /// Maximum count of bytes that heap and stack can grow memory_limit: usize, + interner: DbInterner<'a>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -230,15 +232,19 @@ impl Interval { Self { addr, size } } - fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> { memory.read_memory(self.addr, self.size) } - fn write_from_bytes(&self, memory: &mut Evaluator<'_>, bytes: &[u8]) -> Result<()> { + fn write_from_bytes<'db>(&self, memory: &mut Evaluator<'db>, bytes: &[u8]) -> Result<'db, ()> { memory.write_memory(self.addr, bytes) } - fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> { + fn write_from_interval<'db>( + &self, + memory: &mut Evaluator<'db>, + interval: Interval, + ) -> Result<'db, ()> { memory.copy_from_interval(self.addr, interval) } @@ -248,16 +254,16 @@ impl Interval { } impl IntervalAndTy { - fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> { memory.read_memory(self.interval.addr, self.interval.size) } - fn new( + fn new<'db>( addr: Address, ty: Ty, - evaluator: &Evaluator<'_>, + evaluator: &Evaluator<'db>, locals: &Locals, - ) -> Result { + ) -> Result<'db, IntervalAndTy> { let size = evaluator.size_of_sized(&ty, locals, "type of interval")?; Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) } @@ -275,7 +281,7 @@ impl From for IntervalOrOwned { } impl IntervalOrOwned { - fn get<'a, 'db>(&'a self, memory: &'a Evaluator<'db>) -> Result<&'a [u8]> { + fn get<'a, 'db>(&'a self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> { Ok(match self { IntervalOrOwned::Owned(o) => o, IntervalOrOwned::Borrowed(b) => b.get(memory)?, @@ -295,7 +301,7 @@ const HEAP_OFFSET: usize = 1 << 29; impl Address { #[allow(clippy::double_parens)] - fn from_bytes(it: &[u8]) -> Result { + fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> { Ok(Address::from_usize(from_bytes!(usize, it))) } @@ -335,8 +341,8 @@ impl Address { } #[derive(Clone, PartialEq, Eq)] -pub enum MirEvalError { - ConstEvalError(String, Box), +pub enum MirEvalError<'db> { + ConstEvalError(String, Box>), LayoutError(LayoutError, Ty), TargetDataLayoutNotAvailable(TargetLoadError), /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected @@ -344,12 +350,15 @@ pub enum MirEvalError { UndefinedBehavior(String), Panic(String), // FIXME: This should be folded into ConstEvalError? - MirLowerError(FunctionId, MirLowerError), - MirLowerErrorForClosure(ClosureId, MirLowerError), + MirLowerError(FunctionId, MirLowerError<'db>), + MirLowerErrorForClosure(ClosureId, MirLowerError<'db>), TypeIsUnsized(Ty, &'static str), NotSupported(String), InvalidConst(Const), - InFunction(Box, Vec<(Either, MirSpan, DefWithBodyId)>), + InFunction( + Box>, + Vec<(Either, MirSpan, DefWithBodyId)>, + ), ExecutionLimitExceeded, StackOverflow, /// FIXME: Fold this into InternalError @@ -360,7 +369,7 @@ pub enum MirEvalError { InternalError(Box), } -impl MirEvalError { +impl MirEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -492,7 +501,7 @@ impl MirEvalError { } } -impl std::fmt::Debug for MirEvalError { +impl std::fmt::Debug for MirEvalError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ConstEvalError(arg0, arg1) => { @@ -534,7 +543,7 @@ impl std::fmt::Debug for MirEvalError { } } -type Result = std::result::Result; +type Result<'db, T> = std::result::Result>; #[derive(Debug, Default)] struct DropFlags { @@ -595,10 +604,10 @@ pub fn interpret_mir<'db>( // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, trait_env: Option>>, -) -> Result<(Result, MirOutput)> { +) -> Result<'db, (Result<'db, Const>, MirOutput)> { let ty = body.locals[return_slot()].ty.clone(); let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?; - let it: Result = (|| { + let it: Result<'db, Const> = (|| { if evaluator.ptr_size() != size_of::() { not_supported!("targets with different pointer size from host"); } @@ -639,13 +648,14 @@ impl<'db> Evaluator<'db> { owner: DefWithBodyId, assert_placeholder_ty_is_unused: bool, trait_env: Option>>, - ) -> Result> { + ) -> Result<'db, Evaluator<'db>> { let crate_id = owner.module(db).krate(); let target_data_layout = match db.target_data_layout(crate_id) { Ok(target_data_layout) => target_data_layout, Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)), }; let cached_ptr_size = target_data_layout.pointer_size().bytes_usize(); + let interner = DbInterner::new_with(db, None, None); Ok(Evaluator { target_data_layout, stack: vec![0], @@ -679,14 +689,15 @@ impl<'db> Evaluator<'db> { cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| { x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once)) }), + interner, }) } - fn place_addr(&self, p: &Place, locals: &Locals) -> Result
{ + fn place_addr(&self, p: &Place, locals: &Locals) -> Result<'db, Address> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) } - fn place_interval(&self, p: &Place, locals: &Locals) -> Result { + fn place_interval(&self, p: &Place, locals: &Locals) -> Result<'db, Interval> { let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; Ok(Interval { addr: place_addr_and_ty.0, @@ -714,14 +725,20 @@ impl<'db> Evaluator<'db> { |c, subst, f| { let InternedClosure(def, _) = self.db.lookup_intern_closure(c.into()); let infer = self.db.infer(def); - let (captures, _) = infer.closure_info(&c); + let (captures, _) = infer.closure_info(c.into()); let parent_subst = ClosureSubst(subst).parent_subst(self.db); captures .get(f) .expect("broken closure field") .ty - .clone() - .substitute(Interner, &parent_subst) + .instantiate( + self.interner, + <_ as ChalkToNextSolver<'db, crate::next_solver::GenericArgs<'db>>>::to_nextsolver( + &parent_subst, + self.interner, + ), + ) + .to_chalk(self.interner) }, self.crate_id, ); @@ -733,7 +750,7 @@ impl<'db> Evaluator<'db> { &'a self, p: &Place, locals: &'a Locals, - ) -> Result<(Address, Ty, Option)> { + ) -> Result<'db, (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(); @@ -851,7 +868,7 @@ impl<'db> Evaluator<'db> { Ok((addr, ty, metadata)) } - fn layout(&self, ty: crate::next_solver::Ty<'db>) -> Result> { + fn layout(&self, ty: crate::next_solver::Ty<'db>) -> Result<'db, Arc> { if let Some(x) = self.layout_cache.borrow().get(&ty) { return Ok(x.clone()); } @@ -864,7 +881,7 @@ impl<'db> Evaluator<'db> { Ok(r) } - fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result> { + fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<'db, Arc> { let interner = DbInterner::new_with(self.db, None, None); self.layout(crate::next_solver::Ty::new( interner, @@ -875,22 +892,27 @@ impl<'db> Evaluator<'db> { )) } - fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result { + fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<'db, Ty> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result { + fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty> { Ok(match &o.kind { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant(c) => c.data(Interner).ty.clone(), &OperandKind::Static(s) => { - let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr].clone(); + let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr] + .to_chalk(self.interner); TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner) } }) } - fn operand_ty_and_eval(&mut self, o: &Operand, locals: &mut Locals) -> Result { + fn operand_ty_and_eval( + &mut self, + o: &Operand, + locals: &mut Locals, + ) -> Result<'db, IntervalAndTy> { Ok(IntervalAndTy { interval: self.eval_operand(o, locals)?, ty: self.operand_ty(o, locals)?, @@ -901,7 +923,7 @@ impl<'db> Evaluator<'db> { &mut self, body: Arc, args: impl Iterator, - ) -> Result { + ) -> Result<'db, Interval> { if let Some(it) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = it; } else { @@ -962,7 +984,7 @@ impl<'db> Evaluator<'db> { let args = args .iter() .map(|it| self.operand_ty_and_eval(it, locals)) - .collect::>>()?; + .collect::>>()?; let stack_frame = match &fn_ty.kind(Interner) { TyKind::Function(_) => { let bytes = self.eval_operand(func, locals)?; @@ -1066,7 +1088,7 @@ impl<'db> Evaluator<'db> { body: &MirBody, locals: &mut Locals, args: impl Iterator, - ) -> Result<()> { + ) -> Result<'db, ()> { let mut remain_args = body.param_locals.len(); for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) { locals.drop_flags.add_place(l.into(), &locals.body.projection_store); @@ -1089,7 +1111,7 @@ impl<'db> Evaluator<'db> { &mut self, body: &Arc, destination: Option, - ) -> Result<(Locals, usize)> { + ) -> Result<'db, (Locals, usize)> { let mut locals = match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() { None => Locals { @@ -1136,7 +1158,7 @@ impl<'db> Evaluator<'db> { Ok((locals, prev_stack_pointer)) } - fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result { + fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result<'db, IntervalOrOwned> { let interner = DbInterner::new_with(self.db, None, None); use IntervalOrOwned::*; Ok(match r { @@ -1450,7 +1472,7 @@ impl<'db> Evaluator<'db> { let values = values .iter() .map(|it| self.eval_operand(it, locals)) - .collect::>>()?; + .collect::>>()?; match kind { AggregateKind::Array(_) => { let mut r = vec![]; @@ -1649,7 +1671,7 @@ impl<'db> Evaluator<'db> { }) } - fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result { + fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result<'db, i128> { 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 { @@ -1696,7 +1718,7 @@ impl<'db> Evaluator<'db> { &self, ty: &Ty, goal: impl Fn(&TyKind) -> Option, - ) -> Result { + ) -> Result<'db, T> { let kind = ty.kind(Interner); if let Some(it) = goal(kind) { return Ok(it); @@ -1719,7 +1741,7 @@ impl<'db> Evaluator<'db> { addr: Interval, current_ty: &Ty, target_ty: &Ty, - ) -> Result { + ) -> Result<'db, IntervalOrOwned> { fn for_ptr(it: &TyKind) -> Option { match it { TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()), @@ -1738,7 +1760,7 @@ impl<'db> Evaluator<'db> { target_ty: Ty, current_ty: Ty, addr: Interval, - ) -> Result { + ) -> Result<'db, IntervalOrOwned> { use IntervalOrOwned::*; Ok(match &target_ty.kind(Interner) { TyKind::Slice(_) => match ¤t_ty.kind(Interner) { @@ -1806,7 +1828,7 @@ impl<'db> Evaluator<'db> { it: VariantId, subst: Substitution, locals: &Locals, - ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { + ) -> Result<'db, (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 @@ -1874,7 +1896,7 @@ impl<'db> Evaluator<'db> { variant_layout: &Layout, tag: Option<(usize, usize, i128)>, values: impl Iterator, - ) -> Result> { + ) -> Result<'db, Vec> { let mut result = vec![0; size]; if let Some((offset, size, value)) = tag { match result.get_mut(offset..offset + size) { @@ -1904,7 +1926,7 @@ impl<'db> Evaluator<'db> { Ok(result) } - fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result { + fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<'db, Interval> { Ok(match &it.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p, &locals.body.projection_store); @@ -1919,8 +1941,8 @@ impl<'db> Evaluator<'db> { } #[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); + fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result<'db, Interval> { + let interner = self.interner; let ConstData { ty, value: chalk_ir::ConstValue::Concrete(c) } = &konst.data(Interner) else { not_supported!("evaluating non concrete constant"); @@ -1932,9 +1954,14 @@ impl<'db> Evaluator<'db> { let mut const_id = *const_id; let mut subst = subst.clone(); if let hir_def::GeneralConstId::ConstId(c) = const_id { - let (c, s) = lookup_impl_const(self.db, self.trait_env.clone(), c, subst); + let (c, s) = lookup_impl_const( + self.interner, + self.trait_env.clone(), + c, + subst.to_nextsolver(self.interner), + ); const_id = hir_def::GeneralConstId::ConstId(c); - subst = s; + subst = s.to_chalk(self.interner); } result_owner = self .db @@ -1987,7 +2014,7 @@ impl<'db> Evaluator<'db> { Ok(Interval::new(addr, size)) } - fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result { + fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<'db, Interval> { let addr = self.place_addr(p, locals)?; Ok(Interval::new( addr, @@ -1995,7 +2022,7 @@ impl<'db> Evaluator<'db> { )) } - fn read_memory(&self, addr: Address, size: usize) -> Result<&[u8]> { + fn read_memory(&self, addr: Address, size: usize) -> Result<'db, &[u8]> { if size == 0 { return Ok(&[]); } @@ -2012,7 +2039,7 @@ impl<'db> Evaluator<'db> { .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_owned())) } - fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<&mut [u8]> { + fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<'db, &mut [u8]> { let (mem, pos) = match addr { Stack(it) => (&mut self.stack, it), Heap(it) => (&mut self.heap, it), @@ -2026,7 +2053,7 @@ impl<'db> Evaluator<'db> { .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory write".to_owned())) } - fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> { + fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<'db, ()> { if r.is_empty() { return Ok(()); } @@ -2034,14 +2061,18 @@ impl<'db> Evaluator<'db> { Ok(()) } - fn copy_from_interval_or_owned(&mut self, addr: Address, r: IntervalOrOwned) -> Result<()> { + fn copy_from_interval_or_owned( + &mut self, + addr: Address, + r: IntervalOrOwned, + ) -> Result<'db, ()> { match r { IntervalOrOwned::Borrowed(r) => self.copy_from_interval(addr, r), IntervalOrOwned::Owned(r) => self.write_memory(addr, &r), } } - fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> { + fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<'db, ()> { if r.size == 0 { return Ok(()); } @@ -2083,7 +2114,7 @@ impl<'db> Evaluator<'db> { Ok(()) } - fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result> { + fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<'db, Option<(usize, usize)>> { 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 @@ -2112,7 +2143,7 @@ impl<'db> Evaluator<'db> { /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` - fn size_of_sized(&self, ty: &Ty, locals: &Locals, what: &'static str) -> Result { + fn size_of_sized(&self, ty: &Ty, locals: &Locals, what: &'static str) -> Result<'db, usize> { match self.size_align_of(ty, locals)? { Some(it) => Ok(it.0), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), @@ -2126,14 +2157,14 @@ impl<'db> Evaluator<'db> { ty: &Ty, locals: &Locals, what: &'static str, - ) -> Result<(usize, usize)> { + ) -> Result<'db, (usize, usize)> { match self.size_align_of(ty, locals)? { Some(it) => Ok(it), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), } } - fn heap_allocate(&mut self, size: usize, align: usize) -> Result
{ + fn heap_allocate(&mut self, size: usize, align: usize) -> Result<'db, Address> { if !align.is_power_of_two() || align > 10000 { return Err(MirEvalError::UndefinedBehavior(format!("Alignment {align} is invalid"))); } @@ -2166,7 +2197,7 @@ impl<'db> Evaluator<'db> { bytes: &[u8], ty: &Ty, locals: &Locals, - ) -> Result> { + ) -> Result<'db, ComplexMemoryMap<'db>> { fn rec<'db>( this: &Evaluator<'db>, bytes: &[u8], @@ -2174,7 +2205,7 @@ impl<'db> Evaluator<'db> { locals: &Locals, mm: &mut ComplexMemoryMap<'db>, stack_depth_limit: usize, - ) -> Result<()> { + ) -> Result<'db, ()> { let interner = DbInterner::new_with(this.db, None, None); if stack_depth_limit.checked_sub(1).is_none() { return Err(MirEvalError::StackOverflow); @@ -2333,11 +2364,11 @@ impl<'db> Evaluator<'db> { fn patch_addresses( &mut self, patch_map: &FxHashMap, - ty_of_bytes: impl Fn(&[u8]) -> Result> + Copy, + ty_of_bytes: impl Fn(&[u8]) -> Result<'db, crate::next_solver::Ty<'db>> + Copy, addr: Address, ty: crate::next_solver::Ty<'db>, locals: &Locals, - ) -> Result<()> { + ) -> Result<'db, ()> { let interner = DbInterner::new_with(self.db, None, None); // FIXME: support indirect references let layout = self.layout(ty)?; @@ -2469,7 +2500,7 @@ impl<'db> Evaluator<'db> { locals: &Locals, target_bb: Option, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let id = from_bytes!(usize, bytes.get(self)?); let next_ty = self.vtable_map.ty(id)?; let interner = DbInterner::new_with(self.db, None, None); @@ -2506,7 +2537,7 @@ impl<'db> Evaluator<'db> { args: &[IntervalAndTy], locals: &Locals, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let mir_body = self .db .monomorphized_mir_body_for_closure( @@ -2523,7 +2554,7 @@ impl<'db> Evaluator<'db> { }; let arg_bytes = iter::once(Ok(closure_data)) .chain(args.iter().map(|it| Ok(it.get(self)?.to_owned()))) - .collect::>>()?; + .collect::>>()?; let interval = self .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned)) .map_err(|e| { @@ -2545,7 +2576,7 @@ impl<'db> Evaluator<'db> { locals: &Locals, target_bb: Option, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let generic_args = generic_args.clone(); match def { CallableDefId::FunctionId(def) => { @@ -2603,23 +2634,33 @@ impl<'db> Evaluator<'db> { generic_args: Substitution, locals: &Locals, span: MirSpan, - ) -> Result { + ) -> Result<'db, MirOrDynIndex> { let pair = (def, generic_args); if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) { return Ok(r.clone()); } let (def, generic_args) = pair; - let r = if let Some(self_ty_idx) = - is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) - { + let r = if let Some(self_ty_idx) = is_dyn_method( + self.interner, + self.trait_env.clone(), + def, + generic_args.to_nextsolver(self.interner), + ) { MirOrDynIndex::Dyn(self_ty_idx) } else { - let (imp, generic_args) = - self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args.clone()); + let (imp, generic_args) = self.db.lookup_impl_method( + self.trait_env.clone(), + def, + generic_args.to_nextsolver(self.interner), + ); let mir_body = self .db - .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone()) + .monomorphized_mir_body( + imp.into(), + generic_args.to_chalk(self.interner), + self.trait_env.clone(), + ) .map_err(|e| { MirEvalError::InFunction( Box::new(MirEvalError::MirLowerError(imp, e)), @@ -2641,7 +2682,7 @@ impl<'db> Evaluator<'db> { destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let interner = DbInterner::new_with(self.db, None, None); if self.detect_and_exec_special_function( def, @@ -2713,7 +2754,7 @@ impl<'db> Evaluator<'db> { span: MirSpan, destination: Interval, target_bb: Option, - ) -> Result> { + ) -> Result<'db, Option> { Ok(if let Some(target_bb) = target_bb { let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&mir_body, Some(destination))?; @@ -2741,7 +2782,7 @@ impl<'db> Evaluator<'db> { destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let interner = DbInterner::new_with(self.db, None, None); let func = args .first() @@ -2817,7 +2858,7 @@ impl<'db> Evaluator<'db> { } } - fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result
{ + fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> { if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; @@ -2828,8 +2869,9 @@ impl<'db> Evaluator<'db> { })?; self.allocate_const_in_heap(locals, &konst)? } else { - let ty = &self.db.infer(st.into())[self.db.body(st.into()).body_expr]; - let Some((size, align)) = self.size_align_of(ty, locals)? else { + let ty = + self.db.infer(st.into())[self.db.body(st.into()).body_expr].to_chalk(self.interner); + let Some((size, align)) = self.size_align_of(&ty, locals)? else { not_supported!("unsized extern static"); }; let addr = self.heap_allocate(size, align)?; @@ -2841,7 +2883,7 @@ impl<'db> Evaluator<'db> { Ok(addr) } - fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result { + fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let r = self.db.const_eval_discriminant(variant); match r { Ok(r) => Ok(r), @@ -2863,7 +2905,7 @@ impl<'db> Evaluator<'db> { } } - fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> { + fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<'db, ()> { let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; if !locals.drop_flags.remove_place(place, &locals.body.projection_store) { return Ok(()); @@ -2882,7 +2924,7 @@ impl<'db> Evaluator<'db> { addr: Address, _metadata: &[u8], span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { let Some(drop_fn) = (|| { let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?; drop_trait.trait_items(self.db).method_by_name(&Name::new_symbol_root(sym::drop)) @@ -2962,22 +3004,22 @@ impl<'db> Evaluator<'db> { Ok(()) } - fn write_to_stdout(&mut self, interval: Interval) -> Result<()> { + fn write_to_stdout(&mut self, interval: Interval) -> Result<'db, ()> { self.stdout.extend(interval.get(self)?.to_vec()); Ok(()) } - fn write_to_stderr(&mut self, interval: Interval) -> Result<()> { + fn write_to_stderr(&mut self, interval: Interval) -> Result<'db, ()> { self.stderr.extend(interval.get(self)?.to_vec()); Ok(()) } } -pub fn render_const_using_debug_impl( - db: &dyn HirDatabase, +pub fn render_const_using_debug_impl<'db>( + db: &'db dyn HirDatabase, owner: DefWithBodyId, c: &Const, -) -> Result { +) -> Result<'db, String> { let interner = DbInterner::new_with(db, None, None); let mut evaluator = Evaluator::new(db, owner, false, None)?; let locals = &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 bb0d1f70fbb29..4653610eddda1 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 @@ -49,7 +49,7 @@ macro_rules! not_supported { }; } -impl Evaluator<'_> { +impl<'db> Evaluator<'db> { pub(super) fn detect_and_exec_special_function( &mut self, def: FunctionId, @@ -58,7 +58,7 @@ impl Evaluator<'_> { locals: &Locals, destination: Interval, span: MirSpan, - ) -> Result { + ) -> Result<'db, bool> { if self.not_special_fn_cache.borrow().contains(&def) { return Ok(false); } @@ -142,7 +142,7 @@ impl Evaluator<'_> { pub(super) fn detect_and_redirect_special_function( &mut self, def: FunctionId, - ) -> Result> { + ) -> Result<'db, Option> { // `PanicFmt` is redirected to `ConstPanicFmt` if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) { let resolver = CrateRootModuleId::from(self.crate_id).resolver(self.db); @@ -166,8 +166,8 @@ impl Evaluator<'_> { locals: &Locals, destination: Interval, span: MirSpan, - ) -> Result<()> { - let interner = DbInterner::new_with(self.db, None, None); + ) -> Result<'db, ()> { + let interner = self.interner; match self_ty.kind(Interner) { TyKind::Function(_) => { let [arg] = args else { @@ -184,9 +184,12 @@ impl Evaluator<'_> { let addr = Address::from_bytes(arg.get(self)?)?; 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 (captures, _) = infer.closure_info((*id).into()); let layout = self.layout(self_ty.to_nextsolver(interner))?; - let ty_iter = captures.iter().map(|c| c.ty(self.db, subst)); + let db = self.db; + let ty_iter = captures + .iter() + .map(|c| c.ty(db, subst.to_nextsolver(interner)).to_chalk(interner)); self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?; } TyKind::Tuple(_, subst) => { @@ -222,7 +225,7 @@ impl Evaluator<'_> { locals: &Locals, destination: Interval, span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { let interner = DbInterner::new_with(self.db, None, None); for (i, ty) in ty_iter.enumerate() { let size = self.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); @@ -250,7 +253,7 @@ impl Evaluator<'_> { alloc_fn: &Symbol, args: &[IntervalAndTy], destination: Interval, - ) -> Result<()> { + ) -> Result<'db, ()> { match alloc_fn { _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => { let [size, align] = args else { @@ -314,7 +317,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], locals: &Locals, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Vec> { use LangItem::*; let mut args = args.iter(); match it { @@ -391,7 +394,7 @@ impl Evaluator<'_> { destination: Interval, _locals: &Locals, _span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { match id { 318 => { // SYS_getrandom @@ -422,7 +425,7 @@ impl Evaluator<'_> { destination: Interval, locals: &Locals, span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { match as_str { "memcmp" => { let [ptr1, ptr2, size] = args else { @@ -589,7 +592,7 @@ impl Evaluator<'_> { locals: &Locals, span: MirSpan, needs_override: bool, - ) -> Result { + ) -> Result<'db, bool> { let interner = DbInterner::new_with(self.db, None, None); if let Some(name) = name.strip_prefix("atomic_") { return self @@ -1405,7 +1408,7 @@ impl Evaluator<'_> { ty: &Ty, metadata: Interval, locals: &Locals, - ) -> Result<(usize, usize)> { + ) -> Result<'db, (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), @@ -1461,7 +1464,7 @@ impl Evaluator<'_> { destination: Interval, locals: &Locals, _span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { 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. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index f554772904537..8e62c764b99bc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -22,8 +22,8 @@ macro_rules! not_supported { }; } -impl Evaluator<'_> { - fn detect_simd_ty(&self, ty: &Ty) -> Result<(usize, Ty)> { +impl<'db> Evaluator<'db> { + fn detect_simd_ty(&self, ty: &Ty) -> Result<'db, (usize, Ty)> { match ty.kind(Interner) { TyKind::Adt(id, subst) => { let len = match subst.as_slice(Interner).get(1).and_then(|it| it.constant(Interner)) @@ -74,7 +74,7 @@ impl Evaluator<'_> { destination: Interval, _locals: &Locals, _span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { match name { "and" | "or" | "xor" => { let [left, right] = args else { 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 2a6e3a147a7d7..9e948d1b43c7a 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 @@ -11,7 +11,7 @@ use crate::{ use super::{MirEvalError, interpret_mir}; -fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError> { +fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { salsa::attach(db, || { let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); @@ -114,7 +114,7 @@ fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: fn check_error_with( #[rust_analyzer::rust_fixture] ra_fixture: &str, - expect_err: impl FnOnce(MirEvalError) -> bool, + expect_err: impl FnOnce(MirEvalError<'_>) -> bool, ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); salsa::attach(&db, || { 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 3e44e8c68ddaa..ec7bff708297d 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 @@ -20,6 +20,7 @@ use hir_expand::name::Name; use la_arena::ArenaMap; use rustc_apfloat::Float; use rustc_hash::FxHashMap; +use rustc_type_ir::inherent::IntoKind; use span::{Edition, FileId}; use syntax::TextRange; use triomphe::Arc; @@ -74,24 +75,25 @@ struct DropScope { locals: Vec, } -struct MirLowerCtx<'db> { +struct MirLowerCtx<'a, 'db> { result: MirBody, owner: DefWithBodyId, current_loop_blocks: Option, labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'db dyn HirDatabase, - body: &'db Body, - infer: &'db InferenceResult, + body: &'a Body, + infer: &'a InferenceResult<'db>, resolver: Resolver<'db>, drop_scopes: Vec, env: Arc>, + interner: DbInterner<'db>, } // FIXME: Make this smaller, its stored in database queries #[derive(Debug, Clone, PartialEq, Eq)] -pub enum MirLowerError { - ConstEvalError(Box, Box), +pub enum MirLowerError<'db> { + ConstEvalError(Box, Box>), LayoutError(LayoutError), IncompleteExpr, IncompletePattern, @@ -103,7 +105,7 @@ pub enum MirLowerError { UnresolvedField, UnsizedTemporary(Ty), MissingFunctionDefinition(DefWithBodyId, ExprId), - TypeMismatch(TypeMismatch), + TypeMismatch(TypeMismatch<'db>), HasErrors, /// This should never happen. Type mismatch should catch everything. TypeError(&'static str), @@ -128,7 +130,7 @@ struct DropScopeToken; impl DropScopeToken { fn pop_and_drop( self, - ctx: &mut MirLowerCtx<'_>, + ctx: &mut MirLowerCtx<'_, '_>, current: BasicBlockId, span: MirSpan, ) -> BasicBlockId { @@ -140,7 +142,7 @@ impl DropScopeToken { /// code. Either when the control flow is diverging (so drop code doesn't reached) or when drop is handled /// for us (for example a block that ended with a return statement. Return will drop everything, so the block shouldn't /// do anything) - fn pop_assume_dropped(self, ctx: &mut MirLowerCtx<'_>) { + fn pop_assume_dropped(self, ctx: &mut MirLowerCtx<'_, '_>) { std::mem::forget(self); ctx.pop_drop_scope_assume_dropped_internal(); } @@ -161,7 +163,7 @@ impl Drop for DropScopeToken { // } // } -impl MirLowerError { +impl MirLowerError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -248,13 +250,13 @@ macro_rules! implementation_error { }}; } -impl From for MirLowerError { +impl From for MirLowerError<'_> { fn from(value: LayoutError) -> Self { MirLowerError::LayoutError(value) } } -impl MirLowerError { +impl MirLowerError<'_> { fn unresolved_path( db: &dyn HirDatabase, p: &Path, @@ -267,14 +269,14 @@ impl MirLowerError { } } -type Result = std::result::Result; +type Result<'db, T> = std::result::Result>; -impl<'ctx> MirLowerCtx<'ctx> { +impl<'a, 'db> MirLowerCtx<'a, 'db> { fn new( - db: &'ctx dyn HirDatabase, + db: &'db dyn HirDatabase, owner: DefWithBodyId, - body: &'ctx Body, - infer: &'ctx InferenceResult, + body: &'a Body, + infer: &'a InferenceResult<'db>, ) -> Self { let mut basic_blocks = Arena::new(); let start_block = basic_blocks.alloc(BasicBlock { @@ -296,6 +298,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let resolver = owner.resolver(db); let env = db.trait_environment_for_body(owner); + let interner = DbInterner::new_with(db, Some(env.krate), env.block); MirLowerCtx { result: mir, @@ -309,10 +312,11 @@ impl<'ctx> MirLowerCtx<'ctx> { discr_temp: None, drop_scopes: vec![DropScope::default()], env, + interner, } } - fn temp(&mut self, ty: Ty, current: BasicBlockId, span: MirSpan) -> Result { + fn temp(&mut self, ty: Ty, current: BasicBlockId, span: MirSpan) -> Result<'db, LocalId> { if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { return Err(MirLowerError::UnsizedTemporary(ty)); } @@ -325,7 +329,7 @@ impl<'ctx> MirLowerCtx<'ctx> { &mut self, expr_id: ExprId, current: BasicBlockId, - ) -> Result> { + ) -> Result<'db, Option<(Operand, BasicBlockId)>> { if !self.has_adjustments(expr_id) && let Expr::Literal(l) = &self.body[expr_id] { @@ -343,8 +347,8 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id: ExprId, place: Place, current: BasicBlockId, - adjustments: &[Adjustment], - ) -> Result> { + adjustments: &[Adjustment<'db>], + ) -> Result<'db, Option> { match adjustments.split_last() { Some((last, rest)) => match &last.kind { Adjust::NeverToAny => { @@ -372,7 +376,7 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - let bk = BorrowKind::from_chalk(*m); + let bk = BorrowKind::from_rustc(*m); self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); Ok(Some(current)) } @@ -388,7 +392,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Rvalue::Cast( CastKind::PointerCoercion(*cast), Operand { kind: OperandKind::Copy(p), span: None }, - last.target.clone(), + last.target.to_chalk(self.interner), ), expr_id.into(), ); @@ -404,7 +408,7 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id: ExprId, place: Place, prev_block: BasicBlockId, - ) -> Result> { + ) -> Result<'db, Option> { if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) { return self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments); } @@ -416,7 +420,7 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id: ExprId, place: Place, mut current: BasicBlockId, - ) -> Result> { + ) -> Result<'db, Option> { match &self.body[expr_id] { Expr::OffsetOf(_) => { not_supported!("builtin#offset_of") @@ -443,7 +447,7 @@ impl<'ctx> MirLowerCtx<'ctx> { c.into(), current, place, - subst, + subst.to_chalk(self.interner), expr_id.into(), self.expr_ty_without_adjust(expr_id), )?; @@ -511,12 +515,12 @@ impl<'ctx> MirLowerCtx<'ctx> { ValueNs::EnumVariantId(variant_id) => { let variant_fields = variant_id.fields(self.db); if variant_fields.shape == FieldsShape::Unit { - let ty = self.infer.type_of_expr[expr_id].clone(); + let ty = self.infer.type_of_expr[expr_id]; current = self.lower_enum_variant( variant_id, current, place, - ty, + ty.to_chalk(self.interner), Box::new([]), expr_id.into(), )?; @@ -651,7 +655,7 @@ impl<'ctx> MirLowerCtx<'ctx> { if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { let ty = chalk_ir::TyKind::FnDef( CallableDefId::FunctionId(func_id).to_chalk(self.db), - generic_args, + generic_args.to_chalk(self.interner), ) .intern(Interner); let func = Operand::from_bytes(Box::default(), ty); @@ -710,7 +714,7 @@ impl<'ctx> MirLowerCtx<'ctx> { method_name.display(self.db, self.edition()).to_string(), ) })?; - let func = Operand::from_fn(self.db, func_id, generic_args); + let func = Operand::from_fn(self.db, func_id, generic_args.to_chalk(self.interner)); self.lower_call_and_args( func, iter::once(*receiver).chain(args.iter().copied()), @@ -948,8 +952,8 @@ impl<'ctx> MirLowerCtx<'ctx> { let rvalue = if self.infer.coercion_casts.contains(expr) { Rvalue::Use(it) } else { - let source_ty = self.infer[*expr].clone(); - let target_ty = self.infer[expr_id].clone(); + let source_ty = self.infer[*expr].to_chalk(self.interner); + let target_ty = self.infer[expr_id].to_chalk(self.interner); let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { @@ -1047,7 +1051,8 @@ impl<'ctx> MirLowerCtx<'ctx> { if !is_builtin && let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { - let func = Operand::from_fn(self.db, func_id, generic_args); + let func = + Operand::from_fn(self.db, func_id, generic_args.to_chalk(self.interner)); return self.lower_call_and_args( func, [*lhs, *rhs].into_iter(), @@ -1195,7 +1200,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }; o.ok_or(MirLowerError::UnresolvedField) }) - .collect::>()?, + .collect::>()?, ), expr_id.into(), ); @@ -1207,7 +1212,7 @@ impl<'ctx> MirLowerCtx<'ctx> { not_supported!("closure with non closure type"); }; self.result.closures.push(*id); - let (captures, _) = self.infer.closure_info(id); + let (captures, _) = self.infer.closure_info((*id).into()); let mut operands = vec![]; for capture in captures.iter() { let p = Place { @@ -1231,7 +1236,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ProjectionElem::Subslice { from, to } } ProjectionElem::OpaqueCast(it) => { - ProjectionElem::OpaqueCast(it) + ProjectionElem::OpaqueCast(it.to_chalk(self.interner)) } #[allow(unreachable_patterns)] ProjectionElem::Index(it) => match it {}, @@ -1241,9 +1246,12 @@ impl<'ctx> MirLowerCtx<'ctx> { }; match &capture.kind { CaptureKind::ByRef(bk) => { - let placeholder_subst = self.placeholder_subst(); - let tmp_ty = - capture.ty.clone().substitute(Interner, &placeholder_subst); + let placeholder_subst: crate::next_solver::GenericArgs<'db> = + self.placeholder_subst().to_nextsolver(self.interner); + let tmp_ty = capture + .ty + .instantiate(self.interner, placeholder_subst) + .to_chalk(self.interner); // FIXME: Handle more than one span. let capture_spans = capture.spans(); let tmp: Place = self.temp(tmp_ty, current, capture_spans[0])?.into(); @@ -1278,7 +1286,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current = c; Ok(Some(o)) }) - .collect::>>()? + .collect::>>()? else { return Ok(None); }; @@ -1309,7 +1317,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current = c; Ok(Some(o)) }) - .collect::>>()? + .collect::>>()? else { return Ok(None); }; @@ -1353,7 +1361,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } } - fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> { + fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<'db, ()> { if let Expr::Field { expr, name } = &self.body[expr_id] { if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) { let index = @@ -1378,7 +1386,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(()) } - fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result { + fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result<'db, Operand> { match &self.body[*loc] { Expr::Literal(l) => self.lower_literal_to_operand(ty, l), Expr::Path(c) => { @@ -1415,7 +1423,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } } - fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { + fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<'db, Operand> { let interner = DbInterner::new_with(self.db, None, None); let size = || { self.db @@ -1479,7 +1487,7 @@ impl<'ctx> MirLowerCtx<'ctx> { subst: Substitution, span: MirSpan, ty: Ty, - ) -> Result<()> { + ) -> Result<'db, ()> { let c = self.lower_const_to_operand(subst, const_id, ty)?; self.push_assignment(prev_block, place, c.into(), span); Ok(()) @@ -1490,7 +1498,7 @@ impl<'ctx> MirLowerCtx<'ctx> { subst: Substitution, const_id: GeneralConstId, ty: Ty, - ) -> Result { + ) -> Result<'db, Operand> { let c = if subst.len(Interner) != 0 { // We can't evaluate constant with substitution now, as generics are not monomorphized in lowering. intern_const_scalar(ConstScalar::UnevaluatedConst(const_id, subst), ty) @@ -1510,7 +1518,7 @@ impl<'ctx> MirLowerCtx<'ctx> { cv: Box<[u8]>, ty: Ty, span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { self.push_assignment(prev_block, place, Operand::from_bytes(cv, ty).into(), span); Ok(()) } @@ -1523,7 +1531,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ty: Ty, fields: Box<[Operand]>, span: MirSpan, - ) -> Result { + ) -> Result<'db, BasicBlockId> { let subst = match ty.kind(Interner) { TyKind::Adt(_, subst) => subst.clone(), _ => implementation_error!("Non ADT enum"), @@ -1545,7 +1553,7 @@ impl<'ctx> MirLowerCtx<'ctx> { mut current: BasicBlockId, is_uninhabited: bool, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let Some(args) = args .map(|arg| { if let Some((temp, c)) = self.lower_expr_to_some_operand(arg, current)? { @@ -1555,7 +1563,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(None) } }) - .collect::>>>()? + .collect::>>>()? else { return Ok(None); }; @@ -1570,7 +1578,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current: BasicBlockId, is_uninhabited: bool, span: MirSpan, - ) -> Result> { + ) -> Result<'db, Option> { let b = if is_uninhabited { None } else { Some(self.new_basic_block()) }; self.set_terminator( current, @@ -1600,7 +1608,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn expr_ty_without_adjust(&self, e: ExprId) -> Ty { - self.infer[e].clone() + self.infer[e].to_chalk(self.interner) } fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { @@ -1608,7 +1616,7 @@ impl<'ctx> MirLowerCtx<'ctx> { if let Some(it) = self.infer.expr_adjustments.get(&e) && let Some(it) = it.last() { - ty = Some(it.target.clone()); + ty = Some(it.target.to_chalk(self.interner)); } ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } @@ -1651,8 +1659,8 @@ impl<'ctx> MirLowerCtx<'ctx> { place: Place, label: Option, span: MirSpan, - f: impl FnOnce(&mut MirLowerCtx<'_>, BasicBlockId) -> Result<()>, - ) -> Result> { + f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId) -> Result<'db, ()>, + ) -> Result<'db, Option> { let begin = self.new_basic_block(); let prev = self.current_loop_blocks.replace(LoopBlocks { begin, @@ -1703,7 +1711,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } } - fn current_loop_end(&mut self) -> Result { + fn current_loop_end(&mut self) -> Result<'db, BasicBlockId> { let r = match self .current_loop_blocks .as_mut() @@ -1730,7 +1738,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn is_uninhabited(&self, expr_id: ExprId) -> bool { is_ty_uninhabited_from( self.db, - &self.infer[expr_id], + &self.infer[expr_id].to_chalk(self.interner), self.owner.module(self.db), self.env.clone(), ) @@ -1738,7 +1746,7 @@ impl<'ctx> MirLowerCtx<'ctx> { /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and /// `Drop` in the appropriated places. - fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> { + fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<'db, ()> { let l = self.binding_local(b)?; self.push_storage_live_for_local(l, current, MirSpan::BindingId(b)) } @@ -1748,13 +1756,13 @@ impl<'ctx> MirLowerCtx<'ctx> { l: LocalId, current: BasicBlockId, span: MirSpan, - ) -> Result<()> { + ) -> Result<'db, ()> { self.drop_scopes.last_mut().unwrap().locals.push(l); self.push_statement(current, StatementKind::StorageLive(l).with_span(span)); Ok(()) } - fn resolve_lang_item(&self, item: LangItem) -> Result { + fn resolve_lang_item(&self, item: LangItem) -> Result<'db, LangItemTarget> { let crate_id = self.owner.module(self.db).krate(); lang_item(self.db, crate_id, item).ok_or(MirLowerError::LangItemNotFound(item)) } @@ -1766,7 +1774,7 @@ impl<'ctx> MirLowerCtx<'ctx> { tail: Option, place: Place, span: MirSpan, - ) -> Result>> { + ) -> Result<'db, Option>> { let scope = self.push_drop_scope(); for statement in statements.iter() { match statement { @@ -1842,7 +1850,7 @@ impl<'ctx> MirLowerCtx<'ctx> { params: impl Iterator + Clone, self_binding: Option<(BindingId, Ty)>, pick_binding: impl Fn(BindingId) -> bool, - ) -> Result { + ) -> Result<'db, BasicBlockId> { let base_param_count = self.result.param_locals.len(); let self_binding = match self_binding { Some((self_binding, ty)) => { @@ -1873,9 +1881,10 @@ impl<'ctx> MirLowerCtx<'ctx> { continue; } if !self.result.binding_locals.contains_idx(id) { - self.result - .binding_locals - .insert(id, self.result.locals.alloc(Local { ty: self.infer[id].clone() })); + self.result.binding_locals.insert( + id, + self.result.locals.alloc(Local { ty: self.infer[id].to_chalk(self.interner) }), + ); } } let mut current = self.result.start_block; @@ -1910,7 +1919,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(current) } - fn binding_local(&self, b: BindingId) -> Result { + fn binding_local(&self, b: BindingId) -> Result<'db, LocalId> { match self.result.binding_locals.get(b) { Some(it) => Ok(*it), None => { @@ -1922,7 +1931,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } } - fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result { + fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let r = self.db.const_eval_discriminant(variant); match r { Ok(r) => Ok(r), @@ -1993,7 +2002,7 @@ impl<'ctx> MirLowerCtx<'ctx> { &mut self, mut current: BasicBlockId, span: MirSpan, - ) -> Result { + ) -> Result<'db, BasicBlockId> { current = self.pop_drop_scope_internal(current, span); if !self.drop_scopes.is_empty() { implementation_error!("Mismatched count between drop scope push and pops"); @@ -2021,9 +2030,14 @@ impl<'ctx> MirLowerCtx<'ctx> { } } -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); +fn cast_kind<'db>( + db: &'db dyn HirDatabase, + source_ty: &Ty, + target_ty: &Ty, +) -> Result<'db, CastKind> { + let interner = DbInterner::new_with(db, None, None); + let from = CastTy::from_ty(db, source_ty.to_nextsolver(interner)); + let cast = CastTy::from_ty(db, target_ty.to_nextsolver(interner)); Ok(match (from, cast) { (Some(CastTy::Ptr(..) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress @@ -2039,31 +2053,34 @@ fn cast_kind(db: &dyn HirDatabase, source_ty: &Ty, target_ty: &Ty) -> Result( + db: &'db dyn HirDatabase, closure: InternedClosureId, -) -> Result> { +) -> Result<'db, Arc> { let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); let body = db.body(owner); let infer = db.infer(owner); let Expr::Closure { args, body: root, .. } = &body[expr] else { implementation_error!("closure expression is not closure"); }; - let TyKind::Closure(_, substs) = &infer[expr].kind(Interner) else { + let crate::next_solver::TyKind::Closure(_, substs) = infer[expr].kind() else { implementation_error!("closure expression is not closure"); }; - let (captures, kind) = infer.closure_info(&closure.into()); + let (captures, kind) = infer.closure_info(closure); let mut ctx = MirLowerCtx::new(db, owner, &body, &infer); + let substs: &Substitution = &substs.to_chalk(ctx.interner); // 0 is return local - ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); + ctx.result.locals.alloc(Local { ty: infer[*root].to_chalk(ctx.interner) }); let closure_local = ctx.result.locals.alloc(Local { ty: match kind { - FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].clone(), + FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].to_chalk(ctx.interner), FnTrait::FnMut | FnTrait::AsyncFnMut => { - TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].clone()).intern(Interner) + TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].to_chalk(ctx.interner)) + .intern(Interner) } FnTrait::Fn | FnTrait::AsyncFn => { - TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].clone()).intern(Interner) + TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].to_chalk(ctx.interner)) + .intern(Interner) } }, }); @@ -2082,7 +2099,7 @@ pub fn mir_body_for_closure_query( let current = ctx.pop_drop_scope_assert_finished(current, root.into())?; ctx.set_terminator(current, TerminatorKind::Return, (*root).into()); } - let mut upvar_map: FxHashMap> = FxHashMap::default(); + let mut upvar_map: FxHashMap, usize)>> = FxHashMap::default(); for (i, capture) in captures.iter().enumerate() { let local = ctx.binding_local(capture.place.local)?; upvar_map.entry(local).or_default().push((capture, i)); @@ -2144,7 +2161,10 @@ pub fn mir_body_for_closure_query( Ok(Arc::new(ctx.result)) } -pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result> { +pub fn mir_body_query<'db>( + db: &'db dyn HirDatabase, + def: DefWithBodyId, +) -> Result<'db, Arc> { let krate = def.krate(db); let edition = krate.data(db).edition; let detail = match def { @@ -2177,22 +2197,22 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result( + _db: &'db dyn HirDatabase, _def: DefWithBodyId, -) -> Result> { +) -> Result<'db, Arc> { Err(MirLowerError::Loop) } -pub fn lower_to_mir( - db: &dyn HirDatabase, +pub fn lower_to_mir<'db>( + db: &'db dyn HirDatabase, owner: DefWithBodyId, body: &Body, - infer: &InferenceResult, + infer: &InferenceResult<'db>, // FIXME: root_expr should always be the body.body_expr, but since `X` in `[(); X]` doesn't have its own specific body yet, we // need to take this input explicitly. root_expr: ExprId, -) -> Result { +) -> Result<'db, MirBody> { if infer.type_mismatches().next().is_some() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 42a14664626f0..bd7b644618e7a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -12,12 +12,12 @@ macro_rules! not_supported { }; } -impl MirLowerCtx<'_> { +impl<'db> MirLowerCtx<'_, 'db> { fn lower_expr_to_some_place_without_adjust( &mut self, expr_id: ExprId, prev_block: BasicBlockId, - ) -> Result> { + ) -> Result<'db, Option<(Place, BasicBlockId)>> { let ty = self.expr_ty_without_adjust(expr_id); let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = @@ -32,11 +32,11 @@ impl MirLowerCtx<'_> { &mut self, expr_id: ExprId, prev_block: BasicBlockId, - adjustments: &[Adjustment], - ) -> Result> { + adjustments: &[Adjustment<'db>], + ) -> Result<'db, Option<(Place, BasicBlockId)>> { let ty = adjustments .last() - .map(|it| it.target.clone()) + .map(|it| it.target.to_chalk(self.interner)) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = @@ -52,9 +52,9 @@ impl MirLowerCtx<'_> { current: BasicBlockId, expr_id: ExprId, upgrade_rvalue: bool, - adjustments: &[Adjustment], - ) -> Result> { - let try_rvalue = |this: &mut MirLowerCtx<'_>| { + adjustments: &[Adjustment<'db>], + ) -> Result<'db, Option<(Place, BasicBlockId)>> { + let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); } @@ -89,11 +89,11 @@ impl MirLowerCtx<'_> { current, r, rest.last() - .map(|it| it.target.clone()) + .map(|it| it.target.to_chalk(self.interner)) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)), - last.target.clone(), + last.target.to_chalk(self.interner), expr_id.into(), - match od.0 { + match od.0.to_chalk(self.interner) { Some(Mutability::Mut) => true, Some(Mutability::Not) => false, None => { @@ -114,7 +114,7 @@ impl MirLowerCtx<'_> { current: BasicBlockId, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result> { + ) -> Result<'db, Option<(Place, BasicBlockId)>> { match self.infer.expr_adjustments.get(&expr_id) { Some(a) => self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a), None => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue), @@ -126,8 +126,8 @@ impl MirLowerCtx<'_> { current: BasicBlockId, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result> { - let try_rvalue = |this: &mut MirLowerCtx<'_>| { + ) -> Result<'db, Option<(Place, BasicBlockId)>> { + let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); } @@ -230,6 +230,7 @@ impl MirLowerCtx<'_> { "[overloaded index]".to_owned(), )); }; + let index_fn = (index_fn.0, index_fn.1.to_chalk(self.interner)); let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else { @@ -285,7 +286,7 @@ impl MirLowerCtx<'_> { index_operand: Operand, span: MirSpan, index_fn: (FunctionId, Substitution), - ) -> Result> { + ) -> Result<'db, Option<(Place, BasicBlockId)>> { let mutability = match base_ty.as_reference() { Some((_, _, mutability)) => mutability, None => Mutability::Not, @@ -319,7 +320,7 @@ impl MirLowerCtx<'_> { target_ty: Ty, span: MirSpan, mutability: bool, - ) -> Result> { + ) -> Result<'db, Option<(Place, BasicBlockId)>> { let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability { ( Mutability::Not, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 0440d85022321..359c4fbb2e052 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -2,16 +2,17 @@ use hir_def::{AssocItemId, hir::ExprId, signatures::VariantFields}; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ BindingMode, mir::{ LocalId, MutBorrowKind, Operand, OperandKind, lower::{ BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner, - MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Pat, PatId, Place, - PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, - Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, - ValueNs, VariantId, + MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem, + ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, Substitution, + SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs, + VariantId, }, }, }; @@ -50,7 +51,7 @@ enum MatchingMode { Assign, } -impl MirLowerCtx<'_> { +impl<'db> MirLowerCtx<'_, 'db> { /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which /// can be the `current` block) and one for the mismatched path. If the input pattern is irrefutable, the @@ -66,7 +67,7 @@ impl MirLowerCtx<'_> { current_else: Option, cond_place: Place, pattern: PatId, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { let (current, current_else) = self.pattern_match_inner( current, current_else, @@ -89,7 +90,7 @@ impl MirLowerCtx<'_> { current: BasicBlockId, value: Place, pattern: PatId, - ) -> Result { + ) -> Result<'db, BasicBlockId> { let (current, _) = self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?; Ok(current) @@ -100,7 +101,7 @@ impl MirLowerCtx<'_> { id: BindingId, current: BasicBlockId, local: LocalId, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { self.pattern_match_binding( id, BindingMode::Move, @@ -118,7 +119,7 @@ impl MirLowerCtx<'_> { mut cond_place: Place, pattern: PatId, mode: MatchingMode, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); cond_place.projection = self.result.projection_store.intern( cond_place @@ -134,8 +135,8 @@ impl MirLowerCtx<'_> { Pat::Missing => return Err(MirLowerError::IncompletePattern), Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { - let subst = match self.infer[pattern].kind(Interner) { - TyKind::Tuple(_, s) => s, + let subst = match self.infer[pattern].to_chalk(self.interner).kind(Interner) { + TyKind::Tuple(_, s) => s.clone(), _ => { return Err(MirLowerError::TypeError( "non tuple type matched with tuple pattern", @@ -207,9 +208,11 @@ impl MirLowerCtx<'_> { )? } Pat::Range { start, end } => { - let mut add_check = |l: &ExprId, binop| -> Result<()> { - let lv = - self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?; + let mut add_check = |l: &ExprId, binop| -> Result<'db, ()> { + let lv = self.lower_literal_or_const_to_operand( + self.infer[pattern].to_chalk(self.interner), + l, + )?; let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); let next = self.new_basic_block(); let discr: Place = @@ -249,7 +252,9 @@ impl MirLowerCtx<'_> { Pat::Slice { prefix, slice, suffix } => { if mode == MatchingMode::Check { // emit runtime length check for slice - if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) { + if let TyKind::Slice(_) = + self.infer[pattern].to_chalk(self.interner).kind(Interner) + { let pattern_len = prefix.len() + suffix.len(); let place_len: Place = self.temp(TyBuilder::usize(), current, pattern.into())?.into(); @@ -393,15 +398,16 @@ impl MirLowerCtx<'_> { if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) && let AssocItemId::ConstId(c) = x.0 { - break 'b (c, x.1); + break 'b (c, x.1.to_chalk(self.interner)); } if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr { break 'b (c, Substitution::empty(Interner)); } not_supported!("path in pattern position that is not const or variant") }; - let tmp: Place = - self.temp(self.infer[pattern].clone(), current, pattern.into())?.into(); + let tmp: Place = self + .temp(self.infer[pattern].to_chalk(self.interner), current, pattern.into())? + .into(); let span = pattern.into(); self.lower_const( c.into(), @@ -409,7 +415,7 @@ impl MirLowerCtx<'_> { tmp, subst, span, - self.infer[pattern].clone(), + self.infer[pattern].to_chalk(self.interner), )?; let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); self.push_assignment( @@ -438,7 +444,10 @@ impl MirLowerCtx<'_> { Pat::Lit(l) => match &self.body[*l] { Expr::Literal(l) => { if mode == MatchingMode::Check { - let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?; + let c = self.lower_literal_to_operand( + self.infer[pattern].to_chalk(self.interner), + l, + )?; self.pattern_match_const(current_else, current, c, cond_place, pattern)? } else { (current, current_else) @@ -514,7 +523,7 @@ impl MirLowerCtx<'_> { span: MirSpan, current: BasicBlockId, current_else: Option, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { let target_place = self.binding_local(id)?; self.push_storage_live(id, current)?; self.push_match_assignment(current, target_place, mode, cond_place, span); @@ -536,8 +545,10 @@ impl MirLowerCtx<'_> { BindingMode::Move => { Operand { kind: OperandKind::Copy(cond_place), span: None }.into() } - BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place), - BindingMode::Ref(Mutability::Mut) => { + BindingMode::Ref(rustc_ast_ir::Mutability::Not) => { + Rvalue::Ref(BorrowKind::Shared, cond_place) + } + BindingMode::Ref(rustc_ast_ir::Mutability::Mut) => { Rvalue::Ref(BorrowKind::Mut { kind: MutBorrowKind::Default }, cond_place) } }, @@ -552,7 +563,7 @@ impl MirLowerCtx<'_> { c: Operand, cond_place: Place, pattern: Idx, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { let then_target = self.new_basic_block(); let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); let discr: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); @@ -587,7 +598,7 @@ impl MirLowerCtx<'_> { mut current_else: Option, shape: AdtPatternShape<'_>, mode: MatchingMode, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { Ok(match variant { VariantId::EnumVariantId(v) => { if mode == MatchingMode::Check { @@ -640,7 +651,7 @@ impl MirLowerCtx<'_> { current_else: Option, cond_place: &Place, mode: MatchingMode, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { Ok(match shape { AdtPatternShape::Record { args } => { let it = args @@ -656,7 +667,7 @@ impl MirLowerCtx<'_> { x.pat, )) }) - .collect::>>()?; + .collect::>>()?; self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)? } AdtPatternShape::Tuple { args, ellipsis } => { @@ -684,7 +695,7 @@ impl MirLowerCtx<'_> { args: impl Iterator, cond_place: &Place, mode: MatchingMode, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { for (proj, arg) in args { let cond_place = cond_place.project(proj, &mut self.result.projection_store); (current, current_else) = @@ -702,7 +713,7 @@ impl MirLowerCtx<'_> { fields: impl DoubleEndedIterator + Clone, cond_place: &Place, mode: MatchingMode, - ) -> Result<(BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId, Option)> { let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); let it = al .iter() 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 index 1d7a16ed72d07..bac694eabb704 100644 --- 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 @@ -4,16 +4,11 @@ use span::Edition; use test_fixture::WithFixture; use triomphe::Arc; -use crate::{ - db::HirDatabase, - mir::{MirBody, MirLowerError}, - setup_tracing, - test_db::TestDB, -}; +use crate::{db::HirDatabase, mir::MirBody, setup_tracing, test_db::TestDB}; fn lower_mir( #[rust_analyzer::rust_fixture] ra_fixture: &str, -) -> FxHashMap, MirLowerError>> { +) -> FxHashMap, ()>> { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); @@ -28,7 +23,7 @@ fn lower_mir( .map(|func| { let name = db.function_signature(func).name.display(&db, Edition::CURRENT).to_string(); let mir = db.mir_body(func.into()); - (name, mir) + (name, mir.map_err(drop)) }) .collect() } 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 f293f38c76980..4bc81a4806ec6 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 @@ -16,6 +16,8 @@ use chalk_ir::{ use hir_def::DefWithBodyId; use triomphe::Arc; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, consteval::{intern_const_scalar, unknown_const}, @@ -33,14 +35,15 @@ macro_rules! not_supported { }; } -struct Filler<'a> { - db: &'a dyn HirDatabase, - trait_env: Arc>, +struct Filler<'a, 'db> { + db: &'db dyn HirDatabase, + trait_env: Arc>, subst: &'a Substitution, generics: Option, + interner: DbInterner<'db>, } -impl FallibleTypeFolder for Filler<'_> { - type Error = MirLowerError; +impl<'a, 'db> FallibleTypeFolder for Filler<'a, 'db> { + type Error = MirLowerError<'db>; fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { self @@ -80,8 +83,13 @@ impl FallibleTypeFolder for Filler<'_> { trait_env: self.trait_env.clone(), subst: &subst, generics: Some(generics(self.db, func.into())), + interner: self.interner, }; - filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder) + filler.try_fold_ty( + infer.type_of_rpit[idx.to_nextsolver(self.interner)] + .to_chalk(self.interner), + outer_binder, + ) } crate::ImplTraitId::TypeAliasImplTrait(..) => { not_supported!("type alias impl trait"); @@ -148,8 +156,8 @@ impl FallibleTypeFolder for Filler<'_> { } } -impl Filler<'_> { - fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError> { +impl<'a, 'db> Filler<'a, 'db> { + fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError<'db>> { let tmp = mem::replace(ty, TyKind::Error.intern(Interner)); *ty = normalize( self.db, @@ -159,19 +167,19 @@ impl Filler<'_> { Ok(()) } - fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError> { + fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError<'db>> { let tmp = mem::replace(c, unknown_const(c.data(Interner).ty.clone())); *c = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; Ok(()) } - fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError> { + fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError<'db>> { let tmp = mem::replace(ty, Substitution::empty(Interner)); *ty = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; Ok(()) } - fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { + fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> { match &mut op.kind { OperandKind::Constant(c) => { match &c.data(Interner).value { @@ -222,7 +230,7 @@ impl Filler<'_> { Ok(()) } - fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> { + fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError<'db>> { for (_, l) in body.locals.iter_mut() { self.fill_ty(&mut l.ty)?; } @@ -306,9 +314,10 @@ pub fn monomorphized_mir_body_query<'db>( owner: DefWithBodyId, subst: Substitution, trait_env: Arc>, -) -> Result, MirLowerError> { +) -> Result, MirLowerError<'db>> { 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 }; + let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); + let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner }; let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; @@ -320,7 +329,7 @@ pub(crate) fn monomorphized_mir_body_cycle_result<'db>( _: DefWithBodyId, _: Substitution, _: Arc>, -) -> Result, MirLowerError> { +) -> Result, MirLowerError<'db>> { Err(MirLowerError::Loop) } @@ -329,10 +338,11 @@ pub fn monomorphized_mir_body_for_closure_query<'db>( closure: InternedClosureId, subst: Substitution, trait_env: Arc>, -) -> Result, MirLowerError> { +) -> Result, MirLowerError<'db>> { 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 }; + let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); + let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner }; let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut 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 ab167e88af2ef..776e0d956f404 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 @@ -33,6 +33,9 @@ pub use region::*; pub use solver::*; pub use ty::*; +pub use crate::lower_nextsolver::ImplTraitIdx; +pub use rustc_ast_ir::Mutability; + pub type Binder<'db, T> = 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>; 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 1ae59beca2728..918a311ea9ccc 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 @@ -139,6 +139,17 @@ impl TryFrom for GenericDefId { } } +impl SolverDefId { + #[inline] + #[track_caller] + pub fn expect_opaque_ty(self) -> InternedOpaqueTyId { + match self { + SolverDefId::InternedOpaqueTyId(it) => it, + _ => panic!("expected opaque type, found {self:?}"), + } + } +} + impl<'db> inherent::DefId> for SolverDefId { fn as_local(self) -> Option { Some(self) 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 405a57d9e898c..a42fdb0943041 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 @@ -129,3 +129,26 @@ where if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } } + +pub fn fold_tys<'db, T: TypeFoldable>>( + interner: DbInterner<'db>, + t: T, + callback: impl FnMut(Ty<'db>) -> Ty<'db>, +) -> T { + struct Folder<'db, F> { + interner: DbInterner<'db>, + callback: F, + } + impl<'db, F: FnMut(Ty<'db>) -> Ty<'db>> TypeFolder> for Folder<'db, F> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + let t = t.super_fold_with(self); + (self.callback)(t) + } + } + + t.fold_with(&mut Folder { interner, callback }) +} 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 097bb85cbd491..89a4d9202a75d 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,7 +1,8 @@ //! Things related to generic args in the next-trait-solver. -use hir_def::GenericParamId; +use hir_def::{GenericDefId, GenericParamId}; use intern::{Interned, Symbol}; +use rustc_type_ir::inherent::Const as _; use rustc_type_ir::{ ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable, @@ -216,6 +217,59 @@ impl<'db> GenericArgs<'db> { interner.mk_args(&args) } + /// Like `for_item`, but prefers the default of a parameter if it has any. + pub fn for_item_with_defaults( + interner: DbInterner<'db>, + def_id: GenericDefId, + mut fallback: F, + ) -> GenericArgs<'db> + where + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let defaults = interner.db.generic_defaults_ns(def_id); + Self::for_item(interner, def_id.into(), |name, idx, id, prev| { + match defaults.get(idx as usize) { + Some(default) => default.instantiate(interner, prev), + None => fallback(name, idx, id, prev), + } + }) + } + + /// Like `for_item()`, but calls first uses the args from `first`. + pub fn fill_rest( + interner: DbInterner<'db>, + def_id: SolverDefId, + first: impl IntoIterator>, + mut fallback: F, + ) -> GenericArgs<'db> + where + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let mut iter = first.into_iter(); + Self::for_item(interner, def_id, |name, idx, id, prev| { + iter.next().unwrap_or_else(|| fallback(name, idx, id, prev)) + }) + } + + /// Appends default param values to `first` if needed. Params without default will call `fallback()`. + pub fn fill_with_defaults( + interner: DbInterner<'db>, + def_id: GenericDefId, + first: impl IntoIterator>, + mut fallback: F, + ) -> GenericArgs<'db> + where + F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + { + let defaults = interner.db.generic_defaults_ns(def_id); + Self::fill_rest(interner, def_id.into(), first, |name, idx, id, prev| { + defaults + .get(idx as usize) + .map(|default| default.instantiate(interner, prev)) + .unwrap_or_else(|| fallback(name, idx, id, prev)) + }) + } + fn fill_item( args: &mut SmallVec<[GenericArg<'db>; 8]>, interner: DbInterner<'_>, @@ -271,6 +325,18 @@ impl<'db> GenericArgs<'db> { } } } + + pub fn types(self) -> impl Iterator> { + self.iter().filter_map(|it| it.as_type()) + } + + pub fn consts(self) -> impl Iterator> { + self.iter().filter_map(|it| it.as_const()) + } + + pub fn regions(self) -> impl Iterator> { + self.iter().filter_map(|it| it.as_region()) + } } impl<'db> rustc_type_ir::relate::Relate> for GenericArgs<'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 8e922abacb206..1bb6934e073ed 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 @@ -10,6 +10,7 @@ pub use at::DefineOpaqueTypes; use ena::undo_log::UndoLogs; use ena::unify as ut; use hir_def::GenericParamId; +use hir_def::lang_item::LangItem; use intern::Symbol; use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage}; use region_constraints::{ @@ -18,6 +19,7 @@ use region_constraints::{ pub use relate::StructurallyRelateAliases; pub use relate::combine::PredicateEmittingRelation; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_pattern_analysis::Captures; use rustc_type_ir::error::{ExpectedFound, TypeError}; use rustc_type_ir::inherent::{ @@ -38,7 +40,10 @@ 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::{BoundConst, BoundRegion, BoundTy, BoundVarKind}; +use crate::next_solver::infer::select::EvaluationResult; +use crate::next_solver::infer::traits::PredicateObligation; +use crate::next_solver::obligation_ctxt::ObligationCtxt; +use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext}; use super::generics::GenericParamDef; use super::{ @@ -62,7 +67,7 @@ pub(crate) mod traits; mod type_variable; mod unify_key; -/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper +/// `InferOk<'db, ()>` 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 @@ -395,6 +400,102 @@ impl<'db> InferCtxt<'db> { self.typing_mode } + /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank) + /// for more details. + pub fn predicate_may_hold_opaque_types_jank( + &self, + obligation: &PredicateObligation<'db>, + ) -> bool { + <&SolverContext<'db>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new( + self.interner, + obligation.param_env, + obligation.predicate, + )) + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + /// + /// This version may conservatively fail when outlives obligations + /// are required. Therefore, this version should only be used for + /// optimizations or diagnostics and be treated as if it can always + /// return `false`. + /// + /// # Example + /// + /// ``` + /// # #![allow(dead_code)] + /// trait Trait {} + /// + /// fn check() {} + /// + /// fn foo() + /// where + /// &'static T: Trait, + /// { + /// // Evaluating `&'?0 T: Trait` adds a `'?0: 'static` outlives obligation, + /// // which means that `predicate_must_hold_considering_regions` will return + /// // `false`. + /// check::<&'_ T>(); + /// } + /// ``` + fn predicate_must_hold_considering_regions( + &self, + obligation: &PredicateObligation<'db>, + ) -> bool { + self.evaluate_obligation(obligation).must_apply_considering_regions() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + /// + /// This version ignores all outlives constraints. + fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool { + self.evaluate_obligation(obligation).must_apply_modulo_regions() + } + + /// Evaluate a given predicate, capturing overflow and propagating it back. + fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult { + let param_env = obligation.param_env; + + self.probe(|snapshot| { + let mut ocx = ObligationCtxt::new(self); + ocx.register_obligation(obligation.clone()); + let mut result = EvaluationResult::EvaluatedToOk; + for error in ocx.select_all_or_error() { + if error.is_true_error() { + return EvaluationResult::EvaluatedToErr; + } else { + result = result.max(EvaluationResult::EvaluatedToAmbig); + } + } + if self.opaque_types_added_in_snapshot(snapshot) { + result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes); + } else if self.region_constraints_added_in_snapshot(snapshot) { + result = result.max(EvaluationResult::EvaluatedToOkModuloRegions); + } + result + }) + } + + pub fn type_is_copy_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool { + let ty = self.resolve_vars_if_possible(ty); + + let Some(copy_def_id) = + LangItem::Copy.resolve_trait(self.interner.db, self.interner.krate.unwrap()) + else { + return false; + }; + + // This can get called from typeck (by euv), and `moves_by_default` + // rightly refuses to work with inference variables, but + // moves_by_default has a cache, which we want to use in other + // cases. + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) + } + pub fn unresolved_variables(&self) -> Vec> { let mut inner = self.inner.borrow_mut(); let mut vars: Vec> = inner @@ -682,6 +783,17 @@ impl<'db> InferCtxt<'db> { }) } + /// Like `fresh_args_for_item()`, but first uses the args from `first`. + pub fn fill_rest_fresh_args( + &self, + def_id: SolverDefId, + first: impl IntoIterator>, + ) -> GenericArgs<'db> { + GenericArgs::fill_rest(self.interner, def_id, first, |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 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 index 84338ade6e354..4bd3fbd4985d0 100644 --- 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 @@ -2,11 +2,12 @@ use rustc_type_ir::{ ConstKind, FallibleTypeFolder, InferConst, InferTy, RegionKind, TyKind, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, data_structures::DelayedMap, - inherent::IntoKind, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, + data_structures::DelayedMap, + inherent::{Const as _, IntoKind, Ty as _}, }; -use crate::next_solver::{Const, DbInterner, Region, Ty}; +use crate::next_solver::{Const, DbInterner, ErrorGuaranteed, Region, Ty}; use super::{FixupError, FixupResult, InferCtxt}; @@ -60,3 +61,48 @@ impl<'a, 'db> TypeFolder> for OpportunisticVarResolver<'a, 'db> } } } + +pub struct ReplaceInferWithError<'db> { + interner: DbInterner<'db>, +} + +impl<'db> ReplaceInferWithError<'db> { + #[inline] + pub fn new(interner: DbInterner<'db>) -> Self { + Self { interner } + } +} + +impl<'db> TypeFolder> for ReplaceInferWithError<'db> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + if !t.has_infer() { + return t; + } + + if t.is_infer() { + Ty::new_error(self.interner, ErrorGuaranteed) + } else { + t.super_fold_with(self) + } + } + + fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { + if !c.has_infer() { + return c; + } + + if c.is_ct_infer() { + Const::new_error(self.interner, ErrorGuaranteed) + } else { + c.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if r.is_var() { Region::error(self.interner) } else { r } + } +} 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 4f111fa662668..392e2b9329a04 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 @@ -12,6 +12,7 @@ use crate::{ Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError, infer::{ InferCtxt, + select::EvaluationResult::*, traits::{Obligation, ObligationCause, PredicateObligation, TraitObligation}, }, inspect::{InspectCandidate, InspectGoal, ProofTreeVisitor}, @@ -47,6 +48,83 @@ pub enum NotConstEvaluatable { MentionsParam, } +/// The result of trait evaluation. The order is important +/// here as the evaluation of a list is the maximum of the +/// evaluations. +/// +/// The evaluation results are ordered: +/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` +/// implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent` +/// - the "union" of evaluation results is equal to their maximum - +/// all the "potential success" candidates can potentially succeed, +/// so they are noops when unioned with a definite error, and within +/// the categories it's easy to see that the unions are correct. +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub enum EvaluationResult { + /// Evaluation successful. + EvaluatedToOk, + /// Evaluation successful, but there were unevaluated region obligations. + EvaluatedToOkModuloRegions, + /// Evaluation successful, but need to rerun because opaque types got + /// hidden types assigned without it being known whether the opaque types + /// are within their defining scope + EvaluatedToOkModuloOpaqueTypes, + /// Evaluation is known to be ambiguous -- it *might* hold for some + /// assignment of inference variables, but it might not. + /// + /// While this has the same meaning as `EvaluatedToAmbigStackDependent` -- we can't + /// know whether this obligation holds or not -- it is the result we + /// would get with an empty stack, and therefore is cacheable. + EvaluatedToAmbig, + /// Evaluation failed because of recursion involving inference + /// variables. We are somewhat imprecise there, so we don't actually + /// know the real result. + /// + /// This can't be trivially cached because the result depends on the + /// stack results. + EvaluatedToAmbigStackDependent, + /// Evaluation failed. + EvaluatedToErr, +} + +impl EvaluationResult { + /// Returns `true` if this evaluation result is known to apply, even + /// considering outlives constraints. + pub fn must_apply_considering_regions(self) -> bool { + self == EvaluatedToOk + } + + /// Returns `true` if this evaluation result is known to apply, ignoring + /// outlives constraints. + pub fn must_apply_modulo_regions(self) -> bool { + self <= EvaluatedToOkModuloRegions + } + + pub fn may_apply(self) -> bool { + match self { + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToAmbigStackDependent => true, + + EvaluatedToErr => false, + } + } + + pub fn is_stack_dependent(self) -> bool { + match self { + EvaluatedToAmbigStackDependent => true, + + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToErr => false, + } + } +} + /// Indicates that trait evaluation caused overflow and in which pass. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum OverflowError { 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 7b9ca96c51406..705aa43fb1199 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 @@ -109,4 +109,17 @@ impl<'db> InferCtxt<'db> { self.rollback_to(snapshot); r } + + /// Scan the constraints produced since `snapshot` and check whether + /// we added any region constraints. + pub fn region_constraints_added_in_snapshot(&self, snapshot: &CombinedSnapshot) -> bool { + self.inner + .borrow_mut() + .unwrap_region_constraints() + .region_constraints_added_in_snapshot(&snapshot.undo_snapshot) + } + + pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot) -> bool { + self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) + } } 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 68aa12d7bb0cb..9fa1fa7fb4404 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,16 +7,18 @@ use std::{ hash::{Hash, Hasher}, }; +use hir_def::TraitId; use rustc_type_ir::elaborate::Elaboratable; use rustc_type_ir::{ PredicatePolarity, Upcast, solve::{Certainty, NoSolution}, }; use rustc_type_ir::{TypeFoldable, TypeVisitable}; +use tracing::debug; use crate::next_solver::{ Binder, Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, Span, - TraitPredicate, Ty, + TraitPredicate, TraitRef, Ty, }; use super::InferCtxt; @@ -237,3 +239,35 @@ impl<'db, O> Obligation<'db, O> { Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value) } } + +/// Determines whether the type `ty` is known to meet `bound` and +/// returns true if so. Returns false if `ty` either does not meet +/// `bound` or is not known to meet bound (note that this is +/// conservative towards *no impl*, which is the opposite of the +/// `evaluate` methods). +pub fn type_known_to_meet_bound_modulo_regions<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: TraitId, +) -> bool { + let trait_ref = TraitRef::new(infcx.interner, def_id.into(), [ty]); + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) +} + +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +fn pred_known_to_hold_modulo_regions<'db>( + infcx: &InferCtxt<'db>, + param_env: ParamEnv<'db>, + pred: impl Upcast, Predicate<'db>>, +) -> bool { + let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), param_env, pred); + + let result = infcx.evaluate_obligation(&obligation); + debug!(?result); + + result.must_apply_modulo_regions() +} 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 b72504a19cf0f..6b91ee35eba3b 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 @@ -1616,7 +1616,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { mut f: impl FnMut(Self::ImplId), ) { let trait_ = trait_.0; - let self_ty_fp = TyFingerprint::for_trait_impl_ns(&self_ty); + let self_ty_fp = TyFingerprint::for_trait_impl(self_ty); let fps: &[TyFingerprint] = match self_ty.kind() { TyKind::Infer(InferTy::IntVar(..)) => &ALL_INT_FPS, TyKind::Infer(InferTy::FloatVar(..)) => &ALL_FLOAT_FPS, @@ -1907,7 +1907,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { 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)) + EarlyBinder::bind(infer.type_of_rpit[idx.to_nextsolver(self)]) } crate::ImplTraitId::TypeAliasImplTrait(..) | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { 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 f3f74f67c04de..b32a5ec2928bf 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 @@ -143,10 +143,29 @@ pub trait ChalkToNextSolver<'db, Out> { fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out; } +impl<'db, A, OutA, B, OutB> ChalkToNextSolver<'db, (OutA, OutB)> for (A, B) +where + A: ChalkToNextSolver<'db, OutA>, + B: ChalkToNextSolver<'db, OutB>, +{ + fn to_nextsolver(&self, interner: DbInterner<'db>) -> (OutA, OutB) { + (self.0.to_nextsolver(interner), self.1.to_nextsolver(interner)) + } +} + pub trait NextSolverToChalk<'db, Out> { fn to_chalk(self, interner: DbInterner<'db>) -> Out; } +impl<'db, T, Out> NextSolverToChalk<'db, Option> for Option +where + T: NextSolverToChalk<'db, Out>, +{ + fn to_chalk(self, interner: DbInterner<'db>) -> Option { + self.map(|it| it.to_chalk(interner)) + } +} + impl NextSolverToChalk<'_, chalk_ir::Mutability> for rustc_ast_ir::Mutability { fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Mutability { match self { @@ -633,6 +652,16 @@ impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg NextSolverToChalk<'db, crate::GenericArg> for GenericArg<'db> { + fn to_chalk(self, interner: DbInterner<'db>) -> crate::GenericArg { + match self { + GenericArg::Ty(ty) => ty.to_chalk(interner).cast(Interner), + GenericArg::Lifetime(region) => region.to_chalk(interner).cast(Interner), + GenericArg::Const(konst) => konst.to_chalk(interner).cast(Interner), + } + } +} + impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution { fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> { GenericArgs::new_from_iter( @@ -642,6 +671,17 @@ impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution ChalkToNextSolver<'db, crate::lower_nextsolver::ImplTraitIdx<'db>> + for crate::ImplTraitIdx +{ + fn to_nextsolver( + &self, + interner: DbInterner<'db>, + ) -> crate::lower_nextsolver::ImplTraitIdx<'db> { + crate::lower_nextsolver::ImplTraitIdx::from_raw(self.into_raw()) + } +} + 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()) 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 0bfd2b8003d05..32c30d19c7849 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 @@ -17,12 +17,18 @@ use super::{ pub type RegionKind<'db> = rustc_type_ir::RegionKind>; -#[salsa::interned(constructor = new_, debug)] +#[salsa::interned(constructor = new_)] pub struct Region<'db> { #[returns(ref)] kind_: RegionKind<'db>, } +impl std::fmt::Debug for Region<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.kind().fmt(f) + } +} + impl<'db> Region<'db> { pub fn new(interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { Region::new_(interner.db(), kind) @@ -69,6 +75,10 @@ impl<'db> Region<'db> { matches!(self.inner(), RegionKind::ReVar(_)) } + pub fn is_error(&self) -> bool { + matches!(self.inner(), RegionKind::ReError(_)) + } + pub fn error(interner: DbInterner<'db>) -> Self { Region::new(interner, RegionKind::ReError(ErrorGuaranteed)) } 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 a25996ab485c9..5ccd84af8d2f1 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 @@ -3,7 +3,8 @@ use std::iter; use std::ops::ControlFlow; -use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId}; +use hir_def::type_ref::Rawness; +use hir_def::{AdtId, GenericDefId, TypeOrConstParamId, TypeParamId}; use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; @@ -13,7 +14,7 @@ use rustc_type_ir::{ IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo, inherent::{ - Abi, AdtDef, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, + Abi, AdtDef as _, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _, }, relate::Relate, @@ -23,6 +24,7 @@ use rustc_type_ir::{ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; +use crate::next_solver::{AdtDef, Binder}; use crate::{ FnAbi, db::HirDatabase, @@ -75,6 +77,10 @@ impl<'db> Ty<'db> { .unwrap() } + pub fn new_adt(interner: DbInterner<'db>, adt_id: AdtId, args: GenericArgs<'db>) -> Self { + Ty::new(interner, TyKind::Adt(AdtDef::new(adt_id, interner), args)) + } + pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> Self { Ty::new(interner, TyKind::Param(ParamTy { id, index })) } @@ -337,6 +343,23 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty()) } + #[inline] + pub fn is_raw_ptr(self) -> bool { + matches!(self.kind(), TyKind::RawPtr(..)) + } + + pub fn is_union(self) -> bool { + self.as_adt().is_some_and(|(adt, _)| matches!(adt, AdtId::UnionId(_))) + } + + #[inline] + pub fn as_adt(self) -> Option<(AdtId, GenericArgs<'db>)> { + match self.kind() { + TyKind::Adt(adt_def, args) => Some((adt_def.def_id().0, args)), + _ => None, + } + } + #[inline] pub fn ty_vid(self) -> Option { match self.kind() { @@ -372,6 +395,38 @@ impl<'db> Ty<'db> { pub fn references_non_lt_error(self) -> bool { self.references_error() && self.visit_with(&mut ReferencesNonLifetimeError).is_break() } + + pub fn callable_sig(self, interner: DbInterner<'db>) -> Option>> { + match self.kind() { + TyKind::FnDef(callable, args) => { + Some(interner.fn_sig(callable).instantiate(interner, args)) + } + TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)), + TyKind::Closure(closure_id, closure_args) => closure_args + .split_closure_args_untupled() + .closure_sig_as_fn_ptr_ty + .callable_sig(interner), + _ => None, + } + } + + pub fn as_reference_or_ptr(self) -> Option<(Ty<'db>, Rawness, Mutability)> { + match self.kind() { + TyKind::Ref(_, ty, mutability) => Some((ty, Rawness::Ref, mutability)), + TyKind::RawPtr(ty, mutability) => Some((ty, Rawness::RawPtr, mutability)), + _ => None, + } + } + + /// Replace infer vars with errors. + /// + /// This needs to be called for every type that may contain infer vars and is yielded to outside inference, + /// as things other than inference do not expect to see infer vars. + pub fn replace_infer_with_error(self, interner: DbInterner<'db>) -> Ty<'db> { + self.fold_with(&mut crate::next_solver::infer::resolve::ReplaceInferWithError::new( + interner, + )) + } } struct ReferencesNonLifetimeError; @@ -928,11 +983,17 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { interned_vec_db!(Tys, Ty); +impl<'db> Tys<'db> { + pub fn inputs(&self) -> &[Ty<'db>] { + self.as_slice().split_last().unwrap().1 + } +} + 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(), + self.as_slice().split_last().unwrap().1.iter().copied(), ) } 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 a7f9817f9c08e..750d09e1a739c 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 @@ -413,7 +413,7 @@ pub(crate) fn for_trait_impls( 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::ForeignType(type_id)) => Some(type_id.module(db)), Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(db)), _ => None, }; 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 1c3da438cb364..5dd9ab75326dc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -36,10 +36,11 @@ use test_fixture::WithFixture; use triomphe::Arc; use crate::{ - InferenceResult, Ty, + InferenceResult, db::HirDatabase, display::{DisplayTarget, HirDisplay}, infer::{Adjustment, TypeMismatch}, + next_solver::Ty, setup_tracing, test_db::TestDB, }; @@ -78,172 +79,172 @@ fn check_impl( let _tracing = setup_tracing(); let (db, files) = TestDB::with_many_files(ra_fixture); - let mut had_annotations = false; - let mut mismatches = FxHashMap::default(); - let mut types = FxHashMap::default(); - let mut adjustments = FxHashMap::default(); - for (file_id, annotations) in db.extract_annotations() { - for (range, expected) in annotations { - let file_range = FileRange { file_id, range }; - if only_types { - types.insert(file_range, expected); - } else if expected.starts_with("type: ") { - types.insert(file_range, expected.trim_start_matches("type: ").to_owned()); - } else if expected.starts_with("expected") { - mismatches.insert(file_range, expected); - } else if expected.starts_with("adjustments:") { - adjustments.insert( - file_range, - expected.trim_start_matches("adjustments:").trim().to_owned(), - ); - } else { - panic!("unexpected annotation: {expected} @ {range:?}"); + salsa::attach(&db, || { + let mut had_annotations = false; + let mut mismatches = FxHashMap::default(); + let mut types = FxHashMap::default(); + let mut adjustments = FxHashMap::default(); + for (file_id, annotations) in db.extract_annotations() { + for (range, expected) in annotations { + let file_range = FileRange { file_id, range }; + if only_types { + types.insert(file_range, expected); + } else if expected.starts_with("type: ") { + types.insert(file_range, expected.trim_start_matches("type: ").to_owned()); + } else if expected.starts_with("expected") { + mismatches.insert(file_range, expected); + } else if expected.starts_with("adjustments:") { + adjustments.insert( + file_range, + expected.trim_start_matches("adjustments:").trim().to_owned(), + ); + } else { + panic!("unexpected annotation: {expected} @ {range:?}"); + } + had_annotations = true; } - had_annotations = true; } - } - assert!(had_annotations || allow_none, "no `//^` annotations found"); - - let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); - for file_id in files { - let module = db.module_for_file_opt(file_id.file_id(&db)); - let module = match module { - Some(m) => m, - None => continue, - }; - let def_map = module.def_map(&db); - visit_module(&db, def_map, module.local_id, &mut |it| { - let def = match it { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, + assert!(had_annotations || allow_none, "no `//^` annotations found"); + + let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); + for file_id in files { + let module = db.module_for_file_opt(file_id.file_id(&db)); + let module = match module { + Some(m) => m, + None => continue, }; - defs.push((def, module.krate())) - }); - } - defs.sort_by_key(|(def, _)| match def { - DefWithBodyId::FunctionId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::ConstId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::StaticId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::VariantId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() + let def_map = module.def_map(&db); + visit_module(&db, def_map, module.local_id, &mut |it| { + let def = match it { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + defs.push((def, module.krate())) + }); } - }); - let mut unexpected_type_mismatches = String::new(); - for (def, krate) in defs { - let display_target = DisplayTarget::from_crate(&db, krate); - let (body, body_source_map) = db.body_with_source_map(def); - let inference_result = db.infer(def); - - for (pat, mut ty) in inference_result.type_of_pat.iter() { - if let Pat::Bind { id, .. } = body[pat] { - ty = &inference_result.type_of_binding[id]; + defs.sort_by_key(|(def, _)| match def { + DefWithBodyId::FunctionId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() } - let node = match pat_node(&body_source_map, pat, &db) { - Some(value) => value, - None => continue, - }; - let range = node.as_ref().original_file_range_rooted(&db); - if let Some(expected) = types.remove(&range) { - let actual = salsa::attach(&db, || { - if display_source { + DefWithBodyId::ConstId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + DefWithBodyId::StaticId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + DefWithBodyId::VariantId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + }); + let mut unexpected_type_mismatches = String::new(); + for (def, krate) in defs { + let display_target = DisplayTarget::from_crate(&db, krate); + let (body, body_source_map) = db.body_with_source_map(def); + let inference_result = db.infer(def); + + for (pat, mut ty) in inference_result.type_of_pat.iter() { + if let Pat::Bind { id, .. } = body[pat] { + ty = &inference_result.type_of_binding[id]; + } + let node = match pat_node(&body_source_map, pat, &db) { + Some(value) => value, + None => continue, + }; + 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() - } - }); - assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); + }; + assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); + } } - } - for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match expr_node(&body_source_map, expr, &db) { - Some(value) => value, - None => continue, - }; - let range = node.as_ref().original_file_range_rooted(&db); - if let Some(expected) = types.remove(&range) { - let actual = salsa::attach(&db, || { - if display_source { + for (expr, ty) in inference_result.type_of_expr.iter() { + let node = match expr_node(&body_source_map, expr, &db) { + Some(value) => value, + None => continue, + }; + 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() - } - }); - assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); - } - if let Some(expected) = adjustments.remove(&range) { - let adjustments = inference_result - .expr_adjustments - .get(&expr) - .map_or_else(Default::default, |it| &**it); - assert_eq!( - expected, - adjustments - .iter() - .map(|Adjustment { kind, .. }| format!("{kind:?}")) - .join(", ") - ); + }; + assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); + } + if let Some(expected) = adjustments.remove(&range) { + let adjustments = inference_result + .expr_adjustments + .get(&expr) + .map_or_else(Default::default, |it| &**it); + assert_eq!( + expected, + adjustments + .iter() + .map(|Adjustment { kind, .. }| format!("{kind:?}")) + .join(", ") + ); + } } - } - for (expr_or_pat, mismatch) in inference_result.type_mismatches() { - let Some(node) = (match expr_or_pat { - hir_def::hir::ExprOrPatId::ExprId(expr) => expr_node(&body_source_map, expr, &db), - hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), - }) else { - continue; - }; - let range = node.as_ref().original_file_range_rooted(&db); - let actual = salsa::attach(&db, || { - format!( + for (expr_or_pat, mismatch) in inference_result.type_mismatches() { + let Some(node) = (match expr_or_pat { + hir_def::hir::ExprOrPatId::ExprId(expr) => { + expr_node(&body_source_map, expr, &db) + } + hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), + }) else { + 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) - ) - }); - match mismatches.remove(&range) { - Some(annotation) => assert_eq!(actual, annotation), - None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual), + ); + match mismatches.remove(&range) { + Some(annotation) => assert_eq!(actual, annotation), + None => { + format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual) + } + } } } - } - let mut buf = String::new(); - if !unexpected_type_mismatches.is_empty() { - format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches); - } - if !mismatches.is_empty() { - format_to!(buf, "Unchecked mismatch annotations:\n"); - for m in mismatches { - format_to!(buf, "{:?}: {}\n", m.0.range, m.1); + let mut buf = String::new(); + if !unexpected_type_mismatches.is_empty() { + format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches); } - } - if !types.is_empty() { - format_to!(buf, "Unchecked type annotations:\n"); - for t in types { - format_to!(buf, "{:?}: type {}\n", t.0.range, t.1); + if !mismatches.is_empty() { + format_to!(buf, "Unchecked mismatch annotations:\n"); + for m in mismatches { + format_to!(buf, "{:?}: {}\n", m.0.range, m.1); + } } - } - if !adjustments.is_empty() { - format_to!(buf, "Unchecked adjustments annotations:\n"); - for t in adjustments { - format_to!(buf, "{:?}: type {:?}\n", t.0.range, t.1); + if !types.is_empty() { + format_to!(buf, "Unchecked type annotations:\n"); + for t in types { + format_to!(buf, "{:?}: type {}\n", t.0.range, t.1); + } } - } - assert!(buf.is_empty(), "{}", buf); + if !adjustments.is_empty() { + format_to!(buf, "Unchecked adjustments annotations:\n"); + for t in adjustments { + format_to!(buf, "{:?}: type {:?}\n", t.0.range, t.1); + } + } + assert!(buf.is_empty(), "{}", buf); + }); } fn expr_node( @@ -282,139 +283,140 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let _tracing = setup_tracing(); let (db, file_id) = TestDB::with_single_file(content); - let mut buf = String::new(); - - let mut infer_def = |inference_result: Arc, - body: Arc, - body_source_map: Arc, - krate: Crate| { - let display_target = DisplayTarget::from_crate(&db, krate); - let mut types: Vec<(InFile, &Ty)> = Vec::new(); - let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); - - if let Some(self_param) = body.self_param { - let ty = &inference_result.type_of_binding[self_param]; - if let Some(syntax_ptr) = body_source_map.self_param_syntax() { - let root = db.parse_or_expand(syntax_ptr.file_id); - let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); - types.push((node, ty)); + salsa::attach(&db, || { + let mut buf = String::new(); + + let mut infer_def = |inference_result: Arc>, + body: Arc, + body_source_map: Arc, + krate: Crate| { + let display_target = DisplayTarget::from_crate(&db, krate); + let mut types: Vec<(InFile, &Ty<'_>)> = Vec::new(); + let mut mismatches: Vec<(InFile, &TypeMismatch<'_>)> = Vec::new(); + + if let Some(self_param) = body.self_param { + let ty = &inference_result.type_of_binding[self_param]; + if let Some(syntax_ptr) = body_source_map.self_param_syntax() { + let root = db.parse_or_expand(syntax_ptr.file_id); + let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); + types.push((node, ty)); + } } - } - for (pat, mut ty) in inference_result.type_of_pat.iter() { - if let Pat::Bind { id, .. } = body[pat] { - ty = &inference_result.type_of_binding[id]; - } - let node = match body_source_map.pat_syntax(pat) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + for (pat, mut ty) in inference_result.type_of_pat.iter() { + if let Pat::Bind { id, .. } = body[pat] { + ty = &inference_result.type_of_binding[id]; + } + let node = match body_source_map.pat_syntax(pat) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id); + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + } + Err(SyntheticSyntax) => continue, + }; + types.push((node.clone(), ty)); + if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) { + mismatches.push((node, mismatch)); } - Err(SyntheticSyntax) => continue, - }; - types.push((node.clone(), ty)); - if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) { - mismatches.push((node, mismatch)); } - } - for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match body_source_map.expr_syntax(expr) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + for (expr, ty) in inference_result.type_of_expr.iter() { + let node = match body_source_map.expr_syntax(expr) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id); + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + } + Err(SyntheticSyntax) => continue, + }; + types.push((node.clone(), ty)); + if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { + mismatches.push((node, mismatch)); } - Err(SyntheticSyntax) => continue, - }; - types.push((node.clone(), ty)); - if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { - mismatches.push((node, mismatch)); } - } - // sort ranges for consistency - types.sort_by_key(|(node, _)| { - let range = node.value.text_range(); - (range.start(), range.end()) - }); - for (node, ty) in &types { - let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { - (self_param.name().unwrap().syntax().text_range(), "self".to_owned()) - } else { - (node.value.text_range(), node.value.text().to_string().replace('\n', " ")) - }; - let macro_prefix = if node.file_id != file_id { "!" } else { "" }; - format_to!( - buf, - "{}{:?} '{}': {}\n", - macro_prefix, - range, - ellipsize(text, 15), - ty.display_test(&db, display_target) - ); - } - if include_mismatches { - mismatches.sort_by_key(|(node, _)| { + // sort ranges for consistency + types.sort_by_key(|(node, _)| { let range = node.value.text_range(); (range.start(), range.end()) }); - for (src_ptr, mismatch) in &mismatches { - let range = src_ptr.value.text_range(); - let macro_prefix = if src_ptr.file_id != file_id { "!" } else { "" }; + for (node, ty) in &types { + let (range, text) = + if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) { + (self_param.name().unwrap().syntax().text_range(), "self".to_owned()) + } else { + (node.value.text_range(), node.value.text().to_string().replace('\n', " ")) + }; + let macro_prefix = if node.file_id != file_id { "!" } else { "" }; format_to!( buf, - "{}{:?}: expected {}, got {}\n", + "{}{:?} '{}': {}\n", macro_prefix, range, - mismatch.expected.display_test(&db, display_target), - mismatch.actual.display_test(&db, display_target), + ellipsize(text, 15), + ty.display_test(&db, display_target) ); } - } - }; + if include_mismatches { + mismatches.sort_by_key(|(node, _)| { + let range = node.value.text_range(); + (range.start(), range.end()) + }); + for (src_ptr, mismatch) in &mismatches { + let range = src_ptr.value.text_range(); + let macro_prefix = if src_ptr.file_id != file_id { "!" } else { "" }; + format_to!( + buf, + "{}{:?}: expected {}, got {}\n", + macro_prefix, + range, + mismatch.expected.display_test(&db, display_target), + mismatch.actual.display_test(&db, display_target), + ); + } + } + }; - let module = db.module_for_file(file_id.file_id(&db)); - let def_map = module.def_map(&db); + let module = db.module_for_file(file_id.file_id(&db)); + let def_map = module.def_map(&db); - let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); - visit_module(&db, def_map, module.local_id, &mut |it| { - let def = match it { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }; - defs.push((def, module.krate())) - }); - defs.sort_by_key(|(def, _)| match def { - DefWithBodyId::FunctionId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::ConstId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::StaticId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - DefWithBodyId::VariantId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.syntax().text_range().start() - } - }); - for (def, krate) in defs { - let (body, source_map) = db.body_with_source_map(def); - let infer = db.infer(def); - salsa::attach(&db, || { + let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); + visit_module(&db, def_map, module.local_id, &mut |it| { + let def = match it { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + defs.push((def, module.krate())) + }); + defs.sort_by_key(|(def, _)| match def { + DefWithBodyId::FunctionId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + DefWithBodyId::ConstId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + DefWithBodyId::StaticId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + DefWithBodyId::VariantId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.syntax().text_range().start() + } + }); + 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); - }) - } + } - buf.truncate(buf.trim_end().len()); - buf + buf.truncate(buf.trim_end().len()); + buf + }) } pub(crate) fn visit_module( 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 b001ac1e82ea2..d3bc26abd7b0a 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 @@ -2,15 +2,16 @@ use expect_test::{Expect, expect}; use hir_def::db::DefDatabase; use hir_expand::{HirFileId, files::InFileWrapper}; use itertools::Itertools; -use salsa::plumbing::FromId; use span::TextRange; use syntax::{AstNode, AstPtr}; use test_fixture::WithFixture; -use crate::db::{HirDatabase, InternedClosureId}; -use crate::display::{DisplayTarget, HirDisplay}; -use crate::mir::MirSpan; -use crate::test_db::TestDB; +use crate::{ + db::HirDatabase, + display::{DisplayTarget, HirDisplay}, + mir::MirSpan, + test_db::TestDB, +}; use super::{setup_tracing, visit_module}; @@ -35,7 +36,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let infer = db.infer(def); let db = &db; captures_info.extend(infer.closure_info.iter().flat_map(|(closure_id, (captures, _))| { - let closure = db.lookup_intern_closure(InternedClosureId::from_id(closure_id.0)); + let closure = db.lookup_intern_closure(*closure_id); let source_map = db.body_with_source_map(closure.0).1; let closure_text_range = source_map .expr_syntax(closure.1) @@ -70,7 +71,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let capture_ty = salsa::attach(db, || { capture .ty - .skip_binders() + .skip_binder() .display_test(db, DisplayTarget::from_crate(db, module.krate())) .to_string() }); 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 1735f550b8ad7..5a53db4b7ab15 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('?1, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?2, Not)), Pointer(Unsize) let x: *const [isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) } @@ -268,7 +268,7 @@ fn takes_ref_str(x: &str) {} fn returns_string() -> String { loop {} } fn test() { takes_ref_str(&{ returns_string() }); - // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('{error}, Not)) + // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref('{region error}, Not)) } "#, ); @@ -567,7 +567,7 @@ trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; - //^ expected &'? (dyn Foo + '?), got &'? impl Foo + ?Sized + //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized } "#, ); @@ -833,11 +833,11 @@ struct V { t: T } fn main() { let a: V<&dyn Tr>; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,) let mut a: V<&dyn Tr> = V { t: &S }; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,) } "#, ); @@ -854,8 +854,8 @@ impl core::cmp::PartialEq for Struct { } fn test() { Struct == Struct; - // ^^^^^^ adjustments: Borrow(Ref('{error}, Not)) - // ^^^^^^ adjustments: Borrow(Ref('{error}, Not)) + // ^^^^^^ adjustments: Borrow(Ref('{region error}, Not)) + // ^^^^^^ adjustments: Borrow(Ref('{region error}, Not)) }", ); } @@ -871,7 +871,7 @@ impl core::ops::AddAssign for Struct { } fn test() { Struct += Struct; - // ^^^^^^ adjustments: Borrow(Ref('{error}, Mut)) + // ^^^^^^ adjustments: Borrow(Ref('{region error}, Mut)) // ^^^^^^ adjustments: }", ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index 6e3faa05a629b..a986b54a7b064 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -67,11 +67,11 @@ trait B: A {} fn test<'a>( _: &(dyn A + Send), - //^ &(dyn A + Send) + //^ &(dyn A + Send + 'static) _: &'a (dyn Send + A), - //^ &'a (dyn A + Send) + //^ &'a (dyn A + Send + 'static) _: &dyn B, - //^ &(dyn B) + //^ &(dyn B + 'static) ) {} "#, ); @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &dyn Foo<'?> + // ^^^ &(dyn Foo<'?> + 'static) "#, ); } 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 8587c13e87f77..ce3de06127e49 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 @@ -44,7 +44,7 @@ fn foo() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "expr_scopes_shim", "lang_item", "crate_lang_items", @@ -131,7 +131,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "expr_scopes_shim", "lang_item", "crate_lang_items", @@ -143,7 +143,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "expr_scopes_shim", "infer_shim", "function_signature_shim", @@ -151,7 +151,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "expr_scopes_shim", ] "#]], @@ -586,7 +586,7 @@ fn main() { "attrs_shim", "attrs_shim", "generic_predicates_ns_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "infer_shim", "function_signature_shim", "function_signature_with_source_map_shim", @@ -594,7 +594,7 @@ fn main() { "expr_scopes_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", - "generic_predicates_shim", + "generic_predicates_ns_shim", "value_ty_shim", "VariantFields::firewall_", "VariantFields::query_", @@ -610,7 +610,7 @@ fn main() { "impl_self_ty_with_diagnostics_shim", "generic_predicates_ns_shim", "value_ty_shim", - "generic_predicates_shim", + "generic_predicates_ns_shim", ] "#]], ); @@ -683,11 +683,12 @@ fn main() { "attrs_shim", "attrs_shim", "generic_predicates_ns_shim", - "return_type_impl_traits_shim", + "return_type_impl_traits_ns_shim", "infer_shim", "function_signature_with_source_map_shim", "expr_scopes_shim", "struct_signature_with_source_map_shim", + "generic_predicates_ns_shim", "VariantFields::query_", "inherent_impls_in_crate_shim", "impl_signature_with_source_map_shim", @@ -697,7 +698,7 @@ fn main() { "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", "generic_predicates_ns_shim", - "generic_predicates_shim", + "generic_predicates_ns_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 25b938c7078aa..2f41de64cbbdd 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 @@ -199,8 +199,8 @@ fn expr_macro_def_expanded_in_various_places() { 100..119 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter 100..119 'for _ ...!() {}': ::IntoIter 100..119 'for _ ...!() {}': ! - 100..119 'for _ ...!() {}': ::IntoIter - 100..119 'for _ ...!() {}': &'? mut ::IntoIter + 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 _ ...!() {}': () @@ -293,8 +293,8 @@ fn expr_macro_rules_expanded_in_various_places() { 114..133 'for _ ...!() {}': fn into_iter(isize) -> ::IntoIter 114..133 'for _ ...!() {}': ::IntoIter 114..133 'for _ ...!() {}': ! - 114..133 'for _ ...!() {}': ::IntoIter - 114..133 'for _ ...!() {}': &'? mut ::IntoIter + 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 _ ...!() {}': () 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 2f8f666475668..b0afd60406676 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 @@ -1157,9 +1157,9 @@ fn dyn_trait_super_trait_not_in_scope() { 51..55 'self': &'? Self 64..69 '{ 0 }': u32 66..67 '0': u32 - 176..177 'd': &'? (dyn Trait + '?) + 176..177 'd': &'? (dyn Trait + 'static) 191..207 '{ ...o(); }': () - 197..198 'd': &'? (dyn Trait + '?) + 197..198 'd': &'? (dyn Trait + 'static) 197..204 'd.foo()': u32 "#]], ); @@ -2050,7 +2050,7 @@ impl dyn Error + Send { /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; - // ^^^^ expected Box, got Box + // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> 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 40e4c28fcc0b9..5cdd170198ba2 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 @@ -31,6 +31,7 @@ fn test() { } #[test] +#[ignore = "FIXME(next-solver): This currently generates a type mismatch, need to switch opaque type handling to the solver"] fn associated_type_impl_traits_complex() { check_types( r#" 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 00835aa03130c..7c79393e65ac9 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 @@ -1257,8 +1257,8 @@ fn test() { 16..66 'for _ ... }': fn into_iter<()>(()) -> <() as IntoIterator>::IntoIter 16..66 'for _ ... }': <() as IntoIterator>::IntoIter 16..66 'for _ ... }': ! - 16..66 'for _ ... }': <() as IntoIterator>::IntoIter - 16..66 'for _ ... }': &'? mut <() as IntoIterator>::IntoIter + 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 _ ... }': () @@ -2363,8 +2363,8 @@ fn test() { 108..125 '{ ... }': usize 118..119 'N': usize 139..157 '{ ...= N; }': () - 149..150 '_': Foo<_> - 153..154 'N': Foo<_> + 149..150 '_': Foo + 153..154 'N': Foo "#]], ); } 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 c7711f31bf262..e7fadd0363acb 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 @@ -84,7 +84,7 @@ fn test() -> i32 { 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 + '?) + 327..358 '0 as *...yn Foo': *const (dyn Foo + 'static) 370..371 'f': F 374..378 'F {}': F 388..395 'fat_ptr': *const (dyn Foo + '?) 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 9d02a44c37c97..38af7cb7248f4 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 @@ -2743,7 +2743,7 @@ impl B for Astruct {} 725..754 '#[rust...1i32])': Box<[i32; 1], Global> 747..753 '[1i32]': [i32; 1] 748..752 '1i32': i32 - 765..766 'v': Vec, Global> + 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> @@ -3692,39 +3692,6 @@ fn main() { ); } -#[test] -fn infer_bad_lang_item() { - check_infer( - r#" -#[lang="eq"] -pub trait Eq { - fn eq(&self, ) -> bool; - -} - -#[lang="shr"] -pub trait Shr { - fn shr(&self, rhs: &RHS) -> Result; -} - -fn test() -> bool { - 1 >> 1; - 1 == 1; -} -"#, - expect![[r#" - 39..43 'self': &'? Self - 114..118 'self': &'? Self - 120..123 'rhs': &'? RHS - 163..190 '{ ...= 1; }': bool - 169..170 '1': i32 - 169..175 '1 >> 1': {unknown} - 181..182 '1': i32 - 181..187 '1 == 1': {unknown} - "#]], - ); -} - #[test] fn macro_semitransparent_hygiene() { check_types( 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 66faac09cc299..0cf723e8514d8 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 @@ -1480,24 +1480,24 @@ fn test(x: Box>, y: &dyn Trait) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 206..208 '{}': Box + '?> - 218..219 'x': Box + '?> - 242..243 'y': &'? (dyn Trait + '?) + 206..208 '{}': Box + 'static> + 218..219 'x': Box + 'static> + 242..243 'y': &'? (dyn Trait + 'static) 262..379 '{ ...2(); }': () - 268..269 'x': Box + '?> - 275..276 'y': &'? (dyn Trait + '?) + 268..269 'x': Box + 'static> + 275..276 'y': &'? (dyn Trait + 'static) 286..287 'z': Box + '?> 290..293 'bar': fn bar() -> Box + 'static> 290..295 'bar()': Box + 'static> - 301..302 'x': Box + '?> + 301..302 'x': Box + 'static> 301..308 'x.foo()': u64 - 314..315 'y': &'? (dyn Trait + '?) + 314..315 'y': &'? (dyn Trait + 'static) 314..321 'y.foo()': u64 327..328 'z': Box + '?> 327..334 'z.foo()': u64 - 340..341 'x': Box + '?> + 340..341 'x': Box + 'static> 340..348 'x.foo2()': i64 - 354..355 'y': &'? (dyn Trait + '?) + 354..355 'y': &'? (dyn Trait + 'static) 354..362 'y.foo2()': i64 368..369 'z': Box + '?> 368..376 'z.foo2()': i64 @@ -1528,7 +1528,7 @@ fn test(s: S) { expect![[r#" 32..36 'self': &'? Self 102..106 'self': &'? S - 128..139 '{ loop {} }': &'? (dyn Trait + '?) + 128..139 '{ loop {} }': &'? (dyn Trait + 'static) 130..137 'loop {}': ! 135..137 '{}': () 175..179 'self': &'? Self @@ -1561,18 +1561,18 @@ fn test(x: Trait, y: &Trait) -> u64 { }"#, expect![[r#" 26..30 'self': &'? Self - 60..62 '{}': dyn Trait + '? - 72..73 'x': dyn Trait + '? - 82..83 'y': &'? (dyn Trait + '?) + 60..62 '{}': dyn Trait + 'static + 72..73 'x': dyn Trait + 'static + 82..83 'y': &'? (dyn Trait + 'static) 100..175 '{ ...o(); }': u64 - 106..107 'x': dyn Trait + '? - 113..114 'y': &'? (dyn Trait + '?) + 106..107 'x': dyn Trait + 'static + 113..114 'y': &'? (dyn Trait + 'static) 124..125 'z': dyn Trait + '? 128..131 'bar': fn bar() -> dyn Trait + 'static 128..133 'bar()': dyn Trait + 'static - 139..140 'x': dyn Trait + '? + 139..140 'x': dyn Trait + 'static 139..146 'x.foo()': u64 - 152..153 'y': &'? (dyn Trait + '?) + 152..153 'y': &'? (dyn Trait + 'static) 152..159 'y.foo()': u64 165..166 'z': dyn Trait + '? 165..172 'z.foo()': u64 @@ -1594,7 +1594,7 @@ fn main() { expect![[r#" 31..35 'self': &'? S 37..39 '{}': () - 47..48 '_': &'? (dyn Fn(S) + '?) + 47..48 '_': &'? (dyn Fn(S) + 'static) 58..60 '{}': () 71..105 '{ ...()); }': () 77..78 'f': fn f(&'? (dyn Fn(S) + 'static)) @@ -2948,13 +2948,13 @@ fn test(x: &dyn Foo) { foo(x); }"#, expect![[r#" - 21..22 'x': &'? (dyn Foo + '?) + 21..22 'x': &'? (dyn Foo + 'static) 34..36 '{}': () - 46..47 'x': &'? (dyn Foo + '?) + 46..47 'x': &'? (dyn Foo + 'static) 59..74 '{ foo(x); }': () 65..68 'foo': fn foo(&'? (dyn Foo + 'static)) 65..71 'foo(x)': () - 69..70 'x': &'? (dyn Foo + '?) + 69..70 'x': &'? (dyn Foo + 'static) "#]], ); } @@ -3230,13 +3230,13 @@ fn foo() { 218..324 '{ ...&s); }': () 228..229 's': Option 232..236 'None': Option - 246..247 'f': Box) + '?> - 281..310 'Box { ... {}) }': Box) + '?> + 246..247 'f': Box) + 'static> + 281..310 'Box { ... {}) }': Box) + 'static> 294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option) 300..307 '|ps| {}': impl FnOnce(&'? Option) 301..303 'ps': &'? Option 305..307 '{}': () - 316..317 'f': Box) + '?> + 316..317 'f': Box) + 'static> 316..321 'f(&s)': () 318..320 '&s': &'? Option 319..320 's': Option @@ -4272,10 +4272,10 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait = &'a i32> + '?) + 127..128 'v': &'? (dyn Trait = &'a i32> + 'static) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': = &'a i32> + '? as Trait>::Assoc + 170..171 'v': &'? (dyn Trait = &'a i32> + 'static) + 170..184 'v.get::()': = &'a i32> + 'static as Trait>::Assoc 170..192 'v.get:...eref()': {unknown} "#]], ); 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 8ac152341e753..16ad54a2f2c06 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -12,7 +12,7 @@ use intern::sym; use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt}; use rustc_type_ir::{ InferCtxtLike, TypingMode, - inherent::{SliceLike, Span as _}, + inherent::{SliceLike, Span as _, Ty as _}, solve::Certainty, }; use span::Edition; @@ -23,11 +23,11 @@ use crate::{ AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase, - infer::unify::InferenceTable, + from_assoc_type_id, next_solver::{ DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span, - infer::{DbInternerInferExt, InferCtxt}, - mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, + infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result}, util::mini_canonicalize, }, utils::UnevaluatedConstEvaluatorFolder, @@ -93,9 +93,30 @@ pub(crate) fn normalize_projection_query<'db>( return TyKind::Error.intern(Interner); } - let mut table = InferenceTable::new(db, env); - let ty = table.normalize_projection_ty(projection); - table.resolve_completely(ty) + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things), + // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT + // and async blocks. + let infcx = interner.infer_ctxt().build(TypingMode::Analysis { + defining_opaque_types_and_generators: crate::next_solver::SolverDefIds::new_from_iter( + interner, + [], + ), + }); + let alias_ty = crate::next_solver::Ty::new_alias( + interner, + rustc_type_ir::AliasTyKind::Projection, + crate::next_solver::AliasTy::new( + interner, + from_assoc_type_id(projection.associated_ty_id).into(), + >>::to_nextsolver(&projection.substitution, interner), + ), + ); + let mut ctxt = crate::next_solver::obligation_ctxt::ObligationCtxt::new(&infcx); + let normalized = ctxt + .structurally_normalize_ty(&ObligationCause::dummy(), env.env, alias_ty) + .unwrap_or(alias_ty); + normalized.replace_infer_with_error(interner).to_chalk(interner) } fn identity_subst( diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index fca0162765ecf..c094487a8709e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -19,6 +19,7 @@ use hir_ty::{ PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind, db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, + next_solver::{DbInterner, mapping::NextSolverToChalk}, }; use syntax::{ AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange, @@ -620,7 +621,7 @@ impl<'db> AnyDiagnostic<'db> { pub(crate) fn inference_diagnostic( db: &'db dyn HirDatabase, def: DefWithBodyId, - d: &InferenceDiagnostic, + d: &InferenceDiagnostic<'db>, source_map: &hir_def::expr_store::BodySourceMap, sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, ) -> Option> { @@ -640,6 +641,7 @@ impl<'db> AnyDiagnostic<'db> { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat), }; + let interner = DbInterner::new_with(db, None, None); Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { let expr_or_pat = match expr { @@ -666,8 +668,11 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::ExpectedFunction { call_expr, found } => { let call_expr = expr_syntax(*call_expr)?; - ExpectedFunction { call: call_expr, found: Type::new(db, def, found.clone()) } - .into() + ExpectedFunction { + call: call_expr, + found: Type::new(db, def, found.to_chalk(interner)), + } + .into() } InferenceDiagnostic::UnresolvedField { expr, @@ -679,7 +684,7 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedField { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.clone()), + receiver: Type::new(db, def, receiver.to_chalk(interner)), method_with_same_name_exists: *method_with_same_name_exists, } .into() @@ -695,10 +700,9 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedMethodCall { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.clone()), - field_with_same_name: field_with_same_name - .clone() - .map(|ty| Type::new(db, def, ty)), + receiver: Type::new(db, def, receiver.to_chalk(interner)), + field_with_same_name: (*field_with_same_name) + .map(|ty| Type::new(db, def, ty.to_chalk(interner))), assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into), } .into() @@ -725,7 +729,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::TypedHole { expr, expected } => { let expr = expr_syntax(*expr)?; - TypedHole { expr, expected: Type::new(db, def, expected.clone()) }.into() + TypedHole { expr, expected: Type::new(db, def, expected.to_chalk(interner)) }.into() } &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => { let expr_or_pat = match pat { @@ -742,12 +746,13 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::CastToUnsized { expr, cast_ty } => { let expr = expr_syntax(*expr)?; - CastToUnsized { expr, cast_ty: Type::new(db, def, cast_ty.clone()) }.into() + CastToUnsized { expr, cast_ty: Type::new(db, def, cast_ty.to_chalk(interner)) } + .into() } InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => { let expr = expr_syntax(*expr)?; - let expr_ty = Type::new(db, def, expr_ty.clone()); - let cast_ty = Type::new(db, def, cast_ty.clone()); + let expr_ty = Type::new(db, def, expr_ty.to_chalk(interner)); + let cast_ty = Type::new(db, def, cast_ty.to_chalk(interner)); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } InferenceDiagnostic::TyDiagnostic { source, diag } => { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 9198086e9e6cb..d6527777117e0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -157,7 +157,7 @@ pub use { tt, }, hir_ty::{ - CastError, DropGlue, FnAbi, PointerCast, Safety, Variance, + CastError, DropGlue, FnAbi, PointerCast, Variance, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, @@ -165,6 +165,7 @@ pub use { layout::LayoutError, method_resolution::TyFingerprint, mir::{MirEvalError, MirLowerError}, + next_solver::abi::Safety, }, // FIXME: Properly encapsulate mir hir_ty::{Interner as ChalkTyInterner, mir}, @@ -1287,9 +1288,11 @@ impl TupleField { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { + let interner = DbInterner::new_with(db, None, None); let ty = db .infer(self.owner) .tuple_field_access_type(self.tuple) + .to_chalk(interner) .as_slice(Interner) .get(self.index as usize) .and_then(|arg| arg.ty(Interner)) @@ -1720,7 +1723,7 @@ impl Variant { self.source(db)?.value.expr() } - pub fn eval(self, db: &dyn HirDatabase) -> Result { + pub fn eval(self, db: &dyn HirDatabase) -> Result> { db.const_eval_discriminant(self.into()) } @@ -2012,6 +2015,7 @@ impl DefWithBody { style_lints: bool, ) { let krate = self.module(db).id.krate(); + let interner = DbInterner::new_with(db, Some(krate), None); let (body, source_map) = db.body_with_source_map(self.into()); let sig_source_map = match self { @@ -2061,8 +2065,16 @@ impl DefWithBody { acc.push( TypeMismatch { expr_or_pat, - expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()), - actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()), + expected: Type::new( + db, + DefWithBodyId::from(self), + mismatch.expected.to_chalk(interner), + ), + actual: Type::new( + db, + DefWithBodyId::from(self), + mismatch.actual.to_chalk(interner), + ), } .into(), ); @@ -2628,7 +2640,7 @@ impl Function { self, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, - ) -> Result { + ) -> Result> { let body = db.monomorphized_mir_body( self.id.into(), Substitution::empty(Interner), @@ -2912,7 +2924,7 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result { + pub fn eval(self, db: &dyn HirDatabase) -> Result> { db.const_eval(self.id.into(), Substitution::empty(Interner), None) .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) } @@ -2934,7 +2946,7 @@ impl EvaluatedConst { format!("{}", self.const_.display(db, display_target)) } - pub fn render_debug(&self, db: &dyn HirDatabase) -> Result { + pub fn render_debug<'db>(&self, db: &'db dyn HirDatabase) -> Result> { let data = self.const_.data(Interner); if let TyKind::Scalar(s) = data.ty.kind(Interner) && matches!(s, Scalar::Int(_) | Scalar::Uint(_)) @@ -2990,7 +3002,7 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result { + pub fn eval(self, db: &dyn HirDatabase) -> Result> { db.const_eval(self.id.into(), Substitution::empty(Interner), None) .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) } @@ -4021,8 +4033,9 @@ impl Local { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; let infer = db.infer(def); - let ty = infer[self.binding_id].clone(); - Type::new(db, def, ty) + let ty = infer[self.binding_id]; + let interner = DbInterner::new_with(db, None, None); + Type::new(db, def, ty.to_chalk(interner)) } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` @@ -4466,7 +4479,9 @@ impl Impl { db: &'db dyn HirDatabase, Type { ty, env, _pd: _ }: Type<'db>, ) -> Vec { - let def_crates = match method_resolution::def_crates(db, &ty, env.krate) { + let interner = DbInterner::new_with(db, None, None); + let ty_ns = ty.to_nextsolver(interner); + let def_crates = match method_resolution::def_crates(db, ty_ns, env.krate) { Some(def_crates) => def_crates, None => return Vec::new(), }; @@ -4477,7 +4492,7 @@ impl Impl { ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) }; - let fp = TyFingerprint::for_inherent_impl(&ty); + let fp = TyFingerprint::for_inherent_impl(ty_ns); let fp = match fp { Some(fp) => fp, None => return Vec::new(), @@ -4487,7 +4502,7 @@ impl Impl { def_crates.iter().for_each(|&id| { all.extend( db.inherent_impls_in_crate(id) - .for_self_ty(&ty) + .for_self_ty(ty_ns) .iter() .cloned() .map(Self::from) @@ -4512,7 +4527,12 @@ impl Impl { { if let Some(inherent_impls) = db.inherent_impls_in_block(block) { all.extend( - inherent_impls.for_self_ty(&ty).iter().cloned().map(Self::from).filter(filter), + inherent_impls + .for_self_ty(ty_ns) + .iter() + .cloned() + .map(Self::from) + .filter(filter), ); } if let Some(trait_impls) = db.trait_impls_in_block(block) { @@ -4691,10 +4711,10 @@ impl Closure { .to_string() } - pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec { + pub fn captured_items<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { let owner = db.lookup_intern_closure((self.id).into()).0; let infer = &db.infer(owner); - let info = infer.closure_info(&self.id); + let info = infer.closure_info(self.id.into()); info.0 .iter() .cloned() @@ -4705,12 +4725,13 @@ impl Closure { pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { let owner = db.lookup_intern_closure((self.id).into()).0; let infer = &db.infer(owner); - let (captures, _) = infer.closure_info(&self.id); + let (captures, _) = infer.closure_info(self.id.into()); + let interner = DbInterner::new_with(db, None, None); captures .iter() .map(|capture| Type { env: db.trait_environment_for_body(owner), - ty: capture.ty(db, &self.subst), + ty: capture.ty(db, self.subst.to_nextsolver(interner)).to_chalk(interner), _pd: PhantomCovariantLifetime::new(), }) .collect() @@ -4719,19 +4740,19 @@ impl Closure { pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { let owner = db.lookup_intern_closure((self.id).into()).0; let infer = &db.infer(owner); - let info = infer.closure_info(&self.id); + let info = infer.closure_info(self.id.into()); info.1 } } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct ClosureCapture { +pub struct ClosureCapture<'db> { owner: DefWithBodyId, closure: ClosureId, - capture: hir_ty::CapturedItem, + capture: hir_ty::CapturedItem<'db>, } -impl ClosureCapture { +impl<'db> ClosureCapture<'db> { pub fn local(&self) -> Local { Local { parent: self.owner, binding_id: self.capture.local() } } @@ -5443,7 +5464,8 @@ impl<'db> Type<'db> { } pub fn fingerprint_for_trait_impl(&self) -> Option { - TyFingerprint::for_trait_impl(&self.ty) + let interner = DbInterner::conjure(); + TyFingerprint::for_trait_impl(self.ty.to_nextsolver(interner)) } pub(crate) fn canonical(&self) -> Canonical { @@ -5487,14 +5509,16 @@ impl<'db> Type<'db> { krate: Crate, callback: &mut dyn FnMut(AssocItemId) -> bool, ) { - let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) { + let interner = DbInterner::new_with(db, None, None); + let ty_ns = self.ty.to_nextsolver(interner); + let def_crates = match method_resolution::def_crates(db, ty_ns, krate.id) { Some(it) => it, None => return, }; for krate in def_crates { let impls = db.inherent_impls_in_crate(krate); - for impl_def in impls.for_self_ty(&self.ty) { + for impl_def in impls.for_self_ty(ty_ns) { for &(_, item) in impl_def.impl_items(db).items.iter() { if callback(item) { return; diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 5af8659ca669a..45c2020bc8cea 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -29,6 +29,8 @@ use hir_expand::{ name::AsName, }; use hir_ty::diagnostics::{unsafe_operations, unsafe_operations_for_body}; +use hir_ty::next_solver::DbInterner; +use hir_ty::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use intern::{Interned, Symbol, sym}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; @@ -1553,19 +1555,24 @@ impl<'db> SemanticsImpl<'db> { pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option>> { let mutability = |m| match m { - hir_ty::Mutability::Not => Mutability::Shared, - hir_ty::Mutability::Mut => Mutability::Mut, + hir_ty::next_solver::Mutability::Not => Mutability::Shared, + hir_ty::next_solver::Mutability::Mut => Mutability::Mut, }; let analyzer = self.analyze(expr.syntax())?; let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?; + let interner = DbInterner::new_with(self.db, None, None); + analyzer.expr_adjustments(expr).map(|it| { it.iter() .map(|adjust| { - let target = - Type::new_with_resolver(self.db, &analyzer.resolver, adjust.target.clone()); + let target = Type::new_with_resolver( + self.db, + &analyzer.resolver, + adjust.target.to_chalk(interner), + ); let kind = match adjust.kind { hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { @@ -1652,11 +1659,18 @@ impl<'db> SemanticsImpl<'db> { func: Function, subst: impl IntoIterator>, ) -> Option { - let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None); - for s in subst { - substs = substs.push(s.ty); - } - Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into()) + let interner = DbInterner::new_with(self.db, None, None); + let mut subst = subst.into_iter(); + let substs = hir_ty::next_solver::GenericArgs::for_item( + interner, + trait_.id.into(), + |_, _, id, _| { + assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type"); + subst.next().expect("too few subst").ty.to_nextsolver(interner).into() + }, + ); + assert!(subst.next().is_none(), "too many subst"); + Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into()) } fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option { 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 c6b7e84dc20f1..5a2849220ed3f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -18,7 +18,7 @@ use base_db::salsa; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, - ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId, + LocalFieldId, ModuleDefId, StructId, TraitId, VariantId, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, lower::ExprCollector, @@ -36,9 +36,10 @@ use hir_expand::{ mod_path::{ModPath, PathKind, path}, name::{AsName, Name}, }; +use hir_ty::next_solver::GenericArgs; use hir_ty::{ Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy, - Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext, + Substitution, ToChalk, TraitEnvironment, Ty, TyKind, TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -67,16 +68,16 @@ use triomphe::Arc; pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, - pub(crate) body_or_sig: Option, + pub(crate) body_or_sig: Option>, } #[derive(Debug)] -pub(crate) enum BodyOrSig { +pub(crate) enum BodyOrSig<'db> { Body { def: DefWithBodyId, body: Arc, source_map: Arc, - infer: Option>, + infer: Option>>, }, // To be folded into body once it is considered one VariantFields { @@ -116,7 +117,7 @@ impl<'db> SourceAnalyzer<'db> { def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, - infer: Option>, + infer: Option>>, ) -> SourceAnalyzer<'db> { let (body, source_map) = db.body_with_source_map(def); let scopes = db.expr_scopes(def); @@ -182,7 +183,9 @@ impl<'db> SourceAnalyzer<'db> { } // FIXME: Remove this - fn body_(&self) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult>)> { + fn body_( + &self, + ) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult<'db>>)> { self.body_or_sig.as_ref().and_then(|it| match it { BodyOrSig::Body { def, body, source_map, infer } => { Some((*def, &**body, &**source_map, infer.as_deref())) @@ -191,7 +194,7 @@ impl<'db> SourceAnalyzer<'db> { }) } - fn infer(&self) -> Option<&InferenceResult> { + fn infer(&self) -> Option<&InferenceResult<'db>> { self.body_or_sig.as_ref().and_then(|it| match it { BodyOrSig::Sig { .. } => None, BodyOrSig::VariantFields { .. } => None, @@ -250,7 +253,7 @@ impl<'db> SourceAnalyzer<'db> { if let Pat::Bind { id, .. } = self.store()?[pat_id.as_pat()?] { Some(id) } else { None } } - pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]> { + pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment<'db>]> { // It is safe to omit destructuring assignments here because they have no adjustments (neither // expressions nor patterns). let expr_id = self.expr_id(expr.clone())?.as_expr()?; @@ -288,9 +291,11 @@ impl<'db> SourceAnalyzer<'db> { let coerced = expr_id .as_expr() .and_then(|expr_id| infer.expr_adjustment(expr_id)) - .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone())); - let ty = infer[expr_id].clone(); - let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target)); + let ty = infer[expr_id]; + let mk_ty = |ty: hir_ty::next_solver::Ty<'_>| { + Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) + }; Some((mk_ty(ty), coerced.map(mk_ty))) } @@ -311,8 +316,10 @@ impl<'db> SourceAnalyzer<'db> { } }; - let ty = infer[expr_or_pat_id].clone(); - let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + let ty = infer[expr_or_pat_id]; + let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| { + Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) + }; Some((mk_ty(ty), coerced.map(mk_ty))) } @@ -323,8 +330,10 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option> { let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer()?; - let ty = infer[binding_id].clone(); - let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + let ty = infer[binding_id]; + let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| { + Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) + }; Some(mk_ty(ty)) } @@ -334,8 +343,8 @@ impl<'db> SourceAnalyzer<'db> { _param: &ast::SelfParam, ) -> Option> { let binding = self.body()?.self_param?; - let ty = self.infer()?[binding].clone(); - Some(Type::new_with_resolver(db, &self.resolver, ty)) + let ty = self.infer()?[binding]; + Some(Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))) } pub(crate) fn binding_mode_of_pat( @@ -347,8 +356,10 @@ impl<'db> SourceAnalyzer<'db> { let infer = self.infer()?; infer.binding_mode(id.as_pat()?).map(|bm| match bm { hir_ty::BindingMode::Move => BindingMode::Move, - hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut), - hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => { + hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Mut) => { + BindingMode::Ref(Mutability::Mut) + } + hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Not) => { BindingMode::Ref(Mutability::Shared) } }) @@ -364,7 +375,9 @@ impl<'db> SourceAnalyzer<'db> { infer .pat_adjustment(pat_id.as_pat()?)? .iter() - .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone())) + .map(|ty| { + Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) + }) .collect(), ) } @@ -375,9 +388,8 @@ impl<'db> SourceAnalyzer<'db> { call: &ast::MethodCallExpr, ) -> Option> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; - let (func, substs) = self.infer()?.method_resolution(expr_id)?; + let (func, args) = self.infer()?.method_resolution(expr_id)?; let interner = DbInterner::new_with(db, None, None); - let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); let ty = db.value_ty(func.into())?.instantiate(interner, args); let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner)); let mut res = ty.as_callable(db)?; @@ -403,13 +415,18 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option<(Either, Option>)> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let inference_result = self.infer()?; + let interner = DbInterner::new_with(db, None, None); match inference_result.method_resolution(expr_id) { Some((f_in_trait, substs)) => { let (fn_, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs); Some(( Either::Left(fn_.into()), - Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))), + Some(GenericSubstitution::new( + fn_.into(), + subst.to_chalk(interner), + self.trait_environment(db), + )), )) } None => { @@ -443,7 +460,7 @@ impl<'db> SourceAnalyzer<'db> { fn field_subst( &self, field_expr: ExprId, - infer: &InferenceResult, + infer: &InferenceResult<'db>, db: &'db dyn HirDatabase, ) -> Option> { let body = self.store()?; @@ -451,7 +468,7 @@ impl<'db> SourceAnalyzer<'db> { let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?; return Some(GenericSubstitution::new( adt.into(), - subst.clone(), + subst.to_chalk(DbInterner::conjure()), self.trait_environment(db), )); } @@ -467,6 +484,7 @@ impl<'db> SourceAnalyzer<'db> { let (def, ..) = self.body_()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; + let interner = DbInterner::new_with(db, None, None); match inference_result.field_resolution(expr_id) { Some(field) => match field { Either::Left(field) => Some(( @@ -486,7 +504,11 @@ impl<'db> SourceAnalyzer<'db> { let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs); ( Either::Right(f.into()), - Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))), + Some(GenericSubstitution::new( + f.into(), + subst.to_chalk(interner), + self.trait_environment(db), + )), ) }), } @@ -560,11 +582,11 @@ impl<'db> SourceAnalyzer<'db> { } } - let future_trait = LangItem::Future.resolve_trait(db, self.resolver.krate())?; let poll_fn = LangItem::FuturePoll.resolve_function(db, self.resolver.krate())?; // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself // doesn't have any generic parameters, so we skip building another subst for `poll()`. - let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build(); + let interner = DbInterner::new_with(db, None, None); + let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs)) } @@ -573,7 +595,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, prefix_expr: &ast::PrefixExpr, ) -> Option { - let (op_trait, op_fn) = match prefix_expr.op_kind()? { + let (_op_trait, op_fn) = match prefix_expr.op_kind()? { ast::UnaryOp::Deref => { // This can be either `Deref::deref` or `DerefMut::deref_mut`. // Since deref kind is inferenced and stored in `InferenceResult.method_resolution`, @@ -603,9 +625,10 @@ impl<'db> SourceAnalyzer<'db> { let ty = self.ty_of_expr(prefix_expr.expr()?)?; + let interner = DbInterner::new_with(db, None, None); // HACK: subst for all methods coincides with that for their trait because the methods // don't have any generic parameters, so we skip building another subst for the methods. - let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); + let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -618,27 +641,28 @@ impl<'db> SourceAnalyzer<'db> { let base_ty = self.ty_of_expr(index_expr.base()?)?; let index_ty = self.ty_of_expr(index_expr.index()?)?; - let (index_trait, index_fn) = + let (_index_trait, index_fn) = self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index))?; - let (op_trait, op_fn) = self + let op_fn = self .infer() .and_then(|infer| { let expr = self.expr_id(index_expr.clone().into())?.as_expr()?; let (func, _) = infer.method_resolution(expr)?; - let (index_mut_trait, index_mut_fn) = self.lang_trait_fn( + let (_index_mut_trait, index_mut_fn) = self.lang_trait_fn( db, LangItem::IndexMut, &Name::new_symbol_root(sym::index_mut), )?; - if func == index_mut_fn { Some((index_mut_trait, index_mut_fn)) } else { None } + if func == index_mut_fn { Some(index_mut_fn) } else { None } }) - .unwrap_or((index_trait, index_fn)); + .unwrap_or(index_fn); // HACK: subst for all methods coincides with that for their trait because the methods // don't have any generic parameters, so we skip building another subst for the methods. - let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None) - .push(base_ty.clone()) - .push(index_ty.clone()) - .build(); + let interner = DbInterner::new_with(db, None, None); + let substs = GenericArgs::new_from_iter( + interner, + [base_ty.to_nextsolver(interner).into(), index_ty.to_nextsolver(interner).into()], + ); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -651,14 +675,15 @@ impl<'db> SourceAnalyzer<'db> { let lhs = self.ty_of_expr(binop_expr.lhs()?)?; let rhs = self.ty_of_expr(binop_expr.rhs()?)?; - let (op_trait, op_fn) = lang_items_for_bin_op(op) + let (_op_trait, op_fn) = lang_items_for_bin_op(op) .and_then(|(name, lang_item)| self.lang_trait_fn(db, lang_item, &name))?; // HACK: subst for `index()` coincides with that for `Index` because `index()` itself // doesn't have any generic parameters, so we skip building another subst for `index()`. - let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None) - .push(lhs.clone()) - .push(rhs.clone()) - .build(); + let interner = DbInterner::new_with(db, None, None); + let substs = GenericArgs::new_from_iter( + interner, + [lhs.to_nextsolver(interner).into(), rhs.to_nextsolver(interner).into()], + ); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -671,13 +696,10 @@ impl<'db> SourceAnalyzer<'db> { let ty = self.ty_of_expr(try_expr.expr()?)?; let op_fn = LangItem::TryTraitBranch.resolve_function(db, self.resolver.krate())?; - let op_trait = match op_fn.lookup(db).container { - ItemContainerId::TraitId(id) => id, - _ => return None, - }; // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself // doesn't have any generic parameters, so we skip building another subst for `branch()`. - let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build(); + let interner = DbInterner::new_with(db, None, None); + let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -690,6 +712,7 @@ impl<'db> SourceAnalyzer<'db> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let expr = ast::Expr::from(record_expr); let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?; + let interner = DbInterner::new_with(db, None, None); let ast_name = field.field_name()?; let local_name = ast_name.as_name(); @@ -713,16 +736,17 @@ impl<'db> SourceAnalyzer<'db> { } }; let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?; + let subst = subst.to_chalk(interner); let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?; let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; let field_ty = - db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); + db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst); Some(( field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty), - GenericSubstitution::new(adt.into(), subst.clone(), self.trait_environment(db)), + GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)), )) } @@ -731,6 +755,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, field: &ast::RecordPatField, ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> { + let interner = DbInterner::new_with(db, None, None); let field_name = field.field_name()?.as_name(); let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let pat_id = self.pat_id(&record_pat.into())?; @@ -738,12 +763,13 @@ impl<'db> SourceAnalyzer<'db> { let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?; + let subst = subst.to_chalk(interner); let field_ty = - db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); + db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst); Some(( field.into(), Type::new_with_resolver(db, &self.resolver, field_ty), - GenericSubstitution::new(adt.into(), subst.clone(), self.trait_environment(db)), + GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)), )) } @@ -859,6 +885,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, path: &ast::Path, ) -> Option<(PathResolution, Option>)> { + let interner = DbInterner::new_with(db, None, None); let parent = path.syntax().parent(); let parent = || parent.clone(); @@ -874,29 +901,31 @@ impl<'db> SourceAnalyzer<'db> { None => { let subst = GenericSubstitution::new( f_in_trait.into(), - subs, + subs.to_chalk(interner), self.trait_environment(db), ); (assoc, subst) } Some(func_ty) => { - if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) { + if let TyKind::FnDef(_fn_def, subs) = + func_ty.to_chalk(interner).kind(Interner) + { let (fn_, subst) = self .resolve_impl_method_or_trait_def_with_subst( db, f_in_trait, - subs.clone(), + subs.to_nextsolver(interner), ); let subst = GenericSubstitution::new( fn_.into(), - subst, + subst.to_chalk(interner), self.trait_environment(db), ); (fn_.into(), subst) } else { let subst = GenericSubstitution::new( f_in_trait.into(), - subs, + subs.to_chalk(interner), self.trait_environment(db), ); (assoc, subst) @@ -909,7 +938,7 @@ impl<'db> SourceAnalyzer<'db> { self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); let subst = GenericSubstitution::new( konst.into(), - subst, + subst.to_chalk(interner), self.trait_environment(db), ); (konst.into(), subst) @@ -918,7 +947,7 @@ impl<'db> SourceAnalyzer<'db> { assoc, GenericSubstitution::new( type_alias.into(), - subs, + subs.to_chalk(interner), self.trait_environment(db), ), ), @@ -942,7 +971,7 @@ impl<'db> SourceAnalyzer<'db> { self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); let subst = GenericSubstitution::new( konst.into(), - subst, + subst.to_chalk(interner), self.trait_environment(db), ); (konst.into(), subst) @@ -951,7 +980,7 @@ impl<'db> SourceAnalyzer<'db> { assoc, GenericSubstitution::new( assoc.into(), - subs, + subs.to_chalk(interner), self.trait_environment(db), ), ), @@ -1149,10 +1178,10 @@ impl<'db> SourceAnalyzer<'db> { let parent = parent()?; let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { let expr_id = self.expr_id(expr)?; - self.infer()?.type_of_expr_or_pat(expr_id)? + self.infer()?.type_of_expr_or_pat(expr_id)?.to_chalk(interner) } else if let Some(pat) = ast::Pat::cast(parent) { let pat_id = self.pat_id(&pat)?; - &self.infer()?[pat_id] + self.infer()?[pat_id].to_chalk(interner) } else { return None; }; @@ -1232,7 +1261,8 @@ impl<'db> SourceAnalyzer<'db> { record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])? } }; - let res = self.missing_fields(db, substs, variant, missing_fields); + let interner = DbInterner::new_with(db, None, None); + let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields); Some(res) } @@ -1249,7 +1279,8 @@ impl<'db> SourceAnalyzer<'db> { let (variant, missing_fields, _exhaustive) = record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; - let res = self.missing_fields(db, substs, variant, missing_fields); + let interner = DbInterner::new_with(db, None, None); + let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields); Some(res) } @@ -1379,7 +1410,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, func: FunctionId, - substs: Substitution, + substs: GenericArgs<'db>, ) -> FunctionId { self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0 } @@ -1388,8 +1419,8 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, func: FunctionId, - substs: Substitution, - ) -> (FunctionId, Substitution) { + substs: GenericArgs<'db>, + ) -> (FunctionId, GenericArgs<'db>) { let owner = match self.resolver.body_owner() { Some(it) => it, None => return (func, substs), @@ -1402,14 +1433,19 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, const_id: ConstId, - subs: Substitution, - ) -> (ConstId, Substitution) { + subs: GenericArgs<'db>, + ) -> (ConstId, GenericArgs<'db>) { let owner = match self.resolver.body_owner() { Some(it) => it, None => return (const_id, subs), }; let env = db.trait_environment_for_body(owner); - method_resolution::lookup_impl_const(db, env, const_id, subs) + method_resolution::lookup_impl_const( + DbInterner::new_with(db, None, None), + env, + const_id, + subs, + ) } fn lang_trait_fn( @@ -1423,8 +1459,10 @@ impl<'db> SourceAnalyzer<'db> { Some((trait_id, fn_id)) } - fn ty_of_expr(&self, expr: ast::Expr) -> Option<&Ty> { - self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?) + fn ty_of_expr(&self, expr: ast::Expr) -> Option { + self.infer()? + .type_of_expr_or_pat(self.expr_id(expr)?) + .map(|ty| ty.to_chalk(DbInterner::conjure())) } } 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 3dd435d9423b2..2cda6d6f1c0a4 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 @@ -506,7 +506,7 @@ fn wrap_capture_in_deref_if_needed( make::expr_prefix(T![*], capture_name).into() } -fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr { +fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture<'_>) -> ast::Expr { let place = parse_expr_from_str(&capture.display_place_source_code(ctx.db()), ctx.edition()) .expect("`display_place_source_code()` produced an invalid expr"); let needs_mut = match capture.kind() { 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 dbf68dbe33afe..094e679501fc2 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -2987,7 +2987,6 @@ fn main() { &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)], expect![[r#" sn not !expr [snippet] - me not() fn(self) -> ::Output [type_could_unify+requires_import] sn box Box::new(expr) [] sn call function(expr) [] sn const const {} [] @@ -3001,6 +3000,7 @@ fn main() { sn return return expr [] sn unsafe unsafe {} [] sn while while expr {} [] + me not() fn(self) -> ::Output [requires_import] "#]], ); } 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 8613581292f75..e6702ccf13999 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 @@ -1170,7 +1170,7 @@ trait B {} fn test(a: &dyn A) -> &dyn B { a - //^ error: expected &dyn B, found &dyn A + //^ error: expected &(dyn B + 'static), found &(dyn A + 'static) } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 595f0bb5fa8af..9c0b9a6ff99bb 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -791,6 +791,8 @@ impl PatternIterator { #[cfg(test)] mod tests { + use ide_db::base_db::salsa; + use crate::{MatchFinder, SsrRule}; #[test] @@ -799,33 +801,35 @@ mod tests { let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }"; let (db, position, selections) = crate::tests::single_file(input); - let position = ide_db::FilePosition { - file_id: position.file_id.file_id(&db), - offset: position.offset, - }; - let mut match_finder = MatchFinder::in_context( - &db, - position, - selections - .into_iter() - .map(|frange| ide_db::FileRange { - file_id: frange.file_id.file_id(&db), - range: frange.range, - }) - .collect(), - ) - .unwrap(); - match_finder.add_rule(rule).unwrap(); - let matches = match_finder.matches(); - assert_eq!(matches.matches.len(), 1); - assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)"); - assert_eq!(matches.matches[0].placeholder_values.len(), 1); - - let edits = match_finder.edits(); - assert_eq!(edits.len(), 1); - let edit = &edits[&position.file_id]; - let mut after = input.to_owned(); - edit.apply(&mut after); - assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }"); + salsa::attach(&db, || { + let position = ide_db::FilePosition { + file_id: position.file_id.file_id(&db), + offset: position.offset, + }; + let mut match_finder = MatchFinder::in_context( + &db, + position, + selections + .into_iter() + .map(|frange| ide_db::FileRange { + file_id: frange.file_id.file_id(&db), + range: frange.range, + }) + .collect(), + ) + .unwrap(); + match_finder.add_rule(rule).unwrap(); + let matches = match_finder.matches(); + assert_eq!(matches.matches.len(), 1); + assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)"); + assert_eq!(matches.matches[0].placeholder_values.len(), 1); + + let edits = match_finder.edits(); + assert_eq!(edits.len(), 1); + let edit = &edits[&position.file_id]; + let mut after = input.to_owned(); + edit.apply(&mut after); + assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }"); + }); } } 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 875b4d9b06cec..24ad3ba7efe0b 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs @@ -101,33 +101,37 @@ fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { let (db, position, selections) = single_file(input); - let position = - ide_db::FilePosition { file_id: position.file_id.file_id(&db), offset: position.offset }; - let mut match_finder = MatchFinder::in_context( - &db, - position, - selections - .into_iter() - .map(|selection| ide_db::FileRange { - file_id: selection.file_id.file_id(&db), - range: selection.range, - }) - .collect(), - ) - .unwrap(); - for rule in rules { - let rule: SsrRule = rule.parse().unwrap(); - match_finder.add_rule(rule).unwrap(); - } - let edits = salsa::attach(&db, || match_finder.edits()); - if edits.is_empty() { - panic!("No edits were made"); - } - // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters - // stuff. - let mut actual = db.file_text(position.file_id).text(&db).to_string(); - edits[&position.file_id].apply(&mut actual); - expected.assert_eq(&actual); + salsa::attach(&db, || { + let position = ide_db::FilePosition { + file_id: position.file_id.file_id(&db), + offset: position.offset, + }; + let mut match_finder = MatchFinder::in_context( + &db, + position, + selections + .into_iter() + .map(|selection| ide_db::FileRange { + file_id: selection.file_id.file_id(&db), + range: selection.range, + }) + .collect(), + ) + .unwrap(); + for rule in rules { + let rule: SsrRule = rule.parse().unwrap(); + match_finder.add_rule(rule).unwrap(); + } + let edits = match_finder.edits(); + if edits.is_empty() { + panic!("No edits were made"); + } + // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters + // stuff. + let mut actual = db.file_text(position.file_id).text(&db).to_string(); + edits[&position.file_id].apply(&mut actual); + expected.assert_eq(&actual); + }) } #[allow(clippy::print_stdout)] @@ -145,51 +149,57 @@ fn print_match_debug_info(match_finder: &MatchFinder<'_>, file_id: EditionedFile fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { let (db, position, selections) = single_file(code); - let mut match_finder = MatchFinder::in_context( - &db, - ide_db::FilePosition { file_id: position.file_id.file_id(&db), offset: position.offset }, - selections - .into_iter() - .map(|selection| ide_db::FileRange { - file_id: selection.file_id.file_id(&db), - range: selection.range, - }) - .collect(), - ) - .unwrap(); - match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - 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]); - } - assert_eq!(matched_strings, expected); + salsa::attach(&db, || { + let mut match_finder = MatchFinder::in_context( + &db, + ide_db::FilePosition { + file_id: position.file_id.file_id(&db), + offset: position.offset, + }, + selections + .into_iter() + .map(|selection| ide_db::FileRange { + file_id: selection.file_id.file_id(&db), + range: selection.range, + }) + .collect(), + ) + .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(); + if matched_strings != expected && !expected.is_empty() { + print_match_debug_info(&match_finder, position.file_id, expected[0]); + } + assert_eq!(matched_strings, expected); + }) } fn assert_no_match(pattern: &str, code: &str) { let (db, position, selections) = single_file(code); - let mut match_finder = MatchFinder::in_context( - &db, - ide_db::FilePosition { file_id: position.file_id.file_id(&db), offset: position.offset }, - selections - .into_iter() - .map(|selection| ide_db::FileRange { - file_id: selection.file_id.file_id(&db), - range: selection.range, - }) - .collect(), - ) - .unwrap(); - match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); - let matches = match_finder.matches().flattened().matches; - if !matches.is_empty() { - print_match_debug_info(&match_finder, position.file_id, &matches[0].matched_text()); - panic!("Got {} matches when we expected none: {matches:#?}", matches.len()); - } + salsa::attach(&db, || { + let mut match_finder = MatchFinder::in_context( + &db, + ide_db::FilePosition { + file_id: position.file_id.file_id(&db), + offset: position.offset, + }, + selections + .into_iter() + .map(|selection| ide_db::FileRange { + file_id: selection.file_id.file_id(&db), + range: selection.range, + }) + .collect(), + ) + .unwrap(); + match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); + let matches = match_finder.matches().flattened().matches; + if !matches.is_empty() { + print_match_debug_info(&match_finder, position.file_id, &matches[0].matched_text()); + panic!("Got {} matches when we expected none: {matches:#?}", matches.len()); + } + }); } fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &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 b7c124139608b..121b16b97e871 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 @@ -646,9 +646,9 @@ auto trait Sync {} fn main() { // The block expression wrapping disables the constructor hint hiding logic let _v = { Vec::>::new() }; - //^^ Vec> + //^^ Vec> let _v = { Vec::>::new() }; - //^^ Vec> + //^^ Vec> let _v = { Vec::>::new() }; //^^ Vec> } diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs index 8f9d2d6bf111b..05cd145033bf4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs @@ -60,7 +60,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura pub(crate) fn render_const_eval_error( db: &RootDatabase, - e: ConstEvalError, + e: ConstEvalError<'_>, display_target: DisplayTarget, ) -> String { let span_formatter = |file_id, text_range: TextRange| { 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 9911b85799b62..3f3d36bde2fa6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -228,32 +228,30 @@ impl StaticIndex<'_> { let id = if let Some(it) = self.def_map.get(&def) { *it } else { - 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(&sema).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 = 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(&sema).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 @@ -295,37 +293,40 @@ impl StaticIndex<'_> { vendored_libs_config: VendoredLibrariesConfig<'_>, ) -> StaticIndex<'a> { let db = &analysis.db; - 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(&analysis.db)).source_root_id(db); - let source_root = db.source_root(source_root).source_root(db); - let is_vendored = match vendored_libs_config { - VendoredLibrariesConfig::Included { workspace_root } => source_root - .path_for_file(&file_id.file_id(&analysis.db)) - .is_some_and(|module_path| module_path.starts_with(workspace_root)), - VendoredLibrariesConfig::Excluded => false, + salsa::attach(db, || { + 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(&analysis.db)).source_root_id(db); + let source_root = db.source_root(source_root).source_root(db); + let is_vendored = match vendored_libs_config { + VendoredLibrariesConfig::Included { workspace_root } => source_root + .path_for_file(&file_id.file_id(&analysis.db)) + .is_some_and(|module_path| module_path.starts_with(workspace_root)), + VendoredLibrariesConfig::Excluded => false, + }; + + !source_root.is_library || is_vendored + }); + let mut this = StaticIndex { + files: vec![], + tokens: Default::default(), + analysis, + db, + def_map: Default::default(), }; - - !source_root.is_library || is_vendored - }); - let mut this = StaticIndex { - files: vec![], - tokens: Default::default(), - analysis, - db, - def_map: Default::default(), - }; - let mut visited_files = FxHashSet::default(); - for module in work { - let file_id = module.definition_source_file_id(db).original_file(db); - if visited_files.contains(&file_id) { - continue; + let mut visited_files = FxHashSet::default(); + for module in work { + let file_id = module.definition_source_file_id(db).original_file(db); + if visited_files.contains(&file_id) { + continue; + } + this.add_file(file_id.file_id(&analysis.db)); + // mark the file + visited_files.insert(file_id); } - this.add_file(file_id.file_id(&analysis.db)); - // mark the file - visited_files.insert(file_id); - } - this + this + }) } } 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 4e43387f8d9da..720183ac5478d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -426,9 +426,12 @@ fn traverse( let edition = descended_element.file_id.edition(sema.db); let (unsafe_ops, bindings_shadow_count) = match current_body { Some(current_body) => { - let (ops, bindings) = per_body_cache - .entry(current_body) - .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default())); + let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| { + ( + salsa::attach(sema.db, || sema.get_unsafe_ops(current_body)), + Default::default(), + ) + }); (&*ops, Some(bindings)) } None => (&empty, None), 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 ddd58a0a3c9fb..b014261981769 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,7 +3,6 @@ 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}, }; @@ -94,14 +93,14 @@ pub(crate) fn view_memory_layout( let def = get_definition(&sema, token)?; let ty = match def { - Definition::Adt(it) => salsa::attach(db, || it.ty(db)), - Definition::TypeAlias(it) => salsa::attach(db, || it.ty(db)), + Definition::Adt(it) => it.ty(db), + Definition::TypeAlias(it) => it.ty(db), Definition::BuiltinType(it) => it.ty(db), Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), - Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)), - Definition::Const(it) => salsa::attach(db, || it.ty(db)), - Definition::Static(it) => salsa::attach(db, || it.ty(db)), + Definition::Field(it) => it.ty(db).to_type(db), + Definition::Const(it) => it.ty(db), + Definition::Static(it) => it.ty(db), _ => return None, }; @@ -139,12 +138,10 @@ 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) = salsa::attach(db, || child_ty.layout(db)) { + if let Ok(child_layout) = child_ty.layout(db) { nodes.push(MemoryLayoutNode { item_name: field.name(db), - typename: salsa::attach(db, || { - child_ty.display(db, display_target).to_string() - }), + typename: { child_ty.display(db, display_target).to_string() }, size: child_layout.size(), alignment: child_layout.align(), offset: match *field { @@ -172,13 +169,13 @@ pub(crate) fn view_memory_layout( } for (i, (_, child_ty)) in fields.iter().enumerate() { - if let Ok(child_layout) = salsa::attach(db, || child_ty.layout(db)) { + if let Ok(child_layout) = child_ty.layout(db) { read_layout(nodes, db, child_ty, &child_layout, children_start + i, display_target); } } } - salsa::attach(db, || ty.layout(db)) + ty.layout(db) .map(|layout| { let item_name = match def { // def is a datatype @@ -191,7 +188,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 = salsa::attach(db, || ty.display(db, display_target).to_string()); + let typename = ty.display(db, display_target).to_string(); let mut nodes = vec![MemoryLayoutNode { item_name, @@ -216,13 +213,14 @@ mod tests { use crate::fixture; use expect_test::expect; + use ide_db::base_db::salsa; fn make_memory_layout( #[rust_analyzer::rust_fixture] ra_fixture: &str, ) -> Option { let (analysis, position, _) = fixture::annotations(ra_fixture); - view_memory_layout(&analysis.db, position) + salsa::attach(&analysis.db, || view_memory_layout(&analysis.db, position)) } #[test] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index b301a7189b3c9..c746f848b6a06 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -75,6 +75,8 @@ vfs-notify.workspace = true vfs.workspace = true paths.workspace = true +ra-ap-rustc_type_ir.workspace = true + [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.60", features = [ "Win32_System_Diagnostics_Debug", 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 9551536cf4a51..9c8743536877b 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 @@ -20,14 +20,16 @@ use hir_def::{ expr_store::BodySourceMap, hir::{ExprId, PatId}, }; -use hir_ty::{Interner, TyExt, TypeFlags}; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RootDatabase, }; use ide_db::{ EditionedFileId, LineIndexDatabase, SnippetCap, - base_db::{SourceDatabase, salsa::Database}, + base_db::{ + SourceDatabase, + salsa::{self, Database}, + }, }; use itertools::Itertools; use load_cargo::{LoadCargoConfig, ProcMacroServerChoice, load_workspace}; @@ -36,6 +38,7 @@ use profile::StopWatch; use project_model::{CargoConfig, CfgOverrides, ProjectManifest, ProjectWorkspace, RustLibSource}; use rayon::prelude::*; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::Ty as _; use syntax::AstNode; use vfs::{AbsPathBuf, Vfs, VfsPath}; @@ -312,33 +315,35 @@ impl flags::AnalysisStats { shuffle(&mut rng, &mut bodies); } - if !self.skip_lowering { - self.run_body_lowering(db, &vfs, &bodies, verbosity); - } + salsa::attach(db, || { + if !self.skip_lowering { + self.run_body_lowering(db, &vfs, &bodies, verbosity); + } - if !self.skip_inference { - self.run_inference(db, &vfs, &bodies, verbosity); - } + if !self.skip_inference { + self.run_inference(db, &vfs, &bodies, verbosity); + } - if !self.skip_mir_stats { - self.run_mir_lowering(db, &bodies, verbosity); - } + if !self.skip_mir_stats { + self.run_mir_lowering(db, &bodies, verbosity); + } - if !self.skip_data_layout { - self.run_data_layout(db, &adts, verbosity); - } + if !self.skip_data_layout { + self.run_data_layout(db, &adts, verbosity); + } - if !self.skip_const_eval { - self.run_const_eval(db, &bodies, verbosity); - } + if !self.skip_const_eval { + self.run_const_eval(db, &bodies, verbosity); + } - if self.run_all_ide_things { - self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); - } + if self.run_all_ide_things { + self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); + } - if self.run_term_search { - self.run_term_search(&workspace, db, &vfs, file_ids, verbosity); - } + if self.run_term_search { + self.run_term_search(&workspace, db, &vfs, file_ids, verbosity); + } + }); let db = host.raw_database_mut(); db.trigger_lru_eviction(); @@ -814,7 +819,7 @@ impl flags::AnalysisStats { for (expr_id, _) in body.exprs() { let ty = &inference_result[expr_id]; num_exprs += 1; - let unknown_or_partial = if ty.is_unknown() { + let unknown_or_partial = if ty.is_ty_error() { num_exprs_unknown += 1; if verbosity.is_spammy() { if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) @@ -836,8 +841,7 @@ impl flags::AnalysisStats { } true } else { - let is_partially_unknown = - ty.data(Interner).flags.contains(TypeFlags::HAS_ERROR); + let is_partially_unknown = ty.references_non_lt_error(); if is_partially_unknown { num_exprs_partially_unknown += 1; } @@ -919,7 +923,7 @@ impl flags::AnalysisStats { for (pat_id, _) in body.pats() { let ty = &inference_result[pat_id]; num_pats += 1; - let unknown_or_partial = if ty.is_unknown() { + let unknown_or_partial = if ty.is_ty_error() { num_pats_unknown += 1; if verbosity.is_spammy() { if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { @@ -940,8 +944,7 @@ impl flags::AnalysisStats { } true } else { - let is_partially_unknown = - ty.data(Interner).flags.contains(TypeFlags::HAS_ERROR); + let is_partially_unknown = ty.references_non_lt_error(); if is_partially_unknown { num_pats_partially_unknown += 1; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 0dea285e97bd4..44af8fbddf300 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -9,6 +9,8 @@ //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. +extern crate ra_ap_rustc_type_ir as rustc_type_ir; + /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version { major: 1, From 083d279d2e58cdc4ed7ae50b7de0b078e465db13 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 27 Sep 2025 15:38:24 +0800 Subject: [PATCH 12/59] Add else-block support for convert_to_guarded_return Add support for else-block of never-type for `convert_to_guarded_return` Example --- ```rust fn main() { if$0 let Ok(x) = Err(92) { foo(x); } else { return } } ``` **Before this PR**: Assist not applicable **After this PR**: ```rust fn main() { let Ok(x) = Err(92) else { return }; foo(x); } ``` --- .../src/handlers/convert_to_guarded_return.rs | 89 +++++++++++++++---- .../crates/ide-assists/src/utils.rs | 16 ++++ 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 82213ae3217e7..1ebb114cdbb60 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -17,7 +17,7 @@ use syntax::{ use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::invert_boolean_expression_legacy, + utils::{invert_boolean_expression_legacy, is_never_block}, }; // Assist: convert_to_guarded_return @@ -54,9 +54,13 @@ fn if_expr_to_guarded_return( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - if if_expr.else_branch().is_some() { - return None; - } + let else_block = match if_expr.else_branch() { + Some(ast::ElseBranch::Block(block_expr)) if is_never_block(&ctx.sema, &block_expr) => { + Some(block_expr) + } + Some(_) => return None, + _ => None, + }; let cond = if_expr.condition()?; @@ -96,7 +100,11 @@ fn if_expr_to_guarded_return( let parent_container = parent_block.syntax().parent()?; - let early_expression: ast::Expr = early_expression(parent_container, &ctx.sema)?; + let early_expression = else_block + .or_else(|| { + early_expression(parent_container, &ctx.sema).map(ast::make::tail_only_block_expr) + })? + .reset_indent(); then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?; @@ -123,21 +131,14 @@ fn if_expr_to_guarded_return( && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr()) { // If-let. - let let_else_stmt = make::let_else_stmt( - pat, - None, - expr, - ast::make::tail_only_block_expr(early_expression.clone()), - ); + let let_else_stmt = + make::let_else_stmt(pat, None, expr, early_expression.clone()); let let_else_stmt = let_else_stmt.indent(if_indent_level); let_else_stmt.syntax().clone() } else { // If. let new_expr = { - let then_branch = make::block_expr( - once(make::expr_stmt(early_expression.clone()).into()), - None, - ); + let then_branch = clean_stmt_block(&early_expression); let cond = invert_boolean_expression_legacy(expr); make::expr_if(cond, then_branch, None).indent(if_indent_level) }; @@ -272,6 +273,17 @@ fn flat_let_chain(mut expr: ast::Expr) -> Vec { chains } +fn clean_stmt_block(block: &ast::BlockExpr) -> ast::BlockExpr { + if block.statements().next().is_none() + && let Some(tail_expr) = block.tail_expr() + && block.modifier().is_none() + { + make::block_expr(once(make::expr_stmt(tail_expr).into()), None) + } else { + block.clone() + } +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -421,6 +433,53 @@ fn main() { ); } + #[test] + fn convert_if_let_has_never_type_else_block() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 let Ok(x) = Err(92) { + foo(x); + } else { + // needless comment + return; + } +} +"#, + r#" +fn main() { + let Ok(x) = Err(92) else { + // needless comment + return; + }; + foo(x); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 let Ok(x) = Err(92) { + foo(x); + } else { + return + } +} +"#, + r#" +fn main() { + let Ok(x) = Err(92) else { + return + }; + foo(x); +} +"#, + ); + } + #[test] fn convert_if_let_result_inside_let() { check_assist( 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 20e0302b57d70..36b44554f1494 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1150,3 +1150,19 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo }); is_const } + +// FIXME: #20460 When hir-ty can analyze the `never` statement at the end of block, remove it +pub(crate) fn is_never_block( + sema: &Semantics<'_, RootDatabase>, + block_expr: &ast::BlockExpr, +) -> bool { + if let Some(tail_expr) = block_expr.tail_expr() { + sema.type_of_expr(&tail_expr).is_some_and(|ty| ty.original.is_never()) + } else if let Some(ast::Stmt::ExprStmt(expr_stmt)) = block_expr.statements().last() + && let Some(expr) = expr_stmt.expr() + { + sema.type_of_expr(&expr).is_some_and(|ty| ty.original.is_never()) + } else { + false + } +} From ca0f3d16c4accc292848cf429a5ea41806d5f277 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 30 Sep 2025 18:48:54 +0300 Subject: [PATCH 13/59] Ignore impl trait safety errors when the trait is unresolved --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 11 +++++++++-- .../src/handlers/trait_impl_incorrect_safety.rs | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 9198086e9e6cb..2c1e05ca44464 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -753,7 +753,7 @@ impl Module { GenericDef::Impl(impl_def).diagnostics(db, acc); let loc = impl_def.id.lookup(db); - let source_map = db.impl_signature_with_source_map(impl_def.id).1; + let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id); expr_store_diagnostics(db, acc, &source_map); let file_id = loc.id.file_id; @@ -782,10 +782,17 @@ impl Module { } let trait_ = impl_def.trait_(db); - let trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); + let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); let impl_is_negative = impl_def.is_negative(db); let impl_is_unsafe = impl_def.is_unsafe(db); + let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some(); + if trait_is_unresolved { + // Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe, + // which may not be correct. + trait_is_unsafe = impl_is_unsafe; + } + let drop_maybe_dangle = (|| { // FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper let trait_ = trait_?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index dd142db8590fb..3414e972d5c90 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -127,4 +127,13 @@ struct S; "#, ); } + + #[test] + fn unsafe_unresolved_trait() { + check_diagnostics( + r#" +unsafe impl TestTrait for u32 {} + "#, + ); + } } From b19df975432b98c37fd37733d3c37b38e4a02b2f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 22 Sep 2025 05:13:24 +0300 Subject: [PATCH 14/59] Prevent rustup from automatically installing toolchains By setting RUSTUP_AUTO_INSTALL=0. --- .../crates/project-model/src/cargo_workspace.rs | 9 +++++---- .../rust-analyzer/crates/project-model/src/workspace.rs | 5 +++-- src/tools/rust-analyzer/crates/toolchain/src/lib.rs | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index adc0cc5094166..04fb2275893c7 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -13,12 +13,12 @@ use serde_derive::Deserialize; use serde_json::from_value; use span::Edition; use stdx::process::spawn_with_streaming_output; -use toolchain::Tool; +use toolchain::{NO_RUSTUP_AUTO_INSTALL_ENV, Tool}; use triomphe::Arc; -use crate::cargo_config_file::make_lockfile_copy; -use crate::{CfgOverrides, InvocationStrategy}; -use crate::{ManifestPath, Sysroot}; +use crate::{ + CfgOverrides, InvocationStrategy, ManifestPath, Sysroot, cargo_config_file::make_lockfile_copy, +}; pub(crate) const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = semver::Version { @@ -632,6 +632,7 @@ impl FetchMetadata { ) -> Self { let cargo = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env); let mut command = MetadataCommand::new(); + command.env(NO_RUSTUP_AUTO_INSTALL_ENV.0, NO_RUSTUP_AUTO_INSTALL_ENV.1); command.cargo_path(cargo.get_program()); cargo.get_envs().for_each(|(var, val)| _ = command.env(var, val.unwrap_or_default())); command.manifest_path(cargo_toml.to_path_buf()); 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 e0d2105c8df89..0649ce9eeb9df 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -16,8 +16,9 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use span::{Edition, FileId}; -use toolchain::Tool; +use toolchain::{NO_RUSTUP_AUTO_INSTALL_ENV, Tool}; use tracing::instrument; +use tracing::{debug, error, info}; use triomphe::Arc; use crate::{ @@ -33,7 +34,6 @@ use crate::{ toolchain_info::{QueryConfig, rustc_cfg, target_data, target_tuple, version}, utf8_stdout, }; -use tracing::{debug, error, info}; pub type FileLoader<'a> = &'a mut dyn for<'b> FnMut(&'b AbsPath) -> Option; @@ -1907,6 +1907,7 @@ fn cargo_target_dir( ) -> Option { let cargo = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env); let mut meta = cargo_metadata::MetadataCommand::new(); + meta.env(NO_RUSTUP_AUTO_INSTALL_ENV.0, NO_RUSTUP_AUTO_INSTALL_ENV.1); meta.cargo_path(cargo.get_program()); meta.manifest_path(manifest); // `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve. diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 8b7bf1a806415..39319886cfe4a 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -71,6 +71,9 @@ impl Tool { } } +// Prevent rustup from automatically installing toolchains, see https://github.com/rust-lang/rust-analyzer/issues/20719. +pub const NO_RUSTUP_AUTO_INSTALL_ENV: (&str, &str) = ("RUSTUP_AUTO_INSTALL", "0"); + #[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ pub fn command( cmd: impl AsRef, @@ -81,6 +84,7 @@ pub fn command( #[allow(clippy::disallowed_methods)] let mut cmd = Command::new(cmd); cmd.current_dir(working_directory); + cmd.env(NO_RUSTUP_AUTO_INSTALL_ENV.0, NO_RUSTUP_AUTO_INSTALL_ENV.1); for env in extra_env { match env { (key, Some(val)) => cmd.env(key, val), From 3f0ae50c42f019df9182168bc533641e892a9eee Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 1 Oct 2025 12:53:31 +0800 Subject: [PATCH 15/59] Fix not applicable match inside if for pull_assignment_up Example --- ```rust fn foo() { let x; if true { match true { true => $0x = 2, false => x = 3, } } } ``` **Before this PR**: Assist not applicable **After this PR**: ```rust fn foo() { let x; if true { x = match true { true => 2, false => 3, }; } } ``` --- .../src/handlers/pull_assignment_up.rs | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs index 00902fafe8278..812ebf6c6e289 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs @@ -1,3 +1,4 @@ +use either::Either; use syntax::{ AstNode, algo::find_node_at_range, @@ -52,14 +53,15 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) -> assignments: Vec::new(), }; - let tgt: ast::Expr = if let Some(if_expr) = ctx.find_node_at_offset::() { + let node: Either = ctx.find_node_at_offset()?; + let tgt: ast::Expr = if let Either::Left(if_expr) = node { let if_expr = std::iter::successors(Some(if_expr), |it| { it.syntax().parent().and_then(ast::IfExpr::cast) }) .last()?; collector.collect_if(&if_expr)?; if_expr.into() - } else if let Some(match_expr) = ctx.find_node_at_offset::() { + } else if let Either::Right(match_expr) = node { collector.collect_match(&match_expr)?; match_expr.into() } else { @@ -311,6 +313,33 @@ fn foo() { ); } + #[test] + fn test_pull_assignment_up_match_in_if_expr() { + check_assist( + pull_assignment_up, + r#" +fn foo() { + let x; + if true { + match true { + true => $0x = 2, + false => x = 3, + } + } +}"#, + r#" +fn foo() { + let x; + if true { + x = match true { + true => 2, + false => 3, + }; + } +}"#, + ); + } + #[test] fn test_pull_assignment_up_assignment_expressions() { check_assist( From 7a8a5763291aca2f6ba9609849ebbaaaaab951b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 1 Oct 2025 09:10:56 +0300 Subject: [PATCH 16/59] Build x86_64-apple-darwin binaries on macos-14 --- src/tools/rust-analyzer/.github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 5bd90130f4c21..7ccbdd91de391 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -52,7 +52,7 @@ jobs: target: arm-unknown-linux-gnueabihf zig_target: arm-unknown-linux-gnueabihf.2.28 code-target: linux-armhf - - os: macos-13 + - os: macos-14 target: x86_64-apple-darwin code-target: darwin-x64 pgo: clap-rs/clap@v4.5.36 From 981da22e5e009cec48eb93ce254c15d5cb1a3570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 1 Oct 2025 09:11:51 +0300 Subject: [PATCH 17/59] Bump MACOSX_DEPLOYMENT_TARGET to 14.0 --- src/tools/rust-analyzer/.github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 7ccbdd91de391..b6f430f14051e 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -16,7 +16,7 @@ env: RUSTFLAGS: "-D warnings -W unreachable-pub" RUSTUP_MAX_RETRIES: 10 FETCH_DEPTH: 0 # pull in the tags for the version string - MACOSX_DEPLOYMENT_TARGET: 13.0 + MACOSX_DEPLOYMENT_TARGET: 14.0 ZIG_VERSION: 0.13.0 ZIGBUILD_VERSION: 0.19.8 From 0ea569f7ae45464970a83dde09cd64ea6f247608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20M=2E=20Martins?= Date: Thu, 2 Oct 2025 13:33:53 +1000 Subject: [PATCH 18/59] fixes small typos in docs and indent issue --- .../docs/book/src/configuration.md | 2 +- .../docs/book/src/contributing/guide.md | 2 +- .../book/src/contributing/lsp-extensions.md | 22 +++++++++---------- .../docs/book/src/contributing/syntax.md | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/docs/book/src/configuration.md b/src/tools/rust-analyzer/docs/book/src/configuration.md index fd94a4221a927..3f4cb197141fe 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration.md @@ -13,7 +13,7 @@ Vim](./other_editors.md#coc-rust-analyzer) provide `rust-analyzer` specific conf UIs. Others may require you to know a bit more about the interaction with `rust-analyzer`. -For the later category, it might help to know that the initial +For the latter category, it might help to know that the initial configuration is specified as a value of the `initializationOptions` field of the [`InitializeParams` message, in the LSP protocol](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize). diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/guide.md b/src/tools/rust-analyzer/docs/book/src/contributing/guide.md index 2a2a39af2641c..d06840368ccbf 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/guide.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/guide.md @@ -235,7 +235,7 @@ of type `V`. Queries come in two basic varieties: intelligently) when we can re-use these memoized values and when we have to recompute them. -For further discussion, its important to understand one bit of "fairly +For further discussion, it's important to understand one bit of "fairly intelligently". Suppose we have two functions, `f1` and `f2`, and one input, `z`. We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)` returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md index 8c06f33a9f7bf..91154b6f1c87d 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md @@ -455,7 +455,7 @@ interface TestItem { // A human readable name for this test label: string; // The kind of this test item. Based on the kind, - // an icon is chosen by the editor. + // an icon is chosen by the editor. kind: "package" | "module" | "test"; // True if this test may have children not available eagerly canResolveChildren: boolean; @@ -467,7 +467,7 @@ interface TestItem { // like debugging, this field is useful. // Note that this field includes some information about label and location as well, but // those exist just for keeping things in sync with other methods of running runnables - // (for example using one consistent name in the vscode's launch.json) so for any propose + // (for example using one consistent name in the vscode's launch.json) so for any purpose // other than running tests this field should not be used. runnable?: Runnable | undefined; }; @@ -475,11 +475,11 @@ interface TestItem { interface DiscoverTestResults { // The discovered tests. tests: TestItem[]; - // For each test which its id is in this list, the response + // For each test whose id is in this list, the response // contains all tests that are children of this test, and // client should remove old tests not included in the response. scope: string[] | undefined; - // For each file which its uri is in this list, the response + // For each file whose uri is in this list, the response // contains all tests that are located in this file, and // client should remove old tests not included in the response. scopeFile: lc.TextDocumentIdentifier[] | undefined; @@ -491,7 +491,7 @@ interface DiscoverTestResults { **Notification:** `DiscoverTestResults` This notification is sent from the server to the client when the -server detect changes in the existing tests. The `DiscoverTestResults` is +server detects changes in the existing tests. The `DiscoverTestResults` is the same as the one in `experimental/discoverTest` response. **Method:** `experimental/runTest` @@ -527,7 +527,7 @@ after this. This notification is sent from the client to the server when the user is no longer interested in the test results. The server should clean up its resources and send -a `experimental/endRunTest` when is done. +a `experimental/endRunTest` when it is done. **Method:** `experimental/changeTestState` @@ -648,8 +648,8 @@ interface ServerStatusParams { ``` This notification is sent from server to client. -The client can use it to display *persistent* status to the user (in modline). -It is similar to the `showMessage`, but is intended for stares rather than point-in-time events. +The client can use it to display *persistent* status to the user (in the mode line). +It is similar to the `showMessage`, but is intended for status rather than point-in-time events. Note that this functionality is intended primarily to inform the end user about the state of the server. In particular, it's valid for the client to completely ignore this extension. @@ -1070,13 +1070,13 @@ export interface RecursiveMemoryLayoutNode = { size: number; /// Alignment of the type in bytes alignment: number; - /// Offset of the type relative to its parent (or 0 if its the root) + /// Offset of the type relative to its parent (or 0 if it's the root) offset: number; - /// Index of the node's parent (or -1 if its the root) + /// Index of the node's parent (or -1 if it's the root) parent_idx: number; /// Index of the node's children (or -1 if it does not have children) children_start: number; - /// Number of child nodes (unspecified it does not have children) + /// Number of child nodes (unspecified if it does not have children) children_len: number; }; diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md b/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md index 3dcd430cea5d5..93eed7228d05f 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md @@ -192,7 +192,7 @@ Modeling this with immutable trees is possible, but annoying. A function green tree is not super-convenient to use. The biggest problem is accessing parents (there are no parent pointers!). -But there are also "identify" issues. +But there are also "identity" issues. Let's say you want to write a code which builds a list of expressions in a file: `fn collect_expressions(file: GreenNode) -> HashSet`. For the input like From 1c234917634f3522b3a44551c49095dcadf04f8d Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Wed, 1 Oct 2025 22:41:01 -0500 Subject: [PATCH 19/59] Fix two small things clippy was complaining about --- .../ide-completion/src/completions/attribute/cfg.rs | 2 +- src/tools/rust-analyzer/crates/ide-db/src/assists.rs | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index b2e8efde8bebc..b6739c9f75a28 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -39,7 +39,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { "target_os" => KNOWN_OS.iter().copied().for_each(add_completion), "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion), "target_endian" => ["little", "big"].into_iter().for_each(add_completion), - name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| { + name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).for_each(|s| { let s = s.as_str(); let insert_text = format!(r#""{s}""#); let mut item = CompletionItem::new( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs index 384eb57c0fd59..12406efc39cee 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs @@ -170,14 +170,10 @@ impl AssistResolveStrategy { #[derive(Clone, Debug)] pub struct GroupLabel(pub String); -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Default)] pub enum ExprFillDefaultMode { + #[default] Todo, Default, Underscore, } -impl Default for ExprFillDefaultMode { - fn default() -> Self { - Self::Todo - } -} From 4fdd9bf5804e9549e435ddca73932f25e3faad76 Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Wed, 1 Oct 2025 23:00:16 -0500 Subject: [PATCH 20/59] Get rid of unfulfilled expectation --- src/tools/rust-analyzer/crates/stdx/src/thread.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread.rs b/src/tools/rust-analyzer/crates/stdx/src/thread.rs index a34e9e4a65515..37b7a9f5edfa8 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread.rs @@ -101,7 +101,6 @@ impl Drop for JoinHandle { } } -#[expect(clippy::min_ident_chars, reason = "trait impl")] impl fmt::Debug for JoinHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("JoinHandle { .. }") From eb2877b38064f79d889efde5f0b11e36bdc8d413 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 2 Oct 2025 04:07:01 +0000 Subject: [PATCH 21/59] Prepare for merging from rust-lang/rust This updates the rust-version file to 3369e82c6bc03c5cdb66f730dba6f738b74c8e1d. --- 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 1f90d4e5e498a..5e2e5d7d335d0 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f957826bff7a68b267ce75b1ea56352aed0cca0a +3369e82c6bc03c5cdb66f730dba6f738b74c8e1d From 306527dac25eddb4dd2138a6fad9a1c8e57fa1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 2 Oct 2025 07:16:40 +0300 Subject: [PATCH 22/59] Format code --- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs | 4 +--- 1 file changed, 1 insertion(+), 3 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 2c31ba1ec3331..e1983b37472ce 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 @@ -2136,9 +2136,7 @@ impl<'db> Evaluator<'db> { return Ok(Some((0, 1))); } let layout = layout?; - Ok(layout - .is_sized() - .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))) + Ok(layout.is_sized().then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))) } /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should From ef237100f7ae2a16c20489e96e96c6d052c90f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 2 Oct 2025 10:18:47 +0300 Subject: [PATCH 23/59] Reformat code after rustc-pull --- src/tools/rust-analyzer/josh-sync.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/rust-analyzer/josh-sync.toml b/src/tools/rust-analyzer/josh-sync.toml index 51ff0d71e71a9..a12cfa1b5cbd5 100644 --- a/src/tools/rust-analyzer/josh-sync.toml +++ b/src/tools/rust-analyzer/josh-sync.toml @@ -1,2 +1,6 @@ repo = "rust-analyzer" filter = ":rev(55d9a533b309119c8acd13061581b43ae8840823:prefix=src/tools/rust-analyzer):/src/tools/rust-analyzer" + +[[post-pull]] +cmd = ["cargo", "fmt"] +commit-message = "Format code" From 73ee45d13a633d33d59e86ea077187c28f7c3afa Mon Sep 17 00:00:00 2001 From: Supakorn Ieamgomol Date: Thu, 2 Oct 2025 23:56:02 +0700 Subject: [PATCH 24/59] Update license references to use markdown links --- src/tools/rust-analyzer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md index cb3a41eec5a62..6d2a673286853 100644 --- a/src/tools/rust-analyzer/README.md +++ b/src/tools/rust-analyzer/README.md @@ -61,4 +61,4 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer rust-analyzer is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0). -See LICENSE-APACHE and LICENSE-MIT for details. +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details. From 48df0e283363cec26aba29eb5efc5d629f845ef2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 3 Oct 2025 06:54:32 +0300 Subject: [PATCH 25/59] Fix erroneous diagnostic incorrect_generics_len when there are generics on enum variant used through type alias --- .../crates/hir-ty/src/infer/path.rs | 25 +++++++++++++------ .../src/handlers/incorrect_generics_len.rs | 17 +++++++++++++ 2 files changed, 34 insertions(+), 8 deletions(-) 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 7517272362b2c..e649e381ddd4a 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 @@ -95,14 +95,23 @@ impl<'db> InferenceContext<'_, 'db> { return Some(ValuePathResolution::NonGeneric(ty)); }; - let substs = self.with_body_ty_lowering(|ctx| { - let mut path_ctx = ctx.at_path(path, id); - let last_segment = path.segments().len().checked_sub(1); - if let Some(last_segment) = last_segment { - path_ctx.set_current_segment(last_segment) - } - path_ctx.substs_from_path(value_def, true, false) - }); + let substs = if self_subst.is_some_and(|it| !it.is_empty()) + && matches!(value_def, ValueTyDefId::EnumVariantId(_)) + { + // This is something like `TypeAlias::::EnumVariant`. Do not call `substs_from_path()`, + // as it'll try to re-lower the previous segment assuming it refers to the enum, but it refers + // to the type alias and they may have different generics. + self.types.empty_args + } else { + self.with_body_ty_lowering(|ctx| { + let mut path_ctx = ctx.at_path(path, id); + let last_segment = path.segments().len().checked_sub(1); + if let Some(last_segment) = last_segment { + path_ctx.set_current_segment(last_segment) + } + path_ctx.substs_from_path(value_def, true, false) + }) + }; let parent_substs_len = self_subst.map_or(0, |it| it.len()); let substs = GenericArgs::fill_rest( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs index 7402133f74799..894e044642cc3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs @@ -203,6 +203,23 @@ impl WithSignals for Player { fn __signals_from_external(&self) -> Self::SignalCollection<'_, Self> { Self::SignalCollection { _v: self } } +} + "#, + ); + } + + #[test] + fn enum_type_alias_default_param() { + check_diagnostics( + r#" +//- minicore: result + +struct Error; + +type Result = core::result::Result; + +fn main() { + let _ = Result::<()>::Ok(()); } "#, ); From 8607cfedc49e402d4301ce1f0f4721045f47203e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 4 Oct 2025 19:32:26 +0800 Subject: [PATCH 26/59] minor: Fix using `make::ty` for extract_type_alias --- .../ide-assists/src/handlers/extract_type_alias.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) 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 7f93506685e18..59522458af9e6 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 @@ -61,11 +61,13 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> generics.map(|it| make::generic_param_list(it.into_iter().cloned())); // Replace original type with the alias - let ty_args = generic_params - .as_ref() - .map_or(String::new(), |it| it.to_generic_args().to_string()); - // FIXME: replace with a `ast::make` constructor - let new_ty = make::ty(&format!("Type{ty_args}")).clone_for_update(); + let ty_args = generic_params.as_ref().map(|it| it.to_generic_args().generic_args()); + let new_ty = if let Some(ty_args) = ty_args { + make::generic_ty_path_segment(make::name_ref("Type"), ty_args) + } else { + make::path_segment(make::name_ref("Type")) + } + .clone_for_update(); edit.replace(ty.syntax(), new_ty.syntax()); // Insert new alias From 3350c27d911dd75d0b2c4fcbdba40776e482e42f Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 22 Sep 2025 11:54:22 -0400 Subject: [PATCH 27/59] internal: bump salsa to 0.24 --- src/tools/rust-analyzer/Cargo.lock | 463 ++++++++---------- src/tools/rust-analyzer/Cargo.toml | 5 +- .../crates/hir-def/src/test_db.rs | 3 +- .../crates/hir-ty/src/next_solver/interner.rs | 4 +- .../crates/hir-ty/src/next_solver/ir_print.rs | 3 + .../crates/query-group-macro/src/queries.rs | 3 +- .../rust-analyzer/crates/span/src/hygiene.rs | 87 +++- 7 files changed, 287 insertions(+), 281 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5a0d209602dfe..5840d2ca6a723 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -31,15 +31,15 @@ checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" @@ -115,9 +115,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[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 = "borsh" @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "boxcar" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa" +checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e" [[package]] name = "byteorder" @@ -142,11 +142,11 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "camino" -version = "1.1.10" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -184,7 +184,7 @@ dependencies = [ "serde", "serde-untagged", "serde-value", - "thiserror 2.0.12", + "thiserror 2.0.16", "toml", "unicode-xid", "url", @@ -202,7 +202,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -217,15 +217,16 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "cc" -version = "1.2.26" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -247,9 +248,9 @@ dependencies = [ [[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 = "cfg_aliases" @@ -275,24 +276,24 @@ version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7047a516de16226cd17344d41a319d0ea1064bf9e60bd612ab341ab4a34bbfa8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "chalk-derive", ] [[package]] name = "clap" -version = "4.5.42" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstyle", "clap_lex", @@ -310,7 +311,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -321,15 +322,15 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "cov-mark" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0570650661aa447e7335f1d5e4f499d8e58796e617bedc9267d971e51c8b49d4" +checksum = "3f1d92727879fb4f24cec33a35e3bff74035541326cbc12ad44ba8886d1927b0" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -385,12 +386,13 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" dependencies = [ + "dispatch", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -409,18 +411,18 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] [[package]] name = "derive-where" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", @@ -429,9 +431,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", @@ -456,9 +458,15 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + [[package]] name = "displaydoc" version = "0.2.5" @@ -515,11 +523,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" dependencies = [ "serde", + "serde_core", "typeid", ] @@ -534,16 +543,10 @@ dependencies = [ ] [[package]] -name = "filetime" -version = "0.2.25" +name = "find-msvc-tools" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "fixedbitset" @@ -569,9 +572,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -625,22 +628,28 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[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" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -700,7 +709,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg", "cov-mark", "drop_bomb", @@ -767,7 +776,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.1", + "bitflags 2.9.4", "chalk-derive", "chalk-ir", "cov-mark", @@ -980,7 +989,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.1", + "bitflags 2.9.4", "cov-mark", "crossbeam-channel", "either", @@ -1047,9 +1056,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1068,13 +1077,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -1083,7 +1093,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "inotify-sys", "libc", ] @@ -1116,6 +1126,15 @@ dependencies = [ "memoffset", ] +[[package]] +name = "inventory" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1175,25 +1194,25 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-link 0.2.0", ] [[package]] name = "libmimalloc-sys" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" dependencies = [ "cc", "libc", @@ -1201,13 +1220,12 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", - "redox_syscall", ] [[package]] @@ -1266,9 +1284,9 @@ dependencies = [ [[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 = "lsp-server" @@ -1340,9 +1358,9 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] @@ -1358,9 +1376,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.46" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" dependencies = [ "libmimalloc-sys", ] @@ -1388,11 +1406,11 @@ dependencies = [ [[package]] name = "miow" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.0", ] [[package]] @@ -1401,7 +1419,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -1415,12 +1433,11 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "notify" -version = "8.0.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.1", - "filetime", + "bitflags 2.9.4", "fsevent-sys", "inotify", "kqueue", @@ -1429,7 +1446,7 @@ dependencies = [ "mio", "notify-types", "walkdir", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1517,16 +1534,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "papaya" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92dd0b07c53a0a0c764db2ace8c541dc47320dad97c2200c2a637ab9dd2328f" -dependencies = [ - "equivalent", - "seize", -] - [[package]] name = "parking_lot" version = "0.12.4" @@ -1578,9 +1585,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf-event" @@ -1637,9 +1644,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -1706,9 +1713,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", ] @@ -1788,7 +1795,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "memchr", "unicase", ] @@ -1829,7 +1836,7 @@ version = "0.132.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597bb303548ddcca3a2eb05af254508aaf39cf334d4350bb5da51de1eb728859" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "ra-ap-rustc_hashes", "ra-ap-rustc_index", "tracing", @@ -1925,7 +1932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e35ee9e052406035016b8e6d54ca202bc39ccba1702780b33b2d5fb10d1da8" dependencies = [ "arrayvec", - "bitflags 2.9.1", + "bitflags 2.9.4", "derive-where", "ena", "indexmap", @@ -1952,9 +1959,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", @@ -1962,9 +1969,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", @@ -1972,22 +1979,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", ] [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -2071,9 +2078,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -2111,7 +2118,7 @@ version = "0.2.3+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "smallvec", ] @@ -2124,6 +2131,12 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.20" @@ -2133,17 +2146,16 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e235afdb8e510f38a07138fbe5a0b64691894358a9c0cbd813b1aade110efc9" +source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" dependencies = [ "boxcar", "crossbeam-queue", "crossbeam-utils", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "hashlink", "indexmap", "intrusive-collections", - "papaya", + "inventory", "parking_lot", "portable-atomic", "rayon", @@ -2158,14 +2170,12 @@ dependencies = [ [[package]] name = "salsa-macro-rules" version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2edb86a7e9c91f6d30c9ce054312721dbe773a162db27bbfae834d16177b30ce" +source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" [[package]] name = "salsa-macros" version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0778d6e209051bc4e75acfe83bcd7848601ec3dbe9c3dbb982829020e9128af" +source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" dependencies = [ "proc-macro2", "quote", @@ -2203,42 +2213,35 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "seize" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4b8d813387d566f627f3ea1b914c068aac94c40ae27ec43f5f33bde65abefe7" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" dependencies = [ + "serde_core", "serde_derive", ] [[package]] name = "serde-untagged" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" dependencies = [ "erased-serde", "serde", + "serde_core", "typeid", ] @@ -2252,11 +2255,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", @@ -2265,15 +2277,16 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "indexmap", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2373,9 +2386,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.103" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2491,11 +2504,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] @@ -2511,9 +2524,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -2562,9 +2575,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2579,15 +2592,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2665,9 +2678,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -2763,9 +2776,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-properties" @@ -2781,9 +2794,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -2850,11 +2863,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -2866,7 +2879,7 @@ dependencies = [ "windows-collections", "windows-core", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -2887,7 +2900,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -2899,7 +2912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", "windows-threading", ] @@ -2931,6 +2944,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-numerics" version = "0.2.0" @@ -2938,7 +2957,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -2947,7 +2966,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -2956,16 +2975,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-link 0.1.3", ] [[package]] @@ -2992,22 +3002,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link 0.2.0", ] [[package]] @@ -3028,10 +3032,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -3048,15 +3053,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -3069,12 +3068,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -3087,12 +3080,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3117,12 +3104,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -3135,12 +3116,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -3153,12 +3128,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -3171,12 +3140,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3191,9 +3154,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -3318,9 +3281,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -3340,9 +3303,9 @@ dependencies = [ [[package]] name = "zip" -version = "4.0.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" dependencies = [ "arbitrary", "crc32fast", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index d3a4e375613eb..25af4dfa87af2 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -137,12 +137,13 @@ rayon = "1.10.0" 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 = [ +salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "e257df12eabd566825ba53bb12d782560b9a4dcd", default-features = true, features = [ "rayon", "salsa_unstable", "macros", ] } -salsa-macros = "0.23.0" +# salsa-macros = "0.23.0" +salsa-macros = { git = "https://github.com/salsa-rs/salsa.git", rev = "e257df12eabd566825ba53bb12d782560b9a4dcd" } semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } 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 1e2f354f975cb..61ca6f67e6143 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 @@ -1,5 +1,6 @@ //! Database used for testing `hir_def`. +use salsa::database::AsDynDatabase; use std::{fmt, panic, sync::Mutex}; use base_db::{ @@ -7,7 +8,7 @@ use base_db::{ SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, }; use hir_expand::{InFile, files::FilePosition}; -use salsa::{AsDynDatabase, Durability}; +use salsa::{Durability, database::AsDynDatabase}; use span::FileId; use syntax::{AstNode, algo, ast}; use triomphe::Arc; 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 6b91ee35eba3b..2436d1ede8712 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 @@ -286,9 +286,7 @@ 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()) - }, + db: unsafe { std::mem::transmute::<&dyn salsa::Database, &'db dyn HirDatabase>(db) }, krate: None, block: None, }) 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 407e157564397..757c599232b93 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 @@ -62,9 +62,12 @@ impl<'db> IrPrint> for DbInterner<'db> { let self_ty = &t.args.as_slice()[0]; let trait_args = &t.args.as_slice()[1..]; if trait_args.is_empty() { + let db = db.zalsa().views().downcaster_for::(); + db.downcast_unchecked(db) fmt.write_str(&format!( "{:?}: {}", self_ty, + db.as_dyn_database().as_dyn_database(), db.as_view::().trait_signature(trait_).name.as_str() )) } 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 22a26c49fa530..7698ce5fff13e 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 @@ -327,7 +327,8 @@ impl ToTokens for Lookup { let wrapper_struct = self.interned_struct_path.to_token_stream(); let method = quote! { #sig { - #wrapper_struct::ingredient(self).data(self.as_dyn_database(), id.as_id()).0.clone() + let zalsa = self.zalsa(); + #wrapper_struct::ingredient(zalsa).data(zalsa, id.as_id()).0.clone() } }; diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index aef3fbf051775..67ff27e31c0c3 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -98,21 +98,38 @@ const _: () = { salsa::plumbing::Location { file: file!(), line: line!() }; const DEBUG_NAME: &'static str = "SyntaxContextData"; const REVISIONS: std::num::NonZeroUsize = std::num::NonZeroUsize::MAX; + const PERSIST: bool = false; + type Fields<'a> = SyntaxContextData; type Struct<'a> = SyntaxContext; - } - impl SyntaxContext { - pub fn ingredient(db: &Db) -> &zalsa_struct_::IngredientImpl + + fn serialize(_: &Self::Fields<'_>, _: S) -> Result where - Db: ?Sized + zalsa_::Database, + S: zalsa_::serde::Serializer, + { + unimplemented!("attempted to serialize value that set `PERSIST` to false") + } + + fn deserialize<'de, D>(_: D) -> Result, D::Error> + where + D: zalsa_::serde::Deserializer<'de>, { + unimplemented!("attempted to deserialize value that cannot set `PERSIST` to false"); + } + } + + impl SyntaxContext { + pub fn ingredient(zalsa: &zalsa_::Zalsa) -> &zalsa_struct_::IngredientImpl { static CACHE: zalsa_::IngredientCache> = zalsa_::IngredientCache::new(); - CACHE.get_or_create(db.zalsa(), || { - db.zalsa() - .lookup_jar_by_type::>() - .get_or_create() - }) + + // SAFETY: `lookup_jar_by_type` returns a valid ingredient index, and the only + // ingredient created by our jar is the struct ingredient. + unsafe { + CACHE.get_or_create(zalsa, || { + zalsa.lookup_jar_by_type::>() + }) + } } } impl zalsa_::AsId for SyntaxContext { @@ -132,13 +149,14 @@ const _: () = { impl zalsa_::SalsaStructInDb for SyntaxContext { type MemoIngredientMap = salsa::plumbing::MemoIngredientSingletonIndex; - fn lookup_or_create_ingredient_index( - zalsa: &salsa::plumbing::Zalsa, - ) -> salsa::plumbing::IngredientIndices { - zalsa - .lookup_jar_by_type::>() - .get_or_create() - .into() + fn lookup_ingredient_index(aux: &zalsa_::Zalsa) -> salsa::plumbing::IngredientIndices { + aux.lookup_jar_by_type::>().into() + } + + fn entries(zalsa: &zalsa_::Zalsa) -> impl Iterator + '_ { + let _ingredient_index = + zalsa.lookup_jar_by_type::>(); + ::ingredient(zalsa).entries(zalsa).map(|entry| entry.key()) } #[inline] @@ -149,6 +167,18 @@ const _: () = { None } } + + #[inline] + unsafe fn memo_table( + zalsa: &zalsa_::Zalsa, + id: zalsa_::Id, + current_revision: zalsa_::Revision, + ) -> zalsa_::MemoTableWithTypes<'_> { + // SAFETY: Guaranteed by caller. + unsafe { + zalsa.table().memos::>(id, current_revision) + } + } } unsafe impl salsa::plumbing::Update for SyntaxContext { @@ -184,8 +214,11 @@ const _: () = { Edition: zalsa_::interned::HashEqLike, SyntaxContext: zalsa_::interned::HashEqLike, { - SyntaxContext::ingredient(db).intern( - db.as_dyn_database(), + let (zalsa, zalsa_local) = db.zalsas(); + + SyntaxContext::ingredient(zalsa).intern( + zalsa, + zalsa_local, StructKey::<'db>( outer_expn, outer_transparency, @@ -216,7 +249,8 @@ const _: () = { Db: ?Sized + zalsa_::Database, { let id = self.as_salsa_id()?; - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.outer_expn } @@ -225,7 +259,8 @@ const _: () = { Db: ?Sized + zalsa_::Database, { let Some(id) = self.as_salsa_id() else { return Transparency::Opaque }; - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.outer_transparency } @@ -235,7 +270,8 @@ const _: () = { { match self.as_salsa_id() { Some(id) => { - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.edition } None => Edition::from_u32(SyntaxContext::MAX_ID - self.into_u32()), @@ -248,7 +284,8 @@ const _: () = { { match self.as_salsa_id() { Some(id) => { - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.parent } None => self, @@ -262,7 +299,8 @@ const _: () = { { match self.as_salsa_id() { Some(id) => { - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.opaque } None => self, @@ -276,7 +314,8 @@ const _: () = { { match self.as_salsa_id() { Some(id) => { - let fields = SyntaxContext::ingredient(db).data(db.as_dyn_database(), id); + let zalsa = db.zalsa(); + let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); fields.opaque_and_semitransparent } None => self, From 82e2c674528e9f68590ae1408a4a1a00ce3df628 Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Sat, 4 Oct 2025 12:30:15 -0500 Subject: [PATCH 28/59] Move salsa attach to end before call to run_ide_things --- .../crates/rust-analyzer/src/cli/analysis_stats.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 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 9c8743536877b..36c4f281b7303 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 @@ -335,15 +335,15 @@ impl flags::AnalysisStats { if !self.skip_const_eval { self.run_const_eval(db, &bodies, verbosity); } + }); - if self.run_all_ide_things { - self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); - } + if self.run_all_ide_things { + self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); + } - if self.run_term_search { - self.run_term_search(&workspace, db, &vfs, file_ids, verbosity); - } - }); + if self.run_term_search { + self.run_term_search(&workspace, db, &vfs, file_ids, verbosity); + } let db = host.raw_database_mut(); db.trigger_lru_eviction(); From c7d00075d9e65efbd7c5f9239d6ffe33ac3b937e Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Sat, 4 Oct 2025 13:00:09 -0500 Subject: [PATCH 29/59] Deduplicate sort+dedup calls --- .../rust-analyzer/src/cli/analysis_stats.rs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 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 36c4f281b7303..d365c56edb395 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 @@ -337,12 +337,15 @@ impl flags::AnalysisStats { } }); + file_ids.sort(); + file_ids.dedup(); + if self.run_all_ide_things { - self.run_ide_things(host.analysis(), file_ids.clone(), db, &vfs, verbosity); + self.run_ide_things(host.analysis(), &file_ids, db, &vfs, verbosity); } if self.run_term_search { - self.run_term_search(&workspace, db, &vfs, file_ids, verbosity); + self.run_term_search(&workspace, db, &vfs, &file_ids, verbosity); } let db = host.raw_database_mut(); @@ -438,12 +441,13 @@ impl flags::AnalysisStats { report_metric("const eval time", const_eval_time.time.as_millis() as u64, "ms"); } + /// Invariant: `file_ids` must be sorted and deduped before passing into here fn run_term_search( &self, ws: &ProjectWorkspace, db: &RootDatabase, vfs: &Vfs, - mut file_ids: Vec, + file_ids: &[EditionedFileId], verbosity: Verbosity, ) { let cargo_config = CargoConfig { @@ -461,9 +465,6 @@ impl flags::AnalysisStats { _ => ProgressReport::new(file_ids.len()), }; - file_ids.sort(); - file_ids.dedup(); - #[derive(Debug, Default)] struct Acc { tail_expr_syntax_hits: u64, @@ -477,7 +478,7 @@ impl flags::AnalysisStats { bar.tick(); let mut sw = self.stop_watch(); - for &file_id in &file_ids { + for &file_id in file_ids { let file_id = file_id.editioned_file_id(db); let sema = hir::Semantics::new(db); let display_target = match sema.first_crate(file_id.file_id()) { @@ -1109,10 +1110,11 @@ impl flags::AnalysisStats { report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } + /// Invariant: `file_ids` must be sorted and deduped before passing into here fn run_ide_things( &self, analysis: Analysis, - mut file_ids: Vec, + file_ids: &[EditionedFileId], db: &RootDatabase, vfs: &Vfs, verbosity: Verbosity, @@ -1124,12 +1126,10 @@ impl flags::AnalysisStats { _ => 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 { + 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( @@ -1163,7 +1163,7 @@ impl flags::AnalysisStats { bar.finish_and_clear(); let mut bar = create_bar(); - for &file_id in &file_ids { + 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( @@ -1206,7 +1206,7 @@ impl flags::AnalysisStats { bar.finish_and_clear(); let mut bar = create_bar(); - for &file_id in &file_ids { + 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 From b74760a66494d3a6169cd1a37423a4a4364972c7 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 5 Oct 2025 13:53:40 +0800 Subject: [PATCH 30/59] minor: Fix CURRENT_FIXME for extract_expressions_from_format_string --- .../src/handlers/extract_expressions_from_format_string.rs | 4 +--- 1 file changed, 1 insertion(+), 3 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 e3c7ea1b09391..61af2de6ec683 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 @@ -108,9 +108,7 @@ pub(crate) fn extract_expressions_from_format_string( match arg { Arg::Expr(s) => { // insert arg - // FIXME: use the crate's edition for parsing - let expr = - ast::Expr::parse(&s, syntax::Edition::CURRENT_FIXME).syntax_node(); + let expr = ast::Expr::parse(&s, ctx.edition()).syntax_node(); let mut expr_tt = utils::tt_from_syntax(expr); new_tt_bits.append(&mut expr_tt); } From c7ed41ebd0ad30ac1405841a160080ef0a4faaa9 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sat, 4 Oct 2025 21:20:36 +0800 Subject: [PATCH 31/59] Fix parentheses for missing_unsafe I seem unable to use `Expr::needs_parens*` to complete it Example --- ```rust static mut STATIC_MUT: u8 = 0; fn foo() -> u8 { STATIC_MUT$0 * 2 } ``` **Before this PR**: ```rust static mut STATIC_MUT: u8 = 0; fn foo() -> u8 { unsafe { STATIC_MUT } * 2 } ``` **After this PR**: ```rust static mut STATIC_MUT: u8 = 0; fn foo() -> u8 { (unsafe { STATIC_MUT }) * 2 } ``` --- .../src/handlers/missing_unsafe.rs | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) 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 4bb64747f5bb7..51a0641b90d9e 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 @@ -50,7 +50,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option Option bool { + let node = expr.syntax(); + node.ancestors() + .skip(1) + .take_while(|it| it.text_range().start() == node.text_range().start()) + .map_while(ast::Expr::cast) + .last() + .and_then(|it| Some(it.syntax().parent()?.kind())) + .is_some_and(|kind| ast::ExprStmt::can_cast(kind) || ast::StmtList::can_cast(kind)) +} + #[cfg(test)] mod tests { use crate::tests::{check_diagnostics, check_fix, check_no_fix}; @@ -527,6 +543,27 @@ fn main() { ) } + #[test] + fn needs_parentheses_for_unambiguous() { + check_fix( + r#" +//- minicore: copy +static mut STATIC_MUT: u8 = 0; + +fn foo() -> u8 { + STATIC_MUT$0 * 2 +} +"#, + r#" +static mut STATIC_MUT: u8 = 0; + +fn foo() -> u8 { + (unsafe { STATIC_MUT }) * 2 +} +"#, + ) + } + #[test] fn ref_to_unsafe_expr() { check_fix( From 41dd2b69a6223bcbf9f6782cefa2610b2dc519a9 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 5 Oct 2025 09:55:50 +0300 Subject: [PATCH 32/59] Switch to home-made db attaching infrastructure Instead of using Salsa's, as we can no longer can a `dyn HirDatabase` from the `dyn salsa::Database` Salsa provides. --- src/tools/rust-analyzer/Cargo.lock | 18 +- src/tools/rust-analyzer/Cargo.toml | 5 +- src/tools/rust-analyzer/crates/cfg/Cargo.toml | 6 +- .../rust-analyzer/crates/cfg/src/cfg_expr.rs | 2 +- .../crates/hir-def/src/test_db.rs | 6 +- .../crates/hir-ty/src/consteval/tests.rs | 10 +- .../hir-ty/src/dyn_compatibility/tests.rs | 2 +- .../crates/hir-ty/src/infer/cast.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 2 +- .../crates/hir-ty/src/layout/tests.rs | 53 +++--- .../rust-analyzer/crates/hir-ty/src/lib.rs | 1 + .../crates/hir-ty/src/mir/eval/tests.rs | 8 +- .../crates/hir-ty/src/mir/lower/tests.rs | 33 ++-- .../crates/hir-ty/src/next_solver/consts.rs | 9 +- .../crates/hir-ty/src/next_solver/interner.rs | 151 ++++++++++++--- .../crates/hir-ty/src/next_solver/ir_print.rs | 47 ++--- .../crates/hir-ty/src/next_solver/opaques.rs | 6 +- .../hir-ty/src/next_solver/predicate.rs | 6 +- .../crates/hir-ty/src/next_solver/region.rs | 3 +- .../crates/hir-ty/src/next_solver/ty.rs | 3 +- .../crates/hir-ty/src/next_solver/util.rs | 2 +- .../crates/hir-ty/src/test_db.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 46 +++-- .../hir-ty/src/tests/closure_captures.rs | 180 +++++++++--------- .../crates/hir-ty/src/tests/incremental.rs | 4 +- .../crates/hir-ty/src/variance.rs | 158 +++++++-------- src/tools/rust-analyzer/crates/hir/src/lib.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 3 +- .../crates/ide-assists/src/tests.rs | 6 +- .../ide-completion/src/context/analysis.rs | 3 +- .../ide-completion/src/context/tests.rs | 5 +- .../crates/ide-completion/src/tests.rs | 6 +- .../ide-completion/src/tests/flyimport.rs | 3 +- .../crates/ide-db/src/symbol_index.rs | 4 +- .../ide-db/src/syntax_helpers/suggest_name.rs | 2 +- .../crates/ide-diagnostics/src/tests.rs | 14 +- .../crates/ide-ssr/src/matching.rs | 4 +- .../crates/ide-ssr/src/resolving.rs | 4 +- .../rust-analyzer/crates/ide-ssr/src/tests.rs | 11 +- .../crates/ide/src/doc_links/tests.rs | 5 +- .../crates/ide/src/inlay_hints.rs | 8 +- .../crates/ide/src/inlay_hints/adjustment.rs | 4 +- src/tools/rust-analyzer/crates/ide/src/lib.rs | 6 +- .../crates/ide/src/navigation_target.rs | 6 +- .../rust-analyzer/crates/ide/src/runnables.rs | 6 +- .../crates/ide/src/signature_help.rs | 7 +- .../crates/ide/src/static_index.rs | 6 +- .../crates/ide/src/syntax_highlighting.rs | 8 +- .../ide/src/syntax_highlighting/inject.rs | 6 +- .../crates/ide/src/view_memory_layout.rs | 3 +- .../rust-analyzer/src/cli/analysis_stats.rs | 7 +- .../rust-analyzer/crates/span/src/hygiene.rs | 10 + 52 files changed, 499 insertions(+), 418 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 5840d2ca6a723..8e2c371bceaa5 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -235,7 +235,6 @@ name = "cfg" version = "0.0.0" dependencies = [ "arbitrary", - "derive_arbitrary", "expect-test", "intern", "oorandom", @@ -1615,7 +1614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" dependencies = [ "fixedbitset", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "indexmap", ] @@ -2145,8 +2144,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.23.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27956164373aeec733ac24ff1736de8541234e3a8e7e6f916b28175b5752af3b" dependencies = [ "boxcar", "crossbeam-queue", @@ -2169,13 +2169,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.23.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ca3b9d6e47c08b5de4b218e0c5f7ec910b51bce6314e651c8e7b9d154d174da" [[package]] name = "salsa-macros" -version = "0.23.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=e257df12eabd566825ba53bb12d782560b9a4dcd#e257df12eabd566825ba53bb12d782560b9a4dcd" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6337b62f2968be6b8afa30017d7564ecbde6832ada47ed2261fb14d0fd402ff4" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 25af4dfa87af2..1438d4638922a 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -137,13 +137,12 @@ rayon = "1.10.0" 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 = { git = "https://github.com/salsa-rs/salsa.git", rev = "e257df12eabd566825ba53bb12d782560b9a4dcd", default-features = true, features = [ +salsa = { version = "0.24.0", default-features = true, features = [ "rayon", "salsa_unstable", "macros", ] } -# salsa-macros = "0.23.0" -salsa-macros = { git = "https://github.com/salsa-rs/salsa.git", rev = "e257df12eabd566825ba53bb12d782560b9a4dcd" } +salsa-macros = "0.24.0" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index ba34966614536..af95f86c83521 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -23,11 +23,7 @@ intern.workspace = true [dev-dependencies] expect-test = "1.5.1" oorandom = "11.1.5" -# We depend on both individually instead of using `features = ["derive"]` to microoptimize the -# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr` -# supports `arbitrary`. This way, we avoid feature unification. -arbitrary = "1.4.1" -derive_arbitrary = "1.4.1" +arbitrary = { version = "1.4.1", features = ["derive"] } # local deps syntax-bridge.workspace = true diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs index f83c21eb8d64a..7a21015e14bec 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs @@ -47,7 +47,7 @@ impl fmt::Display for CfgAtom { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(test, derive(derive_arbitrary::Arbitrary))] +#[cfg_attr(test, derive(arbitrary::Arbitrary))] pub enum CfgExpr { Invalid, Atom(CfgAtom), 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 61ca6f67e6143..12a1c1554cc12 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 @@ -1,6 +1,5 @@ //! Database used for testing `hir_def`. -use salsa::database::AsDynDatabase; use std::{fmt, panic, sync::Mutex}; use base_db::{ @@ -8,7 +7,7 @@ use base_db::{ SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, }; use hir_expand::{InFile, files::FilePosition}; -use salsa::{Durability, database::AsDynDatabase}; +use salsa::Durability; use span::FileId; use syntax::{AstNode, algo, ast}; use triomphe::Arc; @@ -304,8 +303,7 @@ impl TestDB { // This is pretty horrible, but `Debug` is the only way to inspect // QueryDescriptor at the moment. salsa::EventKind::WillExecute { database_key } => { - let ingredient = self - .as_dyn_database() + let ingredient = (self as &dyn salsa::Database) .ingredient_debug_name(database_key.ingredient_index()); Some(ingredient.to_string()) } 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 5a214eabcdbd4..70a8ae766c0ba 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 @@ -36,7 +36,7 @@ fn check_fail( error: impl FnOnce(ConstEvalError<'_>) -> bool, ) { let (db, file_id) = TestDB::with_single_file(ra_fixture); - salsa::attach(&db, || match eval_goal(&db, file_id) { + crate::attach_db(&db, || match eval_goal(&db, file_id) { Ok(_) => panic!("Expected fail, but it succeeded"), Err(e) => { assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, &db)) @@ -79,7 +79,7 @@ fn check_answer( check: impl FnOnce(&[u8], &MemoryMap<'_>), ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - salsa::attach(&db, || { + crate::attach_db(&db, || { let file_id = *file_ids.last().unwrap(); let r = match eval_goal(&db, file_id) { Ok(t) => t, @@ -2506,8 +2506,10 @@ fn enums() { const GOAL: E = E::A; "#, ); - let r = eval_goal(&db, file_id).unwrap(); - assert_eq!(try_const_usize(&db, &r), Some(1)); + crate::attach_db(&db, || { + let r = eval_goal(&db, file_id).unwrap(); + assert_eq!(try_const_usize(&db, &r), Some(1)); + }) } #[test] 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 04a9ba79921ad..f90cd608e997e 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 @@ -57,7 +57,7 @@ fn check_dyn_compatibility<'a>( }; let mut osvs = FxHashSet::default(); let db = &db; - salsa::attach(db, || { + crate::attach_db(db, || { _ = dyn_compatibility_with_callback(db, trait_id, &mut |osv| { osvs.insert(match osv { DynCompatibilityViolation::SizedSelf => SizedSelf, 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 017f45f43df46..990281a7c8965 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 @@ -400,7 +400,7 @@ fn pointer_kind<'db>( Ok(Some(PointerKind::Thin)) } } - TyKind::Tuple(subst) => match subst.iter().last() { + TyKind::Tuple(subst) => match subst.iter().next_back() { None => Ok(Some(PointerKind::Thin)), Some(ty) => pointer_kind(ty, ctx), }, 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 d97d2af080732..eed36b1bb7f5d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -385,7 +385,7 @@ fn struct_tail_erasing_lifetimes<'a>(db: &'a dyn HirDatabase, pointee: Ty<'a>) - } } TyKind::Tuple(tys) => { - if let Some(last_field_ty) = tys.iter().last() { + if let Some(last_field_ty) = tys.iter().next_back() { struct_tail_erasing_lifetimes(db, last_field_ty) } else { pointee 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 712f5a89a2342..f0fed83597298 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 @@ -79,7 +79,7 @@ fn eval_goal( Some(adt_or_type_alias_id) }) .unwrap(); - salsa::attach(&db, || { + crate::attach_db(&db, || { let interner = DbInterner::new_with(&db, None, None); let goal_ty = match adt_or_type_alias_id { Either::Left(adt_id) => crate::next_solver::Ty::new_adt( @@ -112,29 +112,34 @@ fn eval_expr( ); let (db, file_id) = TestDB::with_single_file(&ra_fixture); - 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 function_id = scope - .declarations() - .find_map(|x| match x { - hir_def::ModuleDefId::FunctionId(x) => { - let name = - db.function_signature(x).name.display_no_db(file_id.edition(&db)).to_smolstr(); - (name == "main").then_some(x) - } - _ => None, - }) - .unwrap(); - let hir_body = db.body(function_id.into()); - let b = hir_body - .bindings() - .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal") - .unwrap() - .0; - let infer = db.infer(function_id.into()); - let goal_ty = infer.type_of_binding[b]; - salsa::attach(&db, || db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))) + crate::attach_db(&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 function_id = scope + .declarations() + .find_map(|x| match x { + hir_def::ModuleDefId::FunctionId(x) => { + let name = db + .function_signature(x) + .name + .display_no_db(file_id.edition(&db)) + .to_smolstr(); + (name == "main").then_some(x) + } + _ => None, + }) + .unwrap(); + let hir_body = db.body(function_id.into()); + let b = hir_body + .bindings() + .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal") + .unwrap() + .0; + let infer = db.infer(function_id.into()); + let goal_ty = infer.type_of_binding[b]; + db.layout_of_ty(goal_ty, db.trait_environment(function_id.into())) + }) } #[track_caller] 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 2aa9b8fa192d0..2add66d02d235 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -114,6 +114,7 @@ pub use mapping::{ to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index, }; pub use method_resolution::check_orphan_rules; +pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; pub use traits::TraitEnvironment; pub use utils::{ 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 9e948d1b43c7a..82c0a8070c41a 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,7 +12,7 @@ use crate::{ use super::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { - salsa::attach(db, || { + crate::attach_db(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; @@ -56,7 +56,7 @@ fn check_pass_and_stdio( ) { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); - salsa::attach(&db, || { + crate::attach_db(&db, || { let file_id = *file_ids.last().unwrap(); let x = eval_main(&db, file_id); match x { @@ -102,7 +102,7 @@ fn check_pass_and_stdio( fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: &str) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - salsa::attach(&db, || { + crate::attach_db(&db, || { let file_id = *file_ids.last().unwrap(); let e = eval_main(&db, file_id).unwrap_err(); assert_eq!( @@ -117,7 +117,7 @@ fn check_error_with( expect_err: impl FnOnce(MirEvalError<'_>) -> bool, ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - salsa::attach(&db, || { + crate::attach_db(&db, || { let file_id = *file_ids.last().unwrap(); let e = eval_main(&db, file_id).unwrap_err(); assert!(expect_err(e)); 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 index bac694eabb704..ee088bd06ca6b 100644 --- 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 @@ -11,21 +11,24 @@ fn lower_mir( ) -> FxHashMap, ()>> { 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.map_err(drop)) - }) - .collect() + crate::attach_db(&db, || { + 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.map_err(drop)) + }) + .collect() + }) } #[test] 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..aae48eeaf9346 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 @@ -41,13 +41,12 @@ impl<'db> Const<'db> { } pub fn inner(&self) -> &WithCachedTypeInfo> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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 { @@ -197,21 +196,19 @@ pub struct Valtree<'db> { impl<'db> Valtree<'db> { pub fn new(bytes: ConstBytes<'db>) -> Self { - salsa::with_attached_database(|db| unsafe { + crate::with_attached_db(|db| unsafe { // SAFETY: ¯\_(ツ)_/¯ std::mem::transmute(Valtree::new_(db, bytes)) }) - .unwrap() } pub fn inner(&self) -> &ConstBytes<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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() } } 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 2436d1ede8712..4a0ede35ac752 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 @@ -1,6 +1,8 @@ //! Things related to the Interner in the next-trait-solver. #![allow(unused)] +pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; + use base_db::Crate; use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; use hir_def::lang_item::LangItem; @@ -127,11 +129,10 @@ macro_rules! _interned_vec_nolifetime_salsa { pub fn inner(&self) -> &smallvec::SmallVec<[$ty; 2]> { // SAFETY: ¯\_(ツ)_/¯ - salsa::with_attached_database(|db| { + $crate::with_attached_db(|db| { let inner = self.inner_(db); unsafe { std::mem::transmute(inner) } }) - .unwrap() } } @@ -230,11 +231,10 @@ macro_rules! _interned_vec_db { pub fn inner(&self) -> &smallvec::SmallVec<[$ty<'db>; 2]> { // SAFETY: ¯\_(ツ)_/¯ - salsa::with_attached_database(|db| { + $crate::with_attached_db(|db| { let inner = self.inner_(db); unsafe { std::mem::transmute(inner) } }) - .unwrap() } } @@ -285,12 +285,11 @@ 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 salsa::Database, &'db dyn HirDatabase>(db) }, + crate::with_attached_db(|db| DbInterner { + db: unsafe { std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db) }, krate: None, block: None, }) - .expect("db is expected to be attached") } pub fn new_with( @@ -583,12 +582,11 @@ impl AdtDef { } pub fn inner(&self) -> &AdtDefInner { - salsa::with_attached_database(|db| { + crate::with_attached_db(|db| { let inner = self.data_(db); // SAFETY: ¯\_(ツ)_/¯ unsafe { std::mem::transmute(inner) } }) - .unwrap() } pub fn is_enum(&self) -> bool { @@ -706,21 +704,20 @@ impl<'db> inherent::AdtDef> for AdtDef { impl fmt::Debug for AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - salsa::with_attached_database(|db| match self.inner().id { + crate::with_attached_db(|db| match self.inner().id { AdtId::StructId(struct_id) => { - let data = db.as_view::().struct_signature(struct_id); + let data = db.struct_signature(struct_id); f.write_str(data.name.as_str()) } AdtId::UnionId(union_id) => { - let data = db.as_view::().union_signature(union_id); + let data = db.union_signature(union_id); f.write_str(data.name.as_str()) } AdtId::EnumId(enum_id) => { - let data = db.as_view::().enum_signature(enum_id); + let data = db.enum_signature(enum_id); f.write_str(data.name.as_str()) } }) - .unwrap_or_else(|| f.write_str(&format!("AdtDef({:?})", self.inner().id))) } } @@ -776,13 +773,12 @@ impl<'db> Pattern<'db> { } pub fn inner(&self) -> &PatternKind<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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() } } @@ -1018,17 +1014,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { 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() + tls_cache::with_cache(self.db, f) } fn canonical_param_env_cache_get_or_insert( @@ -2104,6 +2090,117 @@ TrivialTypeTraversalImpls! { Placeholder, } +mod tls_db { + use std::{cell::Cell, ptr::NonNull}; + + use crate::db::HirDatabase; + + struct Attached { + database: Cell>>, + } + + impl Attached { + #[inline] + fn attach(&self, db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + struct DbGuard<'s> { + state: Option<&'s Attached>, + } + + impl<'s> DbGuard<'s> { + #[inline] + fn new(attached: &'s Attached, db: &dyn HirDatabase) -> Self { + match attached.database.get() { + Some(current_db) => { + let new_db = NonNull::from(db); + if !std::ptr::addr_eq(current_db.as_ptr(), new_db.as_ptr()) { + panic!( + "Cannot change attached database. This is likely a bug.\n\ + If this is not a bug, you can use `attach_db_allow_change()`." + ); + } + Self { state: None } + } + None => { + // Otherwise, set the database. + attached.database.set(Some(NonNull::from(db))); + Self { state: Some(attached) } + } + } + } + } + + impl Drop for DbGuard<'_> { + #[inline] + fn drop(&mut self) { + // Reset database to null if we did anything in `DbGuard::new`. + if let Some(attached) = self.state { + attached.database.set(None); + } + } + } + + let _guard = DbGuard::new(self, db); + op() + } + + #[inline] + fn attach_allow_change(&self, db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + struct DbGuard<'s> { + state: &'s Attached, + prev: Option>, + } + + impl<'s> DbGuard<'s> { + #[inline] + fn new(attached: &'s Attached, db: &dyn HirDatabase) -> Self { + let prev = attached.database.replace(Some(NonNull::from(db))); + Self { state: attached, prev } + } + } + + impl Drop for DbGuard<'_> { + #[inline] + fn drop(&mut self) { + self.state.database.set(self.prev); + } + } + + let _guard = DbGuard::new(self, db); + op() + } + + #[inline] + fn with(&self, op: impl FnOnce(&dyn HirDatabase) -> R) -> R { + let db = self.database.get().expect("Try to use attached db, but not db is attached"); + + // SAFETY: The db is attached, so it must be valid. + op(unsafe { db.as_ref() }) + } + } + + thread_local! { + static GLOBAL_DB: Attached = const { Attached { database: Cell::new(None) } }; + } + + #[inline] + pub fn attach_db(db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + GLOBAL_DB.with(|global_db| global_db.attach(db, op)) + } + + #[inline] + pub fn attach_db_allow_change(db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + GLOBAL_DB.with(|global_db| global_db.attach_allow_change(db, op)) + } + + #[inline] + pub fn with_attached_db(op: impl FnOnce(&dyn HirDatabase) -> R) -> R { + GLOBAL_DB.with( + #[inline] + |a| a.with(op), + ) + } +} + mod tls_cache { use crate::db::HirDatabase; 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 757c599232b93..69afcf5dde90b 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 @@ -16,10 +16,10 @@ impl<'db> IrPrint> for DbInterner<'db> { } fn print_debug(t: &ty::AliasTy, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - salsa::with_attached_database(|db| match t.def_id { + crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTy({:?}[{:?}])", - db.as_view::().type_alias_signature(id).name.as_str(), + db.type_alias_signature(id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -27,7 +27,6 @@ impl<'db> IrPrint> for DbInterner<'db> { } _ => panic!("Expected TypeAlias or OpaqueTy."), }) - .unwrap_or_else(|| fmt.write_str(&format!("AliasTy({:?}[{:?}])", t.def_id, t.args))) } } @@ -37,10 +36,10 @@ impl<'db> IrPrint> for DbInterner<'db> { } fn print_debug(t: &ty::AliasTerm, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - salsa::with_attached_database(|db| match t.def_id { + crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTerm({:?}[{:?}])", - db.as_view::().type_alias_signature(id).name.as_str(), + db.type_alias_signature(id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -48,7 +47,6 @@ impl<'db> IrPrint> for DbInterner<'db> { } _ => panic!("Expected TypeAlias or OpaqueTy."), }) - .unwrap_or_else(|| fmt.write_str(&format!("AliasTerm({:?}[{:?}])", t.def_id, t.args))) } } impl<'db> IrPrint> for DbInterner<'db> { @@ -57,29 +55,25 @@ 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| { + crate::with_attached_db(|db| { 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() { - let db = db.zalsa().views().downcaster_for::(); - db.downcast_unchecked(db) fmt.write_str(&format!( "{:?}: {}", self_ty, - db.as_dyn_database().as_dyn_database(), - db.as_view::().trait_signature(trait_).name.as_str() + db.trait_signature(trait_).name.as_str() )) } else { fmt.write_str(&format!( "{:?}: {}<{:?}>", self_ty, - db.as_view::().trait_signature(trait_).name.as_str(), + db.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> { @@ -121,17 +115,14 @@ impl<'db> IrPrint> for DbInterner<'db> { t: &ty::ExistentialTraitRef, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - salsa::with_attached_database(|db| { + crate::with_attached_db(|db| { let trait_ = t.def_id.0; fmt.write_str(&format!( "ExistentialTraitRef({:?}[{:?}])", - db.as_view::().trait_signature(trait_).name.as_str(), + db.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> { @@ -146,24 +137,18 @@ impl<'db> IrPrint> for DbInterner<'db> { t: &ty::ExistentialProjection, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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(), + db.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> { @@ -178,24 +163,18 @@ impl<'db> IrPrint> for DbInterner<'db> { t: &ty::ProjectionPredicate, fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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(), + db.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> { 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 index 43589ab2ef139..0aee779ed04f0 100644 --- 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 @@ -24,12 +24,11 @@ impl<'db> PredefinedOpaques<'db> { } pub fn inner(&self) -> &PredefinedOpaquesData<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|db| { let inner = self.kind_(db); // SAFETY: ¯\_(ツ)_/¯ unsafe { std::mem::transmute(inner) } }) - .unwrap() } } @@ -96,12 +95,11 @@ impl<'db> ExternalConstraints<'db> { } pub fn inner(&self) -> &ExternalConstraintsData<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|db| { let inner = self.kind_(db); // SAFETY: ¯\_(ツ)_/¯ unsafe { std::mem::transmute(inner) } }) - .unwrap() } } 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..1623fa342a736 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 @@ -232,13 +232,12 @@ impl<'db> Predicate<'db> { } pub fn inner(&self) -> &WithCachedTypeInfo>> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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. @@ -303,13 +302,12 @@ impl<'db> Clauses<'db> { } pub fn inner(&self) -> &InternedClausesWrapper<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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() } } 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 32c30d19c7849..13c333b9d54d8 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 @@ -35,13 +35,12 @@ impl<'db> Region<'db> { } pub fn inner(&self) -> &RegionKind<'db> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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( 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 5ccd84af8d2f1..11ca0b03eb3dc 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 @@ -68,13 +68,12 @@ impl<'db> Ty<'db> { } pub fn inner(&self) -> &WithCachedTypeInfo> { - salsa::with_attached_database(|db| { + crate::with_attached_db(|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_adt(interner: DbInterner<'db>, adt_id: AdtId, args: GenericArgs<'db>) -> Self { 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 750d09e1a739c..ae240a942f576 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 @@ -486,7 +486,7 @@ pub fn sizedness_constraint_for_ty<'db>( Tuple(tys) => tys .into_iter() - .last() + .next_back() .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)), Adt(adt, args) => { 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 2a92aa52e0cd2..7044ca5d23ae1 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 @@ -10,7 +10,7 @@ use base_db::{ use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map}; use hir_expand::EditionedFileId; use rustc_hash::FxHashMap; -use salsa::{AsDynDatabase, Durability}; +use salsa::Durability; use span::FileId; use syntax::TextRange; use test_utils::extract_annotations; @@ -191,8 +191,7 @@ impl TestDB { // This is pretty horrible, but `Debug` is the only way to inspect // QueryDescriptor at the moment. salsa::EventKind::WillExecute { database_key } => { - let ingredient = self - .as_dyn_database() + let ingredient = (self as &dyn salsa::Database) .ingredient_debug_name(database_key.ingredient_index()); Some(ingredient.to_string()) } 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 5dd9ab75326dc..95a02d534b8ed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -79,7 +79,7 @@ fn check_impl( let _tracing = setup_tracing(); let (db, files) = TestDB::with_many_files(ra_fixture); - salsa::attach(&db, || { + crate::attach_db(&db, || { let mut had_annotations = false; let mut mismatches = FxHashMap::default(); let mut types = FxHashMap::default(); @@ -283,7 +283,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let _tracing = setup_tracing(); let (db, file_id) = TestDB::with_single_file(content); - salsa::attach(&db, || { + crate::attach_db(&db, || { let mut buf = String::new(); let mut infer_def = |inference_result: Arc>, @@ -558,15 +558,17 @@ fn salsa_bug() { ", ); - let module = db.module_for_file(pos.file_id.file_id(&db)); - let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { - db.infer(match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, + crate::attach_db(&db, || { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let crate_def_map = module.def_map(&db); + visit_module(&db, crate_def_map, module.local_id, &mut |def| { + db.infer(match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }); }); }); @@ -597,15 +599,17 @@ fn salsa_bug() { db.set_file_text(pos.file_id.file_id(&db), new_text); - let module = db.module_for_file(pos.file_id.file_id(&db)); - let crate_def_map = module.def_map(&db); - visit_module(&db, crate_def_map, module.local_id, &mut |def| { - db.infer(match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, + crate::attach_db(&db, || { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let crate_def_map = module.def_map(&db); + visit_module(&db, crate_def_map, module.local_id, &mut |def| { + db.infer(match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }); }); - }); + }) } 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 d3bc26abd7b0a..8425c0dd89900 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 @@ -18,96 +18,105 @@ 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); + crate::attach_db(&db, || { + let module = db.module_for_file(file_id.file_id(&db)); + let def_map = module.def_map(&db); - let mut defs = Vec::new(); - visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it)); + let mut defs = Vec::new(); + visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it)); - let mut captures_info = Vec::new(); - for def in defs { - let def = match def { - hir_def::ModuleDefId::FunctionId(it) => it.into(), - hir_def::ModuleDefId::EnumVariantId(it) => it.into(), - hir_def::ModuleDefId::ConstId(it) => it.into(), - hir_def::ModuleDefId::StaticId(it) => it.into(), - _ => continue, - }; - let infer = db.infer(def); - let db = &db; - captures_info.extend(infer.closure_info.iter().flat_map(|(closure_id, (captures, _))| { - let closure = db.lookup_intern_closure(*closure_id); - let source_map = db.body_with_source_map(closure.0).1; - let closure_text_range = source_map - .expr_syntax(closure.1) - .expect("failed to map closure to SyntaxNode") - .value - .text_range(); - captures.iter().map(move |capture| { - fn text_range( - db: &TestDB, - syntax: InFileWrapper>, - ) -> TextRange { - let root = syntax.file_syntax(db); - syntax.value.to_node(&root).syntax().text_range() - } - - // FIXME: Deduplicate this with hir::Local::sources(). - let (body, source_map) = db.body_with_source_map(closure.0); - let local_text_range = match body.self_param.zip(source_map.self_param_syntax()) { - Some((param, source)) if param == capture.local() => { - format!("{:?}", text_range(db, source)) - } - _ => source_map - .patterns_for_binding(capture.local()) - .iter() - .map(|&definition| { - text_range(db, source_map.pat_syntax(definition).unwrap()) - }) - .map(|it| format!("{it:?}")) - .join(", "), - }; - let place = capture.display_place(closure.0, db); - let capture_ty = salsa::attach(db, || { - capture - .ty - .skip_binder() - .display_test(db, DisplayTarget::from_crate(db, module.krate())) - .to_string() - }); - let spans = capture - .spans() - .iter() - .flat_map(|span| match *span { - MirSpan::ExprId(expr) => { - vec![text_range(db, source_map.expr_syntax(expr).unwrap())] - } - MirSpan::PatId(pat) => { - vec![text_range(db, source_map.pat_syntax(pat).unwrap())] + let mut captures_info = Vec::new(); + for def in defs { + let def = match def { + hir_def::ModuleDefId::FunctionId(it) => it.into(), + hir_def::ModuleDefId::EnumVariantId(it) => it.into(), + hir_def::ModuleDefId::ConstId(it) => it.into(), + hir_def::ModuleDefId::StaticId(it) => it.into(), + _ => continue, + }; + let infer = db.infer(def); + let db = &db; + captures_info.extend(infer.closure_info.iter().flat_map( + |(closure_id, (captures, _))| { + let closure = db.lookup_intern_closure(*closure_id); + let source_map = db.body_with_source_map(closure.0).1; + let closure_text_range = source_map + .expr_syntax(closure.1) + .expect("failed to map closure to SyntaxNode") + .value + .text_range(); + captures.iter().map(move |capture| { + fn text_range( + db: &TestDB, + syntax: InFileWrapper>, + ) -> TextRange { + let root = syntax.file_syntax(db); + syntax.value.to_node(&root).syntax().text_range() } - MirSpan::BindingId(binding) => source_map - .patterns_for_binding(binding) + + // FIXME: Deduplicate this with hir::Local::sources(). + let (body, source_map) = db.body_with_source_map(closure.0); + let local_text_range = + match body.self_param.zip(source_map.self_param_syntax()) { + Some((param, source)) if param == capture.local() => { + format!("{:?}", text_range(db, source)) + } + _ => source_map + .patterns_for_binding(capture.local()) + .iter() + .map(|&definition| { + text_range(db, source_map.pat_syntax(definition).unwrap()) + }) + .map(|it| format!("{it:?}")) + .join(", "), + }; + let place = capture.display_place(closure.0, db); + let capture_ty = capture + .ty + .skip_binder() + .display_test(db, DisplayTarget::from_crate(db, module.krate())) + .to_string(); + let spans = capture + .spans() .iter() - .map(|pat| text_range(db, source_map.pat_syntax(*pat).unwrap())) - .collect(), - MirSpan::SelfParam => { - vec![text_range(db, source_map.self_param_syntax().unwrap())] - } - MirSpan::Unknown => Vec::new(), - }) - .sorted_by_key(|it| it.start()) - .map(|it| format!("{it:?}")) - .join(","); + .flat_map(|span| match *span { + MirSpan::ExprId(expr) => { + vec![text_range(db, source_map.expr_syntax(expr).unwrap())] + } + MirSpan::PatId(pat) => { + vec![text_range(db, source_map.pat_syntax(pat).unwrap())] + } + MirSpan::BindingId(binding) => source_map + .patterns_for_binding(binding) + .iter() + .map(|pat| text_range(db, source_map.pat_syntax(*pat).unwrap())) + .collect(), + MirSpan::SelfParam => { + vec![text_range(db, source_map.self_param_syntax().unwrap())] + } + MirSpan::Unknown => Vec::new(), + }) + .sorted_by_key(|it| it.start()) + .map(|it| format!("{it:?}")) + .join(","); - (closure_text_range, local_text_range, spans, place, capture_ty, capture.kind()) - }) - })); - } - captures_info.sort_unstable_by_key(|(closure_text_range, local_text_range, ..)| { - (closure_text_range.start(), local_text_range.clone()) - }); + ( + closure_text_range, + local_text_range, + spans, + place, + capture_ty, + capture.kind(), + ) + }) + }, + )); + } + captures_info.sort_unstable_by_key(|(closure_text_range, local_text_range, ..)| { + (closure_text_range.start(), local_text_range.clone()) + }); - let rendered = captures_info + let rendered = captures_info .iter() .map(|(closure_text_range, local_text_range, spans, place, capture_ty, capture_kind)| { format!( @@ -116,7 +125,8 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec }) .join("\n"); - expect.assert_eq(&rendered); + expect.assert_eq(&rendered); + }) } #[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 ce3de06127e49..76cd5f7ab3302 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 @@ -710,8 +710,8 @@ fn execute_assert_events( required: &[(&str, usize)], expect: Expect, ) { - let (executed, events) = db.log_executed(f); - salsa::attach(db, || { + crate::attach_db(db, || { + let (executed, events) = db.log_executed(f); for (event, count) in required { let n = executed.iter().filter(|it| it.contains(event)).count(); assert_eq!( 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 a17cf3782701a..0ff110106ebe5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -1001,84 +1001,86 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); // )); let (db, file_id) = TestDB::with_single_file(ra_fixture); - let mut defs: Vec = Vec::new(); - let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap(); - let def_map = module.def_map(&db); - crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| { - defs.push(match it { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::AdtId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::TraitId(it) => it.into(), - ModuleDefId::TypeAliasId(it) => it.into(), - _ => return, - }) - }); - let defs = defs - .into_iter() - .filter_map(|def| { - Some(( - def, - match def { - GenericDefId::FunctionId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::AdtId(AdtId::EnumId(it)) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::AdtId(AdtId::StructId(it)) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::AdtId(AdtId::UnionId(it)) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::TraitId(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() - } - GenericDefId::ImplId(_) => return None, - GenericDefId::ConstId(_) => return None, - GenericDefId::StaticId(_) => return None, - }, - )) - }) - .sorted_by_key(|(_, n)| n.syntax().text_range().start()); - let mut res = String::new(); - for (def, name) in defs { - let Some(variances) = db.variances_of(def) else { - continue; - }; - format_to!( - res, - "{name}[{}]\n", - generics(&db, def) - .iter() - .map(|(_, param)| match param { - GenericParamDataRef::TypeParamData(type_param_data) => { - type_param_data.name.as_ref().unwrap() - } - GenericParamDataRef::ConstParamData(const_param_data) => - &const_param_data.name, - GenericParamDataRef::LifetimeParamData(lifetime_param_data) => { - &lifetime_param_data.name - } - }) - .zip_eq(&*variances) - .format_with(", ", |(name, var), f| f(&format_args!( - "{}: {var}", - name.as_str() - ))) - ); - } + crate::attach_db(&db, || { + let mut defs: Vec = Vec::new(); + let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap(); + let def_map = module.def_map(&db); + crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| { + defs.push(match it { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::AdtId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::TraitId(it) => it.into(), + ModuleDefId::TypeAliasId(it) => it.into(), + _ => return, + }) + }); + let defs = defs + .into_iter() + .filter_map(|def| { + Some(( + def, + match def { + GenericDefId::FunctionId(it) => { + let loc = it.lookup(&db); + loc.source(&db).value.name().unwrap() + } + GenericDefId::AdtId(AdtId::EnumId(it)) => { + let loc = it.lookup(&db); + loc.source(&db).value.name().unwrap() + } + GenericDefId::AdtId(AdtId::StructId(it)) => { + let loc = it.lookup(&db); + loc.source(&db).value.name().unwrap() + } + GenericDefId::AdtId(AdtId::UnionId(it)) => { + let loc = it.lookup(&db); + loc.source(&db).value.name().unwrap() + } + GenericDefId::TraitId(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() + } + GenericDefId::ImplId(_) => return None, + GenericDefId::ConstId(_) => return None, + GenericDefId::StaticId(_) => return None, + }, + )) + }) + .sorted_by_key(|(_, n)| n.syntax().text_range().start()); + let mut res = String::new(); + for (def, name) in defs { + let Some(variances) = db.variances_of(def) else { + continue; + }; + format_to!( + res, + "{name}[{}]\n", + generics(&db, def) + .iter() + .map(|(_, param)| match param { + GenericParamDataRef::TypeParamData(type_param_data) => { + type_param_data.name.as_ref().unwrap() + } + GenericParamDataRef::ConstParamData(const_param_data) => + &const_param_data.name, + GenericParamDataRef::LifetimeParamData(lifetime_param_data) => { + &lifetime_param_data.name + } + }) + .zip_eq(&*variances) + .format_with(", ", |(name, var), f| f(&format_args!( + "{}: {var}", + name.as_str() + ))) + ); + } - expected.assert_eq(&res); + expected.assert_eq(&res); + }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c36a8677ddb3a..ae52986008f11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -157,7 +157,7 @@ pub use { tt, }, hir_ty::{ - CastError, DropGlue, FnAbi, PointerCast, Variance, + CastError, DropGlue, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, 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 5a2849220ed3f..1faa3c4165fdd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -14,7 +14,6 @@ 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, @@ -1637,7 +1636,7 @@ fn resolve_hir_path_( Some(unresolved) => resolver .generic_def() .and_then(|def| { - salsa::attach(db, || { + hir_ty::attach_db(db, || { hir_ty::associated_type_shorthand_candidates( db, def, 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 c0637a7470f3e..ade60691b57bc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -5,7 +5,7 @@ use hir::{Semantics, db::HirDatabase, setup_tracing}; use ide_db::{ EditionedFileId, FileRange, RootDatabase, SnippetCap, assists::ExprFillDefaultMode, - base_db::{SourceDatabase, salsa}, + base_db::SourceDatabase, imports::insert_use::{ImportGranularity, InsertUseConfig}, source_change::FileSystemEdit, }; @@ -109,7 +109,7 @@ fn assists( resolve: AssistResolveStrategy, range: ide_db::FileRange, ) -> Vec { - salsa::attach(db, || { + hir::attach_db(db, || { HirDatabase::zalsa_register_downcaster(db); crate::assists(db, config, resolve, range) }) @@ -332,7 +332,7 @@ fn check_with_config( _ => AssistResolveStrategy::All, }; let mut acc = Assists::new(&ctx, resolve); - salsa::attach(&db, || { + hir::attach_db(&db, || { HirDatabase::zalsa_register_downcaster(&db); handler(&mut acc, &ctx); }); 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 77a94403abb94..9ab7b7c82e432 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 @@ -1,7 +1,6 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use base_db::salsa; use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; @@ -86,7 +85,7 @@ pub(super) fn expand_and_analyze<'db>( let original_offset = expansion.original_offset + relative_offset; let token = expansion.original_file.token_at_offset(original_offset).left_biased()?; - salsa::attach(sema.db, || analyze(sema, expansion, original_token, &token)).map( + hir::attach_db(sema.db, || analyze(sema, expansion, original_token, &token)).map( |(analysis, expected, qualifier_ctx)| AnalysisResult { analysis, expected, 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 d9ec7915e3c72..24647ab6279dc 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,4 +1,3 @@ -use base_db::salsa; use expect_test::{Expect, expect}; use hir::HirDisplay; @@ -11,12 +10,12 @@ fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, let (db, pos) = position(ra_fixture); let config = TEST_CONFIG; let (completion_context, _analysis) = - salsa::attach(&db, || CompletionContext::new(&db, pos, &config).unwrap()); + hir::attach_db(&db, || CompletionContext::new(&db, pos, &config).unwrap()); let ty = completion_context .expected_type .map(|t| { - salsa::attach(&db, || { + hir::attach_db(&db, || { t.display_test(&db, completion_context.krate.to_display_target(&db)).to_string() }) }) 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 b20b570c2b8df..ec9cd9fdf3782 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, salsa}; +use base_db::SourceDatabase; use expect_test::Expect; use hir::db::HirDatabase; use hir::{PrefixKind, setup_tracing}; @@ -244,7 +244,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 = - salsa::attach(&db, || crate::completions(&db, &config, position, None).unwrap()); + hir::attach_db(&db, || crate::completions(&db, &config, position, None).unwrap()); let (completion,) = completions .iter() .filter(|it| it.lookup() == what) @@ -307,7 +307,7 @@ pub(crate) fn get_all_items( trigger_character: Option, ) -> Vec { let (db, position) = position(code); - let res = salsa::attach(&db, || { + let res = hir::attach_db(&db, || { HirDatabase::zalsa_register_downcaster(&db); crate::completions(&db, &config, position, trigger_character) }) 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 d78a3731011e8..2d3ebad9340c7 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,4 +1,3 @@ -use base_db::salsa; use expect_test::{Expect, expect}; use crate::{ @@ -20,7 +19,7 @@ fn check_with_config( let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); let mut acc = crate::completions::Completions::default(); - salsa::attach(ctx.db, || { + hir::attach_db(ctx.db, || { if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) = &analysis { 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 76b647f8e9f2d..c5ea9bcf5f107 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 @@ -134,7 +134,7 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar let _p = tracing::info_span!("library_symbols").entered(); // We call this without attaching because this runs in parallel, so we need to attach here. - salsa::attach(db, || { + hir::attach_db(db, || { let mut symbol_collector = SymbolCollector::new(db); db.source_root_crates(source_root_id) @@ -153,7 +153,7 @@ fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc let _p = tracing::info_span!("module_symbols").entered(); // 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)))) + hir::attach_db(db, || Arc::new(SymbolIndex::new(SymbolCollector::new_module(db, module)))) } pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc]> { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 2e03665765f38..1a0ef55a8b259 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -473,7 +473,7 @@ mod tests { frange.range, "selection is not an expression(yet contained in one)" ); - let name = salsa::attach(sema.db, || NameGenerator::default().for_variable(&expr, &sema)); + let name = hir::attach_db(sema.db, || NameGenerator::default().for_variable(&expr, &sema)); assert_eq!(&name, expected); } 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 1839ab1c58c1e..37af05e0d1bbf 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, salsa}, + base_db::SourceDatabase, }; use itertools::Itertools; use stdx::trim_indent; @@ -74,7 +74,7 @@ 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 = salsa::attach(&db, || { + let diagnostic = hir::attach_db(&db, || { super::full_diagnostics( &db, &config, @@ -129,7 +129,7 @@ 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 = salsa::attach(&db, || { + let fix = hir::attach_db(&db, || { super::full_diagnostics( &db, &conf, @@ -170,7 +170,7 @@ 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 = salsa::attach(&db, || { + let diagnostic = hir::attach_db(&db, || { super::full_diagnostics( &db, &DiagnosticsConfig::test_sample(), @@ -212,7 +212,7 @@ pub(crate) fn check_diagnostics_with_config( .iter() .copied() .flat_map(|file_id| { - salsa::attach(&db, || { + hir::attach_db(&db, || { super::full_diagnostics( &db, &config, @@ -288,12 +288,12 @@ 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 = salsa::attach(&db, || { + let diagnostics = hir::attach_db(&db, || { super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id) }); assert!(diagnostics.is_empty()); - let diagnostics = salsa::attach(&db, || { + let diagnostics = hir::attach_db(&db, || { super::full_diagnostics( &db, &DiagnosticsConfig::test_sample(), diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 9c0b9a6ff99bb..264f0660d7f29 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -791,8 +791,6 @@ impl PatternIterator { #[cfg(test)] mod tests { - use ide_db::base_db::salsa; - use crate::{MatchFinder, SsrRule}; #[test] @@ -801,7 +799,7 @@ mod tests { let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }"; let (db, position, selections) = crate::tests::single_file(input); - salsa::attach(&db, || { + hir::attach_db(&db, || { let position = ide_db::FilePosition { file_id: position.file_id.file_id(&db), offset: position.offset, 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 1d5f5adf2eefe..a48c0f8a57ec4 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, base_db::salsa}; +use ide_db::FxHashMap; use parsing::Placeholder; use syntax::{ SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, @@ -48,7 +48,7 @@ impl<'db> ResolvedRule<'db> { resolution_scope: &ResolutionScope<'db>, index: usize, ) -> Result, SsrError> { - salsa::attach(resolution_scope.scope.db, || { + hir::attach_db(resolution_scope.scope.db, || { let resolver = Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in, 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 24ad3ba7efe0b..1bb435f31f29d 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs @@ -2,10 +2,7 @@ use expect_test::{Expect, expect}; use hir::{FilePosition, FileRange}; use ide_db::{ EditionedFileId, FxHashSet, - base_db::{ - SourceDatabase, - salsa::{self, Durability}, - }, + base_db::{SourceDatabase, salsa::Durability}, }; use test_utils::RangeOrOffset; use triomphe::Arc; @@ -101,7 +98,7 @@ fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { let (db, position, selections) = single_file(input); - salsa::attach(&db, || { + hir::attach_db(&db, || { let position = ide_db::FilePosition { file_id: position.file_id.file_id(&db), offset: position.offset, @@ -149,7 +146,7 @@ fn print_match_debug_info(match_finder: &MatchFinder<'_>, file_id: EditionedFile fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { let (db, position, selections) = single_file(code); - salsa::attach(&db, || { + hir::attach_db(&db, || { let mut match_finder = MatchFinder::in_context( &db, ide_db::FilePosition { @@ -177,7 +174,7 @@ fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { fn assert_no_match(pattern: &str, code: &str) { let (db, position, selections) = single_file(code); - salsa::attach(&db, || { + hir::attach_db(&db, || { let mut match_finder = MatchFinder::in_context( &db, ide_db::FilePosition { 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 72436307d2cee..3fd885535a234 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,7 +4,6 @@ use expect_test::{Expect, expect}; use hir::Semantics; use ide_db::{ FilePosition, FileRange, RootDatabase, - base_db::salsa, defs::Definition, documentation::{DocsRangeMap, Documentation, HasDocs}, }; @@ -48,7 +47,7 @@ fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect let sema = &Semantics::new(&analysis.db); let (cursor_def, docs, range) = def_under_cursor(sema, &position); let res = - salsa::attach(sema.db, || rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range))); + hir::attach_db(sema.db, || rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range))); expect.assert_eq(&res) } @@ -65,7 +64,7 @@ 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 = salsa::attach(sema.db, || { + let def = hir::attach_db(sema.db, || { resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr) .unwrap_or_else(|| panic!("Failed to resolve {link}")) }); 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 507af41d84461..f7b09b43813d6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,9 +8,7 @@ use hir::{ ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; -use ide_db::{ - FileRange, RootDatabase, base_db::salsa, famous_defs::FamousDefs, text_edit::TextEditBuilder, -}; +use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder}; use ide_db::{FxHashSet, text_edit::TextEdit}; use itertools::Itertools; use smallvec::{SmallVec, smallvec}; @@ -107,7 +105,7 @@ pub(crate) fn inlay_hints( } }; let mut preorder = file.preorder(); - salsa::attach(sema.db, || { + hir::attach_db(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()) { @@ -739,7 +737,7 @@ fn label_of_ty( config: &InlayHintsConfig, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { - salsa::attach(sema.db, || { + hir::attach_db(sema.db, || { let iter_item_type = hint_iterator(sema, famous_defs, ty); match iter_item_type { Some((iter_trait, item, ty)) => { 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 0fd587a728408..7231a3194d095 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::{base_db::salsa, famous_defs::FamousDefs}; +use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::TextEditBuilder; use syntax::ast::{self, AstNode, prec::ExprPrecedence}; @@ -216,7 +216,7 @@ pub(super) fn hints( text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, linked_location: None, tooltip: Some(config.lazy_tooltip(|| { - salsa::attach(sema.db, || { + hir::attach_db(sema.db, || { InlayTooltip::Markdown(format!( "`{}` → `{}`\n\n**{}**\n\n{}", source.display(sema.db, display_target), diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 5febe4ee20bc6..f7d21c9479505 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::{self, Cancelled}, + salsa::Cancelled, }, prime_caches, symbol_index, }; @@ -480,7 +480,7 @@ impl Analysis { // if we were to attach it here. Cancelled::catch(|| { let symbols = symbol_index::world_symbols(&self.db, query); - salsa::attach(&self.db, || { + hir::attach_db(&self.db, || { symbols .into_iter() .filter_map(|s| s.try_to_nav(&Semantics::new(&self.db))) @@ -899,7 +899,7 @@ impl Analysis { where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - salsa::attach(&self.db, || { + hir::attach_db(&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); 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 46ff16f972625..db1298385b113 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -10,7 +10,7 @@ use hir::{ }; use ide_db::{ FileId, FileRange, RootDatabase, SymbolKind, - base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb, salsa}, + base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb}, defs::{Definition, find_std_module}, documentation::{Documentation, HasDocs}, famous_defs::FamousDefs, @@ -399,7 +399,7 @@ where ) .map(|mut res| { res.docs = self.docs(db); - res.description = salsa::attach(db, || { + res.description = hir::attach_db(db, || { Some(self.display(db, self.krate(db).to_display_target(db)).to_string()) }); res.container_name = self.container_name(db); @@ -520,7 +520,7 @@ 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 = salsa::attach(db, || { + res.description = hir::attach_db(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 ec13ba0fde340..cc1bbfbe20d63 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, salsa}, + base_db::RootQueryDb, defs::Definition, documentation::docs_from_attrs, helpers::visit_file_defs, @@ -413,7 +413,7 @@ 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 = salsa::attach(sema.db, || { + let params = hir::attach_db(sema.db, || { if ty_args.peek().is_some() { format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))) } else { @@ -522,7 +522,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op let mut ty_args = ty.generic_parameters(db, display_target).peekable(); format_to!(path, "{}", name.display(db, edition)); if ty_args.peek().is_some() { - salsa::attach(db, || { + hir::attach_db(db, || { format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); }); } 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 e74d997e97c52..5f7e12cf53f84 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -11,7 +11,6 @@ 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; @@ -267,7 +266,7 @@ 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. - salsa::attach(db, || match (p.ty().contains_unknown(), fn_params.as_deref()) { + hir::attach_db(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)) } @@ -730,7 +729,7 @@ fn signature_help_for_tuple_pat_ish<'db>( mod tests { use expect_test::{Expect, expect}; - use ide_db::{FilePosition, base_db::salsa}; + use ide_db::FilePosition; use stdx::format_to; use test_fixture::ChangeFixture; @@ -759,7 +758,7 @@ mod tests { "# ); let (db, position) = position(&fixture); - let sig_help = salsa::attach(&db, || crate::signature_help::signature_help(&db, position)); + let sig_help = hir::attach_db(&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/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 3f3d36bde2fa6..453d6f537a8bf 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, salsa}, + base_db::{RootQueryDb, SourceDatabase, VfsPath}, defs::{Definition, IdentClass}, documentation::Documentation, famous_defs::FamousDefs, @@ -276,7 +276,7 @@ impl StaticIndex<'_> { for token in tokens { let range = token.text_range(); let node = token.parent().unwrap(); - match salsa::attach(self.db, || get_definitions(&sema, token.clone())) { + match hir::attach_db(self.db, || get_definitions(&sema, token.clone())) { Some(it) => { for i in it { add_token(i, range, &node); @@ -293,7 +293,7 @@ impl StaticIndex<'_> { vendored_libs_config: VendoredLibrariesConfig<'_>, ) -> StaticIndex<'a> { let db = &analysis.db; - salsa::attach(db, || { + hir::attach_db(db, || { let work = all_modules(db).into_iter().filter(|module| { let file_id = module.definition_source_file_id(db).original_file(db); let source_root = 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 720183ac5478d..079dedda000c3 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, base_db::salsa}; +use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind}; use syntax::{ AstNode, AstToken, NodeOrToken, SyntaxKind::*, @@ -428,7 +428,7 @@ fn traverse( Some(current_body) => { let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| { ( - salsa::attach(sema.db, || sema.get_unsafe_ops(current_body)), + hir::attach_db(sema.db, || sema.get_unsafe_ops(current_body)), Default::default(), ) }); @@ -440,7 +440,7 @@ 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 = salsa::attach(sema.db, || { + let hl = hir::attach_db(sema.db, || { highlight::name_like( sema, krate, @@ -458,7 +458,7 @@ fn traverse( } hl } - NodeOrToken::Token(token) => salsa::attach(sema.db, || { + NodeOrToken::Token(token) => hir::attach_db(sema.db, || { highlight::token(sema, token, edition, &is_unsafe_node, tt_level > 0) .zip(Some(None)) }), 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 4bb7308024144..efc77823a2a45 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, base_db::salsa, defs::Definition, + SymbolKind, active_parameter::ActiveParameter, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence, }; use syntax::{ @@ -27,7 +27,7 @@ pub(super) fn ra_fixture( expanded: &ast::String, ) -> Option<()> { let active_parameter = - salsa::attach(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?; + hir::attach_db(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() @@ -128,7 +128,7 @@ 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) { - salsa::attach(sema.db, || { + hir::attach_db(sema.db, || { extract_definitions_from_docs(&docs) .into_iter() .filter_map(|(range, link, ns)| { 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 b014261981769..47ca616f3199b 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 @@ -213,14 +213,13 @@ mod tests { use crate::fixture; use expect_test::expect; - use ide_db::base_db::salsa; fn make_memory_layout( #[rust_analyzer::rust_fixture] ra_fixture: &str, ) -> Option { let (analysis, position, _) = fixture::annotations(ra_fixture); - salsa::attach(&analysis.db, || view_memory_layout(&analysis.db, position)) + hir::attach_db(&analysis.db, || view_memory_layout(&analysis.db, position)) } #[test] 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 9c8743536877b..24619004e1c0c 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 @@ -26,10 +26,7 @@ use ide::{ }; use ide_db::{ EditionedFileId, LineIndexDatabase, SnippetCap, - base_db::{ - SourceDatabase, - salsa::{self, Database}, - }, + base_db::{SourceDatabase, salsa::Database}, }; use itertools::Itertools; use load_cargo::{LoadCargoConfig, ProcMacroServerChoice, load_workspace}; @@ -315,7 +312,7 @@ impl flags::AnalysisStats { shuffle(&mut rng, &mut bodies); } - salsa::attach(db, || { + hir::attach_db(db, || { if !self.skip_lowering { self.run_body_lowering(db, &vfs, &bodies, verbosity); } diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 67ff27e31c0c3..6c363825aa185 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -67,6 +67,16 @@ const _: () = { self.parent.hash(state); } } + + impl zalsa_::HasJar for SyntaxContext { + type Jar = zalsa_struct_::JarImpl; + const KIND: zalsa_::JarKind = zalsa_::JarKind::Struct; + } + + zalsa_::register_jar! { + zalsa_::ErasedJar::erase::() + } + /// Key to use during hash lookups. Each field is some type that implements `Lookup` /// for the owned type. This permits interning with an `&str` when a `String` is required and so forth. #[derive(Hash)] From 22c1eb85f88f6036c771b4ee89d128f9e05a7e9c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 5 Oct 2025 15:18:48 +0800 Subject: [PATCH 33/59] minor: Remove FIXME for test_tuple_field_inference This seems to have been fixed --- .../rust-analyzer/crates/ide-completion/src/completions/dot.rs | 3 +-- 1 file changed, 1 insertion(+), 2 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 8b4f315ac5733..72b245ccafd90 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 @@ -794,8 +794,7 @@ struct T(S); impl T { fn foo(&self) { - // FIXME: This doesn't work without the trailing `a` as `0.` is a float - self.0.a$0 + self.0.$0 } } "#, From a4d51da309d33461d4a6aabf2acda3454cdb2485 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Sun, 5 Oct 2025 13:40:25 +0200 Subject: [PATCH 34/59] docs: Mention editor-independent configuration --- src/tools/rust-analyzer/docs/book/src/configuration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/rust-analyzer/docs/book/src/configuration.md b/src/tools/rust-analyzer/docs/book/src/configuration.md index 3f4cb197141fe..708eecd43561c 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration.md @@ -46,6 +46,11 @@ To verify which configuration is actually used by `rust-analyzer`, set config-related messages. Logs should show both the JSON that `rust-analyzer` sees as well as the updated config. +(Work in progress:) It is also possible to place configuration in a +`rust-analyzer.toml` file. It should be located in the project root or in your +user configuration directory (e.g. `~/.config/rust-analyzer/`). This is a work in +progress, many configuration options aren't supported yet. + This is the list of config options `rust-analyzer` supports: {{#include configuration_generated.md}} From c13b87752a332d8a0d39b0ab63c9621a194fd87c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 5 Oct 2025 15:19:52 +0300 Subject: [PATCH 35/59] Deprecate `preserve` import granularity option It didn't do anything (behaved like `item`), as with `enforceGranularity = false` (which is the default), the style of the current file is always preferred, regardless of the setting. We could make it fail when the setting is `preserve` and the current file's style could not be detected, but that makes little sense. It is a bit weird that the default is `crate` but `preserve` falls back to `item`, however that was the previous behavior. --- .../crates/ide-db/src/imports/insert_use.rs | 5 +-- .../crates/ide-diagnostics/src/lib.rs | 2 +- .../crates/rust-analyzer/src/config.rs | 29 ++++++++++----- .../rust-analyzer/editors/code/package.json | 37 ++++++++++++------- 4 files changed, 46 insertions(+), 27 deletions(-) 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 b174adfd7e448..caba1cdd70614 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 @@ -27,9 +27,6 @@ pub use hir::PrefixKind; /// How imports should be grouped into use statements. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ImportGranularity { - /// Do not change the granularity of any imports and preserve the original structure written - /// by the developer. - Preserve, /// Merge imports from the same crate into a single use statement. Crate, /// Merge imports from the same module into a single use statement. @@ -174,7 +171,7 @@ fn insert_use_with_alias_option( ImportGranularity::Crate => Some(MergeBehavior::Crate), ImportGranularity::Module => Some(MergeBehavior::Module), ImportGranularity::One => Some(MergeBehavior::One), - ImportGranularity::Item | ImportGranularity::Preserve => None, + ImportGranularity::Item => None, }; if !cfg.enforce_granularity { let file_granularity = guess_granularity_from_scope(scope); 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..1530e64652464 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -253,7 +253,7 @@ impl DiagnosticsConfig { style_lints: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { - granularity: ImportGranularity::Preserve, + granularity: ImportGranularity::Item, enforce_granularity: false, prefix_kind: PrefixKind::Plain, group: 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 a88d228fcb60c..d4805dc1bdaf0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1944,8 +1944,9 @@ impl Config { fn insert_use_config(&self, source_root: Option) -> InsertUseConfig { InsertUseConfig { granularity: match self.imports_granularity_group(source_root) { - ImportGranularityDef::Preserve => ImportGranularity::Preserve, - ImportGranularityDef::Item => ImportGranularity::Item, + ImportGranularityDef::Item | ImportGranularityDef::Preserve => { + ImportGranularity::Item + } ImportGranularityDef::Crate => ImportGranularity::Crate, ImportGranularityDef::Module => ImportGranularity::Module, ImportGranularityDef::One => ImportGranularity::One, @@ -3504,13 +3505,23 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, "ImportGranularityDef" => set! { "type": "string", - "enum": ["preserve", "crate", "module", "item", "one"], - "enumDescriptions": [ - "Do not change the granularity of any imports and preserve the original structure written by the developer.", - "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", - "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement.", - "Merge all imports into a single use statement as long as they have the same visibility and attributes." + "anyOf": [ + { + "enum": ["crate", "module", "item", "one"], + "enumDescriptions": [ + "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", + "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", + "Flatten imports so that each has its own use statement.", + "Merge all imports into a single use statement as long as they have the same visibility and attributes." + ], + }, + { + "enum": ["preserve"], + "enumDescriptions": [ + "Deprecated - unless `enforceGranularity` is `true`, the style of the current file is preferred over this setting. Behaves like `item`.", + ], + "deprecated": true, + } ], }, "ImportPrefixDef" => set! { diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 745e0da4efef0..5c75a45ee9252 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2009,19 +2009,30 @@ "markdownDescription": "How imports should be grouped into use statements.", "default": "crate", "type": "string", - "enum": [ - "preserve", - "crate", - "module", - "item", - "one" - ], - "enumDescriptions": [ - "Do not change the granularity of any imports and preserve the original structure written by the developer.", - "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", - "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", - "Flatten imports so that each has its own use statement.", - "Merge all imports into a single use statement as long as they have the same visibility and attributes." + "anyOf": [ + { + "enum": [ + "crate", + "module", + "item", + "one" + ], + "enumDescriptions": [ + "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", + "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", + "Flatten imports so that each has its own use statement.", + "Merge all imports into a single use statement as long as they have the same visibility and attributes." + ] + }, + { + "enum": [ + "preserve" + ], + "enumDescriptions": [ + "Deprecated - unless `enforceGranularity` is `true`, the style of the current file is preferred over this setting. Behaves like `item`." + ], + "deprecated": true + } ] } } From a958b84ea4df97608fcaf5d35ce8de91b1961109 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 5 Oct 2025 15:48:03 +0300 Subject: [PATCH 36/59] Fix merging of import granularity setting with the granularity we infer Previously it was wrong for some combinations. --- .../crates/ide-db/src/imports/insert_use.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 caba1cdd70614..4444ef5d81d54 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 @@ -179,9 +179,18 @@ fn insert_use_with_alias_option( ImportGranularityGuess::Unknown => mb, ImportGranularityGuess::Item => None, ImportGranularityGuess::Module => Some(MergeBehavior::Module), - ImportGranularityGuess::ModuleOrItem => mb.and(Some(MergeBehavior::Module)), + // We use the user's setting to infer if this is module or item. + ImportGranularityGuess::ModuleOrItem => match mb { + Some(MergeBehavior::Module) | None => mb, + // There isn't really a way to decide between module or item here, so we just pick one. + // FIXME: Maybe it is possible to infer based on semantic analysis? + Some(MergeBehavior::One | MergeBehavior::Crate) => Some(MergeBehavior::Module), + }, ImportGranularityGuess::Crate => Some(MergeBehavior::Crate), - ImportGranularityGuess::CrateOrModule => mb.or(Some(MergeBehavior::Crate)), + ImportGranularityGuess::CrateOrModule => match mb { + Some(MergeBehavior::Crate | MergeBehavior::Module) => mb, + Some(MergeBehavior::One) | None => Some(MergeBehavior::Crate), + }, ImportGranularityGuess::One => Some(MergeBehavior::One), }; } From c7a6a799f026ea423ff08281166aec3256a77456 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 5 Oct 2025 21:56:08 +0300 Subject: [PATCH 37/59] Add regression test for need-mut diagnostic --- .../src/handlers/mutability_errors.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 6e30bf92dbaa1..eefa1ac24add1 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1302,6 +1302,22 @@ fn main() { let mut var = 1; let mut func = || (var,) = (2,); func(); +} + "#, + ); + } + + #[test] + fn regression_20662() { + check_diagnostics( + r#" +//- minicore: index +pub trait A: core::ops::IndexMut { + type T: A; +} + +fn func(a: &mut impl A, b: &mut [i32]) { + b[0] += 1; } "#, ); From c4073c5ae3ffd3f673932f86c43f829eef7656f3 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 5 Oct 2025 22:07:58 +0300 Subject: [PATCH 38/59] Replace `--show-output` with `--nocapture` The former does not show any output before the test is finished, which prevents long-running/stuck tests from showing any useful information. --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- .../crates/rust-analyzer/tests/slow-tests/main.rs | 4 ++-- .../rust-analyzer/docs/book/src/configuration_generated.md | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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 a88d228fcb60c..8272ba7f6bf0b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -895,7 +895,7 @@ config_data! { /// [custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field), /// they will end up being interpreted as options to /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments). - runnables_extraTestBinaryArgs: Vec = vec!["--show-output".to_owned()], + runnables_extraTestBinaryArgs: Vec = vec!["--nocapture".to_owned()], /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private /// projects, or "discover" to try to automatically find it if the `rustc-dev` component 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 8a04bc7798f8b..5a4ad6f380f90 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 @@ -256,7 +256,7 @@ fn main() {} { "args": { "cargoArgs": ["test", "--package", "foo", "--test", "spam"], - "executableArgs": ["test_eggs", "--exact", "--show-output"], + "executableArgs": ["test_eggs", "--exact", "--nocapture"], "overrideCargo": null, "cwd": server.path().join("foo"), "workspaceRoot": server.path().join("foo") @@ -289,7 +289,7 @@ fn main() {} ], "executableArgs": [ "", - "--show-output" + "--nocapture" ] }, "kind": "cargo", 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 e78f1b4ba3582..d768993f501fc 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1323,7 +1323,7 @@ tests or binaries. For example, it may be `--release`. Default: ```json [ - "--show-output" + "--nocapture" ] ``` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 745e0da4efef0..e9d00e4f1f346 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2789,7 +2789,7 @@ "rust-analyzer.runnables.extraTestBinaryArgs": { "markdownDescription": "Additional arguments to be passed through Cargo to launched tests, benchmarks, or\ndoc-tests.\n\nUnless the launched target uses a\n[custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),\nthey will end up being interpreted as options to\n[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).", "default": [ - "--show-output" + "--nocapture" ], "type": "array", "items": { From 4808fd4c980417b34e28e4fae27009ccca30e3f1 Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Sun, 5 Oct 2025 18:24:19 -0500 Subject: [PATCH 39/59] Build rust-analyzer with specific target for install/pgo xtask --- src/tools/rust-analyzer/xtask/src/install.rs | 4 ++-- src/tools/rust-analyzer/xtask/src/pgo.rs | 25 +++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs index f0cc445dfa23f..b794f53e761e9 100644 --- a/src/tools/rust-analyzer/xtask/src/install.rs +++ b/src/tools/rust-analyzer/xtask/src/install.rs @@ -145,12 +145,12 @@ fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> { ); if let Some(train_crate) = opts.pgo { + let target = detect_target(sh); let build_cmd = cmd!( sh, - "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --profile={profile} --locked --features force-always-assert {features...}" + "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked --features force-always-assert {features...}" ); - let target = detect_target(sh); let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?; install_cmd = crate::pgo::apply_pgo_to_cmd(install_cmd, &profile); } diff --git a/src/tools/rust-analyzer/xtask/src/pgo.rs b/src/tools/rust-analyzer/xtask/src/pgo.rs index 7f7b3311d9626..0c6f499811a24 100644 --- a/src/tools/rust-analyzer/xtask/src/pgo.rs +++ b/src/tools/rust-analyzer/xtask/src/pgo.rs @@ -53,14 +53,23 @@ pub(crate) fn gather_pgo_profile<'a>( // Merge profiles into a single file let merged_profile = pgo_dir.join("merged.profdata"); - let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| { - let entry = entry.ok()?; - if entry.path().extension() == Some(OsStr::new("profraw")) { - Some(entry.path().to_str().unwrap().to_owned()) - } else { - None - } - }); + let profile_files = std::fs::read_dir(pgo_dir)? + .filter_map(|entry| { + let entry = entry.ok()?; + if entry.path().extension() == Some(OsStr::new("profraw")) { + Some(entry.path().to_str().unwrap().to_owned()) + } else { + None + } + }) + .collect::>(); + + if profile_files.is_empty() { + anyhow::bail!( + "rust-analyzer analysis-stats produced no pgo files. This is a bug in rust-analyzer; please file an issue." + ); + } + cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context( "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?", )?; From 7b9e26ea6cd7a109f55f8d483528e06309c71e30 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 6 Oct 2025 12:48:38 +0800 Subject: [PATCH 40/59] Improve parsing error for `static` and `const` Example --- ```rust static C: u32 = 0; ``` -> ```diff -error 8: missing type for `const` or `static` +error 8: `static` may not have generic parameters ``` --- ```rust const C = 0; ``` -> ```diff -error 7: missing type for `const` or `static` +error 7: missing type for `const` ``` --- ```rust static C = 0; ``` -> ```diff -error 8: missing type for `const` or `static` +error 8: missing type for `static` ``` --- .../crates/parser/src/grammar/items/consts.rs | 12 ++++++++++-- .../crates/parser/test_data/generated/runner.rs | 8 ++++++++ .../test_data/parser/err/0044_item_modifiers.rast | 2 +- .../parser/inline/err/generic_static.rast | 2 +- .../parser/inline/err/missing_const_type.rast | 14 ++++++++++++++ .../parser/inline/err/missing_const_type.rs | 1 + .../parser/inline/err/missing_static_type.rast | 14 ++++++++++++++ .../parser/inline/err/missing_static_type.rs | 1 + 8 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs index 8e255985a205d..6b53493c9a36d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs @@ -32,14 +32,22 @@ fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { // const C<'a>: &'a () = &(); // } generic_params::opt_generic_param_list(p); + } else if p.at(T![<]) { + p.error("`static` may not have generic parameters"); } // test_err generic_static // static C: u32 = 0; if p.at(T![:]) { types::ascription(p); - } else { - p.error("missing type for `const` or `static`"); + } else if is_const { + // test_err missing_const_type + // const C = 0; + p.error("missing type for `const`"); + } else if !p.at(T![<]) { + // test_err missing_static_type + // static C = 0; + p.error("missing type for `static`"); } if p.eat(T![=]) { expressions::expr(p); 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 a3cfe64e6e739..cd6d433d0efa7 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 @@ -824,10 +824,18 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/misplaced_label_err.rs"); } #[test] + fn missing_const_type() { + run_and_expect_errors("test_data/parser/inline/err/missing_const_type.rs"); + } + #[test] fn missing_fn_param_type() { run_and_expect_errors("test_data/parser/inline/err/missing_fn_param_type.rs"); } #[test] + fn missing_static_type() { + run_and_expect_errors("test_data/parser/inline/err/missing_static_type.rs"); + } + #[test] fn path_item_without_excl() { run_and_expect_errors("test_data/parser/inline/err/path_item_without_excl.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast index d6e3219c39577..7a3ca66476e32 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast @@ -42,7 +42,7 @@ SOURCE_FILE WHITESPACE "\n" error 6: expected fn, trait or impl error 38: expected a name -error 40: missing type for `const` or `static` +error 40: missing type for `const` error 40: expected SEMICOLON error 44: expected an item error 44: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast index 485ad11f233ac..0c240b7214f43 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast @@ -30,7 +30,7 @@ SOURCE_FILE ERROR SEMICOLON ";" WHITESPACE "\n" -error 8: missing type for `const` or `static` +error 8: `static` may not have generic parameters error 8: expected SEMICOLON error 8: expected an item error 12: expected an item diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rast new file mode 100644 index 0000000000000..11097232a6831 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rast @@ -0,0 +1,14 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "C" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + SEMICOLON ";" + WHITESPACE "\n" +error 7: missing type for `const` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rs new file mode 100644 index 0000000000000..e3ce44dadfbd2 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_const_type.rs @@ -0,0 +1 @@ +const C = 0; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rast new file mode 100644 index 0000000000000..a9595401d6d62 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rast @@ -0,0 +1,14 @@ +SOURCE_FILE + STATIC + STATIC_KW "static" + WHITESPACE " " + NAME + IDENT "C" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + SEMICOLON ";" + WHITESPACE "\n" +error 8: missing type for `static` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rs new file mode 100644 index 0000000000000..33ecedf80772b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/missing_static_type.rs @@ -0,0 +1 @@ +static C = 0; From a392656b172778f6b61190ef9e1e3cd3496d3d3a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 6 Oct 2025 11:38:23 +0200 Subject: [PATCH 41/59] feat: Log flycheck stdout and stderr to files --- .../crates/rust-analyzer/src/command.rs | 26 ++++++++++++++++--- .../crates/rust-analyzer/src/discover.rs | 2 +- .../crates/rust-analyzer/src/flycheck.rs | 17 +++++++++++- .../crates/rust-analyzer/src/test_runner.rs | 7 ++++- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs index d6c80c399ba2e..674e8623b2d07 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs @@ -3,13 +3,15 @@ use std::{ ffi::OsString, - fmt, io, + fmt, + io::{self, BufWriter, Write}, marker::PhantomData, path::PathBuf, process::{ChildStderr, ChildStdout, Command, Stdio}, }; use crossbeam_channel::Sender; +use paths::Utf8PathBuf; use process_wrap::std::{StdChildWrapper, StdCommandWrap}; use stdx::process::streaming_output; @@ -40,7 +42,7 @@ impl CargoActor { } impl CargoActor { - fn run(self) -> io::Result<(bool, String)> { + fn run(self, outfile: Option) -> io::Result<(bool, String)> { // We manually read a line at a time, instead of using serde's // stream deserializers, because the deserializer cannot recover // from an error, resulting in it getting stuck, because we try to @@ -50,6 +52,15 @@ impl CargoActor { // simply skip a line if it doesn't parse, which just ignores any // erroneous output. + let mut stdout = outfile.as_ref().and_then(|path| { + _ = std::fs::create_dir_all(path); + Some(BufWriter::new(std::fs::File::create(path.join("stdout")).ok()?)) + }); + let mut stderr = outfile.as_ref().and_then(|path| { + _ = std::fs::create_dir_all(path); + Some(BufWriter::new(std::fs::File::create(path.join("stderr")).ok()?)) + }); + let mut stdout_errors = String::new(); let mut stderr_errors = String::new(); let mut read_at_least_one_stdout_message = false; @@ -67,11 +78,19 @@ impl CargoActor { self.stdout, self.stderr, &mut |line| { + if let Some(stdout) = &mut stdout { + _ = stdout.write_all(line.as_bytes()); + _ = stdout.write_all(b"\n"); + } if process_line(line, &mut stdout_errors) { read_at_least_one_stdout_message = true; } }, &mut |line| { + if let Some(stderr) = &mut stderr { + _ = stderr.write_all(line.as_bytes()); + _ = stderr.write_all(b"\n"); + } if process_line(line, &mut stderr_errors) { read_at_least_one_stderr_message = true; } @@ -130,6 +149,7 @@ impl CommandHandle { mut command: Command, parser: impl CargoParser, sender: Sender, + out_file: Option, ) -> std::io::Result { command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); @@ -150,7 +170,7 @@ impl CommandHandle { let actor = CargoActor::::new(parser, sender, stdout, stderr); let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "CommandHandle") - .spawn(move || actor.run()) + .spawn(move || actor.run(out_file)) .expect("failed to spawn thread"); Ok(CommandHandle { program, arguments, current_dir, child, thread, _phantom: PhantomData }) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs index 24c433610f1a3..4ec0c075dd5be 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs @@ -67,7 +67,7 @@ impl DiscoverCommand { cmd.args(args); Ok(DiscoverHandle { - _handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone())?, + _handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?, span: info_span!("discover_command").entered(), }) } 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 cded34be14a28..b545106fe1cfb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -423,7 +423,21 @@ impl FlycheckActor { tracing::debug!(?command, "will restart flycheck"); let (sender, receiver) = unbounded(); - match CommandHandle::spawn(command, CargoCheckParser, sender) { + match CommandHandle::spawn( + command, + CargoCheckParser, + sender, + match &self.config { + FlycheckConfig::CargoCommand { options, .. } => Some( + options + .target_dir + .as_deref() + .unwrap_or("target".as_ref()) + .join(format!("rust-analyzer/flycheck{}", self.id)), + ), + _ => None, + }, + ) { Ok(command_handle) => { tracing::debug!(command = formatted_command, "did restart flycheck"); self.command_handle = Some(command_handle); @@ -622,6 +636,7 @@ impl FlycheckActor { { cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); } + cmd.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); cmd.arg(command); match scope { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs index e7528dbc9396d..0c8658c75df0a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs @@ -136,7 +136,12 @@ impl CargoTestHandle { } Ok(Self { - _handle: CommandHandle::spawn(cmd, CargoTestOutputParser::new(&test_target), sender)?, + _handle: CommandHandle::spawn( + cmd, + CargoTestOutputParser::new(&test_target), + sender, + None, + )?, }) } } From e8d57e96725f97fd5e0341197f3e097db580c50e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 8 Oct 2025 16:02:25 +0800 Subject: [PATCH 42/59] Add self param completions for trait assoc fn Example --- ```rust trait A { fn foo(file_id: usize) {} fn new($0) {} } ``` **Before this PR**: ```text bn file_id: usize kw mut kw ref ``` **After this PR**: ```text bn &mut self bn &self bn file_id: usize bn mut self bn self kw mut kw ref ``` --- .../crates/ide-completion/src/completions.rs | 4 +- .../ide-completion/src/completions/expr.rs | 2 +- .../src/completions/fn_param.rs | 15 +++---- .../ide-completion/src/completions/pattern.rs | 2 +- .../crates/ide-completion/src/context.rs | 3 +- .../ide-completion/src/context/analysis.rs | 15 ++++--- .../ide-completion/src/tests/fn_param.rs | 42 +++++++++++++++++++ 7 files changed, 65 insertions(+), 18 deletions(-) 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 eb2bb31f963e1..b822f53d7b7b7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -630,7 +630,7 @@ fn enum_variants_with_paths( acc: &mut Completions, ctx: &CompletionContext<'_>, enum_: hir::Enum, - impl_: &Option, + impl_: Option<&ast::Impl>, cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), ) { let mut process_variant = |variant: Variant| { @@ -644,7 +644,7 @@ fn enum_variants_with_paths( let variants = enum_.variants(ctx.db); - if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) + if let Some(impl_) = impl_.and_then(|impl_| ctx.sema.to_def(impl_)) && impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { variants.iter().for_each(|variant| process_variant(*variant)); 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 080875e016329..4c79357941516 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 @@ -297,7 +297,7 @@ pub(crate) fn complete_expr_path( acc, ctx, e, - impl_, + impl_.as_ref(), |acc, ctx, variant, path| { acc.add_qualified_enum_variant(ctx, path_ctx, variant, path) }, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index fb78386976d61..34d25c9c67283 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -2,6 +2,7 @@ use hir::HirDisplay; use ide_db::FxHashMap; +use itertools::Either; use syntax::{ AstNode, Direction, SyntaxKind, TextRange, TextSize, algo, ast::{self, HasModuleItem}, @@ -24,8 +25,8 @@ pub(crate) fn complete_fn_param( ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, ) -> Option<()> { - let (ParamContext { param_list, kind, .. }, impl_) = match pattern_ctx { - PatternContext { param_ctx: Some(kind), impl_, .. } => (kind, impl_), + let (ParamContext { param_list, kind, .. }, impl_or_trait) = match pattern_ctx { + PatternContext { param_ctx: Some(kind), impl_or_trait, .. } => (kind, impl_or_trait), _ => return None, }; @@ -45,7 +46,7 @@ pub(crate) fn complete_fn_param( match kind { ParamKind::Function(function) => { - fill_fn_params(ctx, function, param_list, impl_, add_new_item_to_acc); + fill_fn_params(ctx, function, param_list, impl_or_trait, add_new_item_to_acc); } ParamKind::Closure(closure) => { let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; @@ -62,7 +63,7 @@ fn fill_fn_params( ctx: &CompletionContext<'_>, function: &ast::Fn, param_list: &ast::ParamList, - impl_: &Option, + impl_or_trait: &Option>, mut add_new_item_to_acc: impl FnMut(&str), ) { let mut file_params = FxHashMap::default(); @@ -107,7 +108,7 @@ fn fill_fn_params( } remove_duplicated(&mut file_params, param_list.params()); let self_completion_items = ["self", "&self", "mut self", "&mut self"]; - if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_) { + if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_or_trait) { self_completion_items.into_iter().for_each(&mut add_new_item_to_acc); } @@ -161,9 +162,9 @@ fn remove_duplicated( fn should_add_self_completions( cursor: TextSize, param_list: &ast::ParamList, - impl_: &Option, + impl_or_trait: &Option>, ) -> bool { - if impl_.is_none() || param_list.self_param().is_some() { + if impl_or_trait.is_none() || param_list.self_param().is_some() { return false; } match param_list.params().next() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 815ce5145dbec..0ce81d02b4096 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -70,7 +70,7 @@ pub(crate) fn complete_pattern( acc, ctx, e, - &pattern_ctx.impl_, + pattern_ctx.impl_or_trait.as_ref().and_then(|it| it.as_ref().left()), |acc, ctx, variant, path| { acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path); }, 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 9deaaf6631270..d9b0d3296a964 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -15,6 +15,7 @@ use ide_db::{ FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, }; +use itertools::Either; use syntax::{ AstNode, Edition, SmolStr, SyntaxKind::{self, *}, @@ -282,7 +283,7 @@ pub(crate) struct PatternContext { pub(crate) mut_token: Option, /// The record pattern this name or ref is a field of pub(crate) record_pat: Option, - pub(crate) impl_: Option, + pub(crate) impl_or_trait: Option>, /// List of missing variants in a match expr pub(crate) missing_variants: Vec, } 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 9ab7b7c82e432..6cd098462f4db 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 @@ -1302,7 +1302,8 @@ fn classify_name_ref<'db>( .is_some_and(|it| it.semicolon_token().is_none()) || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw; let in_value = it.parent().and_then(Either::::cast).is_some(); - let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); + let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax()) + .and_then(Either::left); let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) { Some(arm) => arm @@ -1755,27 +1756,29 @@ fn pattern_context_for( mut_token, ref_token, record_pat: None, - impl_: fetch_immediate_impl(sema, original_file, pat.syntax()), + impl_or_trait: fetch_immediate_impl_or_trait(sema, original_file, pat.syntax()), missing_variants, } } -fn fetch_immediate_impl( +fn fetch_immediate_impl_or_trait( sema: &Semantics<'_, RootDatabase>, original_file: &SyntaxNode, node: &SyntaxNode, -) -> Option { +) -> Option> { let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)? .filter_map(ast::Item::cast) .filter(|it| !matches!(it, ast::Item::MacroCall(_))); match ancestors.next()? { ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (), - ast::Item::Impl(it) => return Some(it), + ast::Item::Impl(it) => return Some(Either::Left(it)), + ast::Item::Trait(it) => return Some(Either::Right(it)), _ => return None, } match ancestors.next()? { - ast::Item::Impl(it) => Some(it), + ast::Item::Impl(it) => Some(Either::Left(it)), + ast::Item::Trait(it) => Some(Either::Right(it)), _ => None, } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs index 451ce07c7454b..02cba6b6467e5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs @@ -85,7 +85,11 @@ pub(crate) trait SourceRoot { } "#, expect![[r#" + bn &mut self + bn &self bn file_id: usize + bn mut self + bn self kw mut kw ref "#]], @@ -183,6 +187,44 @@ impl A { ) } +#[test] +fn in_trait_only_param() { + check( + r#" +trait A { + fn foo(file_id: usize) {} + fn new($0) {} +} +"#, + expect![[r#" + bn &mut self + bn &self + bn file_id: usize + bn mut self + bn self + kw mut + kw ref + "#]], + ) +} + +#[test] +fn in_trait_after_self() { + check( + r#" +trait A { + fn foo(file_id: usize) {} + fn new(self, $0) {} +} +"#, + expect![[r#" + bn file_id: usize + kw mut + kw ref + "#]], + ) +} + // doesn't complete qux due to there being no expression after // see source_analyzer::adjust comment #[test] From 0553ec97520ad5db7d31ebdd817d5aabd3534463 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 2 Oct 2025 23:22:28 +0300 Subject: [PATCH 43/59] Migrate drop glue handling to new solver And: - Remove it from being a query (it is only used for hover, where no caching is needed, and MIR evaluation of `needs_drop()`, which is rare). - Fix handling of `PhantomData`. --- .../hir-ty/src/consteval/tests/intrinsics.rs | 9 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 5 - .../rust-analyzer/crates/hir-ty/src/drop.rs | 194 ++++++++---------- .../rust-analyzer/crates/hir-ty/src/lib.rs | 3 +- .../crates/hir-ty/src/mir/eval.rs | 10 +- .../crates/hir-ty/src/mir/eval/shim.rs | 8 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 12 +- 7 files changed, 113 insertions(+), 128 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 5e85978e2990d..10282d21168a3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -354,8 +354,9 @@ fn overflowing_add() { fn needs_drop() { check_number( r#" - //- minicore: drop, manually_drop, copy, sized + //- minicore: drop, manually_drop, copy, sized, phantom_data use core::mem::ManuallyDrop; + use core::marker::PhantomData; extern "rust-intrinsic" { pub fn needs_drop() -> bool; } @@ -380,17 +381,19 @@ fn needs_drop() { const fn opaque_copy() -> impl Sized + Copy { || {} } + struct RecursiveType(RecursiveType); trait Everything {} impl Everything for T {} const GOAL: bool = !needs_drop::() && !needs_drop::() && needs_drop::() && !needs_drop::>() && needs_drop::<[NeedsDrop; 1]>() && !needs_drop::<[NeedsDrop; 0]>() - && needs_drop::<(X, NeedsDrop)>() + && needs_drop::<(X, NeedsDrop)>() && !needs_drop::>() && needs_drop::>() && !needs_drop::>() && closure_needs_drop() && !val_needs_drop(opaque()) && !val_needs_drop(opaque_copy()) && needs_drop::<[NeedsDrop]>() && needs_drop::() - && !needs_drop::<&dyn Everything>() && !needs_drop::(); + && !needs_drop::<&dyn Everything>() && !needs_drop::() + && !needs_drop::(); "#, 1, ); 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 82d17cc618cd2..11d3be5c3c487 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -19,7 +19,6 @@ use crate::{ Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty, TyDefId, ValueTyDefId, chalk_db, consteval::ConstEvalError, - drop::DropGlue, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{Diagnostics, GenericDefaults, GenericPredicates}, @@ -334,10 +333,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { goal: crate::Canonical>, ) -> 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::lower_nextsolver::const_param_ty_query)] 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 0618fd17d55d0..4bd9691ea0795 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -1,18 +1,20 @@ //! Utilities for computing drop info about types. -use chalk_ir::cast::Cast; -use hir_def::AdtId; -use hir_def::lang_item::LangItem; -use hir_def::signatures::StructFlags; +use hir_def::{AdtId, lang_item::LangItem, signatures::StructFlags}; +use rustc_hash::FxHashSet; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use stdx::never; use triomphe::Arc; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ - AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, - Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, + TraitEnvironment, consteval_nextsolver, + db::HirDatabase, method_resolution::TyFingerprint, + next_solver::{ + Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + }, }; fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool { @@ -45,27 +47,52 @@ pub enum DropGlue { HasDropGlue, } -pub(crate) fn has_drop_glue( - db: &dyn HirDatabase, - ty: Ty, - env: Arc>, +pub fn has_drop_glue<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc>, ) -> DropGlue { - match ty.kind(Interner) { - TyKind::Adt(adt, subst) => { - if has_destructor(db, adt.0) { + has_drop_glue_impl(infcx, ty, env, &mut FxHashSet::default()) +} + +fn has_drop_glue_impl<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc>, + visited: &mut FxHashSet>, +) -> DropGlue { + let mut ocx = ObligationCtxt::new(infcx); + let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); + + if !visited.insert(ty) { + // Recursive type. + return DropGlue::None; + } + + let db = infcx.interner.db; + match ty.kind() { + TyKind::Adt(adt_def, subst) => { + let adt_id = adt_def.def_id().0; + if has_destructor(db, adt_id) { return DropGlue::HasDropGlue; } - match adt.0 { + match adt_id { AdtId::StructId(id) => { - if db.struct_signature(id).flags.contains(StructFlags::IS_MANUALLY_DROP) { + if db + .struct_signature(id) + .flags + .intersects(StructFlags::IS_MANUALLY_DROP | StructFlags::IS_PHANTOM_DATA) + { return DropGlue::None; } - db.field_types(id.into()) + db.field_types_ns(id.into()) .iter() .map(|(_, field_ty)| { - db.has_drop_glue( - field_ty.clone().substitute(Interner, subst), + has_drop_glue_impl( + infcx, + field_ty.instantiate(infcx.interner, subst), env.clone(), + visited, ) }) .max() @@ -78,12 +105,14 @@ pub(crate) fn has_drop_glue( .variants .iter() .map(|&(variant, _, _)| { - db.field_types(variant.into()) + db.field_types_ns(variant.into()) .iter() .map(|(_, field_ty)| { - db.has_drop_glue( - field_ty.clone().substitute(Interner, subst), + has_drop_glue_impl( + infcx, + field_ty.instantiate(infcx.interner, subst), env.clone(), + visited, ) }) .max() @@ -93,123 +122,70 @@ pub(crate) fn has_drop_glue( .unwrap_or(DropGlue::None), } } - TyKind::Tuple(_, subst) => subst - .iter(Interner) - .map(|ty| ty.assert_ty_ref(Interner)) - .map(|ty| db.has_drop_glue(ty.clone(), env.clone())) + TyKind::Tuple(tys) => tys + .iter() + .map(|ty| has_drop_glue_impl(infcx, ty, env.clone(), visited)) .max() .unwrap_or(DropGlue::None), TyKind::Array(ty, len) => { - if let ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Bytes(len, _) }) = - &len.data(Interner).value - { - match (&**len).try_into() { - Ok(len) => { - let len = usize::from_le_bytes(len); - if len == 0 { - // Arrays of size 0 don't have drop glue. - return DropGlue::None; - } - } - Err(_) => { - never!("const array size with non-usize len"); - } - } + if consteval_nextsolver::try_const_usize(db, len) == Some(0) { + // Arrays of size 0 don't have drop glue. + return DropGlue::None; } - db.has_drop_glue(ty.clone(), env) + has_drop_glue_impl(infcx, ty, env, visited) } - TyKind::Slice(ty) => db.has_drop_glue(ty.clone(), env), + TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { - let closure_id = (*closure_id).into(); - let owner = db.lookup_intern_closure(closure_id).0; + let owner = db.lookup_intern_closure(closure_id.0).0; let infer = db.infer(owner); - let (captures, _) = infer.closure_info(closure_id); + let (captures, _) = infer.closure_info(closure_id.0); let env = db.trait_environment_for_body(owner); - let interner = DbInterner::conjure(); captures .iter() .map(|capture| { - db.has_drop_glue( - capture.ty(db, subst.to_nextsolver(interner)).to_chalk(interner), - env.clone(), - ) + has_drop_glue_impl(infcx, capture.ty(db, subst), env.clone(), visited) }) .max() .unwrap_or(DropGlue::None) } // FIXME: Handle coroutines. - TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) => DropGlue::None, + TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) | TyKind::CoroutineClosure(..) => { + DropGlue::None + } TyKind::Ref(..) - | TyKind::Raw(..) + | TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::Str | TyKind::Never - | TyKind::Scalar(_) - | TyKind::Function(_) + | TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::FnPtr(..) | TyKind::Foreign(_) - | TyKind::Error => DropGlue::None, - TyKind::Dyn(_) => DropGlue::HasDropGlue, - TyKind::AssociatedType(assoc_type_id, subst) => projection_has_drop_glue( - db, - env, - ProjectionTy { associated_ty_id: *assoc_type_id, substitution: subst.clone() }, - ty, - ), - TyKind::Alias(AliasTy::Projection(projection)) => { - projection_has_drop_glue(db, env, projection.clone(), ty) - } - TyKind::OpaqueType(..) | TyKind::Alias(AliasTy::Opaque(_)) => { - if is_copy(db, ty, env) { + | TyKind::Error(_) + | TyKind::Bound(..) + | TyKind::Placeholder(..) => DropGlue::None, + TyKind::Dynamic(..) => DropGlue::HasDropGlue, + TyKind::Alias(..) => { + if infcx.type_is_copy_modulo_regions(env.env, ty) { DropGlue::None } else { DropGlue::HasDropGlue } } - TyKind::Placeholder(_) | TyKind::BoundVar(_) => { - if is_copy(db, ty, env) { + TyKind::Param(_) => { + if infcx.type_is_copy_modulo_regions(env.env, ty) { DropGlue::None } else { DropGlue::DependOnParams } } - TyKind::InferenceVar(..) => unreachable!("inference vars shouldn't exist out of inference"), - } -} - -fn projection_has_drop_glue( - db: &dyn HirDatabase, - env: Arc>, - projection: ProjectionTy, - ty: Ty, -) -> DropGlue { - let normalized = db.normalize_projection(projection, env.clone()); - match normalized.kind(Interner) { - TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(..) => { - if is_copy(db, ty, env) { DropGlue::None } else { DropGlue::DependOnParams } + TyKind::Infer(..) => unreachable!("inference vars shouldn't exist out of inference"), + TyKind::Pat(..) | TyKind::UnsafeBinder(..) => { + never!("we do not handle pattern and unsafe binder types"); + DropGlue::None } - _ => db.has_drop_glue(normalized, env), } } - -fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc>) -> bool { - let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else { - return false; - }; - let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); - let goal = Canonical { - value: InEnvironment::new( - &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), - trait_ref.cast(Interner), - ), - binders: CanonicalVarKinds::empty(Interner), - }; - db.trait_solve(env.krate, env.block, goal).certain() -} - -pub(crate) fn has_drop_glue_cycle_result( - _db: &dyn HirDatabase, - _ty: Ty, - _env: Arc>, -) -> DropGlue { - DropGlue::None -} 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 2add66d02d235..4ff5cc5588bfe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -24,7 +24,6 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; mod builder; mod chalk_db; mod chalk_ext; -mod drop; mod infer; mod inhabitedness; mod interner; @@ -42,6 +41,7 @@ pub mod consteval_nextsolver; pub mod db; pub mod diagnostics; pub mod display; +pub mod drop; pub mod dyn_compatibility; pub mod generics; pub mod lang_items; @@ -94,7 +94,6 @@ use crate::{ pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; -pub use drop::DropGlue; pub use infer::{ Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, PointerCast, 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 e1983b37472ce..6e09cf9aeb882 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 @@ -32,7 +32,6 @@ use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, Interner, MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, @@ -44,8 +43,11 @@ use crate::{ layout::{Layout, LayoutError, RustcEnumVariantIdx}, method_resolution::{is_dyn_method, lookup_impl_const}, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, convert_args_for_result, convert_ty_for_result}, + DbInterner, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, + mapping::{ + ChalkToNextSolver, NextSolverToChalk, convert_args_for_result, convert_ty_for_result, + }, }, static_lifetime, traits::FnTrait, @@ -204,6 +206,7 @@ pub struct Evaluator<'a> { /// Maximum count of bytes that heap and stack can grow memory_limit: usize, interner: DbInterner<'a>, + infcx: InferCtxt<'a>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -690,6 +693,7 @@ impl<'db> Evaluator<'db> { x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once)) }), interner, + infcx: interner.infer_ctxt().build(TypingMode::non_body_analysis()), }) } 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 54d13a8d3d735..9ef0012a89c1c 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 @@ -16,8 +16,8 @@ use stdx::never; use crate::next_solver::mapping::NextSolverToChalk; use crate::{ - DropGlue, display::DisplayTarget, + drop::{DropGlue, has_drop_glue}, error_lifetime, mir::eval::{ Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay, @@ -855,7 +855,11 @@ impl<'db> Evaluator<'db> { "size_of generic arg is not provided".into(), )); }; - let result = match self.db.has_drop_glue(ty.clone(), self.trait_env.clone()) { + let result = match has_drop_glue( + &self.infcx, + ty.to_nextsolver(self.interner), + self.trait_env.clone(), + ) { DropGlue::HasDropGlue => true, DropGlue::None => false, DropGlue::DependOnParams => { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ae52986008f11..cce2564a9e6dd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -82,8 +82,8 @@ use hir_ty::{ method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - ClauseKind, DbInterner, GenericArgs, - infer::InferCtxt, + ClauseKind, DbInterner, GenericArgs, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, primitive::UintTy, @@ -157,10 +157,11 @@ pub use { tt, }, hir_ty::{ - CastError, DropGlue, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, + CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, + drop::DropGlue, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, method_resolution::TyFingerprint, @@ -6043,7 +6044,10 @@ impl<'db> Type<'db> { } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { - db.has_drop_glue(self.ty.clone(), self.env.clone()) + let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + // FIXME: This should be `PostAnalysis` I believe. + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + hir_ty::drop::has_drop_glue(&infcx, self.ty.to_nextsolver(interner), self.env.clone()) } } From fae6cdf0dbdd9d9d9710fbc1b0c902578c5e177f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 9 Oct 2025 09:45:42 +0800 Subject: [PATCH 44/59] Allow generic_param_list for `static` items --- .../crates/parser/src/grammar/items/consts.rs | 21 +++++---- .../parser/inline/err/generic_static.rast | 45 +++++++------------ 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs index 6b53493c9a36d..e6a8aca5861a6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs @@ -25,18 +25,17 @@ fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { } // FIXME: Recover on statics with generic params/where clause. - if is_const { - // test generic_const - // const C: u32 = 0; - // impl Foo { - // const C<'a>: &'a () = &(); - // } - generic_params::opt_generic_param_list(p); - } else if p.at(T![<]) { + if !is_const && p.at(T![<]) { + // test_err generic_static + // static C: u32 = 0; p.error("`static` may not have generic parameters"); } - // test_err generic_static - // static C: u32 = 0; + // test generic_const + // const C: u32 = 0; + // impl Foo { + // const C<'a>: &'a () = &(); + // } + generic_params::opt_generic_param_list(p); if p.at(T![:]) { types::ascription(p); @@ -44,7 +43,7 @@ fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { // test_err missing_const_type // const C = 0; p.error("missing type for `const`"); - } else if !p.at(T![<]) { + } else { // test_err missing_static_type // static C = 0; p.error("missing type for `static`"); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast index 0c240b7214f43..08017cb0fcd91 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast @@ -4,39 +4,24 @@ SOURCE_FILE WHITESPACE " " NAME IDENT "C" - ERROR - L_ANGLE "<" - ERROR - PATH - PATH_SEGMENT - NAME_REF + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME IDENT "i32" - ERROR - R_ANGLE ">" - ERROR + R_ANGLE ">" COLON ":" - WHITESPACE " " - ERROR - PATH - PATH_SEGMENT - NAME_REF - IDENT "u32" - WHITESPACE " " - ERROR + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + WHITESPACE " " EQ "=" - WHITESPACE " " - ERROR - INT_NUMBER "0" - ERROR + WHITESPACE " " + LITERAL + INT_NUMBER "0" SEMICOLON ";" WHITESPACE "\n" error 8: `static` may not have generic parameters -error 8: expected SEMICOLON -error 8: expected an item -error 12: expected an item -error 12: expected an item -error 13: expected an item -error 18: expected an item -error 19: expected an item -error 21: expected an item -error 22: expected an item From cd7736571418aae735adb60d1ca272c750121623 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 9 Oct 2025 11:43:29 +0800 Subject: [PATCH 45/59] Fix closure coerced return type for add_return_type Example --- ```rust fn foo() { let f = ||$0 {loop {}}; let _: fn() -> i8 = f; } ``` **Before this PR**: ```rust fn foo() { let f = || -> ! {loop {}}; let _: fn() -> i8 = f; } ``` mismatched types error on line 3 **After this PR**: ```rust fn foo() { let f = || -> i8 {loop {}}; let _: fn() -> i8 = f; } ``` --- .../ide-assists/src/handlers/add_return_type.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs index a7104ce068da8..c9022f66d1e20 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_return_type.rs @@ -18,7 +18,7 @@ use crate::{AssistContext, AssistId, Assists}; pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (fn_type, tail_expr, builder_edit_pos) = extract_tail(ctx)?; let module = ctx.sema.scope(tail_expr.syntax())?.module(); - let ty = ctx.sema.type_of_expr(&peel_blocks(tail_expr.clone()))?.original(); + let ty = ctx.sema.type_of_expr(&peel_blocks(tail_expr.clone()))?.adjusted(); if ty.is_unit() { return None; } @@ -421,6 +421,21 @@ mod tests { ); } + #[test] + fn infer_coerced_return_type_closure() { + check_assist( + add_return_type, + r#"fn foo() { + let f = ||$0 {loop {}}; + let _: fn() -> i8 = f; +}"#, + r#"fn foo() { + let f = || -> i8 {loop {}}; + let _: fn() -> i8 = f; +}"#, + ); + } + #[test] fn not_applicable_ret_type_specified_closure() { cov_mark::check!(existing_ret_type_closure); From 9a64aebd61df85e5c404025627b9222c6b43c070 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 9 Oct 2025 13:23:14 +0800 Subject: [PATCH 46/59] Fix not applicable on param in let-stmt for add_explicit_type Example --- ```rust fn f() { let f: fn(i32) = |y$0| {}; } ``` **Before this PR**: Assist not applicable **After this PR**: ```rust fn f() { let f: fn(i32) = |y: i32| {}; } ``` --- .../src/handlers/add_explicit_type.rs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs index 35a65cc309111..0dd01b67e8f47 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_type.rs @@ -1,3 +1,4 @@ +use either::Either; use hir::HirDisplay; use ide_db::syntax_helpers::node_ext::walk_ty; use syntax::ast::{self, AstNode, LetStmt, Param}; @@ -20,7 +21,8 @@ use crate::{AssistContext, AssistId, Assists}; // } // ``` pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let (ascribed_ty, expr, pat) = if let Some(let_stmt) = ctx.find_node_at_offset::() { + let syntax_node = ctx.find_node_at_offset::>()?; + let (ascribed_ty, expr, pat) = if let Either::Left(let_stmt) = syntax_node { let cursor_in_range = { let eq_range = let_stmt.eq_token()?.text_range(); ctx.offset() < eq_range.start() @@ -31,7 +33,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O } (let_stmt.ty(), let_stmt.initializer(), let_stmt.pat()?) - } else if let Some(param) = ctx.find_node_at_offset::() { + } else if let Either::Right(param) = syntax_node { if param.syntax().ancestors().nth(2).and_then(ast::ClosureExpr::cast).is_none() { cov_mark::hit!(add_explicit_type_not_applicable_in_fn_param); return None; @@ -298,6 +300,20 @@ fn f() { let x: i32 = y; }; } +"#, + ); + + check_assist( + add_explicit_type, + r#" +fn f() { + let f: fn(i32) = |y$0| {}; +} +"#, + r#" +fn f() { + let f: fn(i32) = |y: i32| {}; +} "#, ); } From c0d82ccbe9661bde5c3c23ed573403c74d459945 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 9 Oct 2025 20:04:39 +0800 Subject: [PATCH 47/59] minor: update typos checker version --- src/tools/rust-analyzer/.github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 0eb57a605f828..e3384c976bb24 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -293,7 +293,7 @@ jobs: timeout-minutes: 10 env: FORCE_COLOR: 1 - TYPOS_VERSION: v1.28.3 + TYPOS_VERSION: v1.38.1 steps: - name: download typos run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin From 56cf2f21cd51a2342abfaff74f8600f74e7a35c5 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 9 Oct 2025 20:07:24 +0800 Subject: [PATCH 48/59] minor: correct typos --- src/tools/rust-analyzer/.typos.toml | 1 + src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs | 2 +- .../rust-analyzer/crates/ide-assists/src/assist_config.rs | 2 +- .../crates/ide-assists/src/handlers/add_missing_match_arms.rs | 2 +- .../crates/ide-assists/src/handlers/convert_bool_to_enum.rs | 2 +- .../crates/ide-assists/src/handlers/convert_into_to_from.rs | 2 +- .../src/handlers/convert_tuple_return_type_to_struct.rs | 2 +- .../ide-assists/src/handlers/destructure_struct_binding.rs | 2 +- .../crates/ide-assists/src/handlers/extract_function.rs | 2 +- .../src/handlers/extract_struct_from_enum_variant.rs | 2 +- .../crates/ide-assists/src/handlers/generate_deref.rs | 4 ++-- .../crates/ide-assists/src/handlers/generate_new.rs | 2 +- .../src/handlers/generate_single_field_struct_from.rs | 2 +- .../crates/ide-assists/src/handlers/qualify_method_call.rs | 2 +- .../src/handlers/replace_derive_with_manual_impl.rs | 2 +- .../src/handlers/replace_qualified_name_with_use.rs | 2 +- .../crates/ide-assists/src/handlers/term_search.rs | 2 +- .../crates/ide-assists/src/handlers/toggle_async_sugar.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs | 2 +- 19 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml index cdbc003a80882..99464150dab47 100644 --- a/src/tools/rust-analyzer/.typos.toml +++ b/src/tools/rust-analyzer/.typos.toml @@ -32,6 +32,7 @@ makro = "makro" trivias = "trivias" thir = "thir" jod = "jod" +tructure = "tructure" [default.extend-identifiers] anc = "anc" 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 8a7d93d50c05b..b0986c423b116 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 @@ -39,7 +39,7 @@ pub fn target_data_layout_query( target, } => format!(r#"inconsistent target specification: "data-layout" claims pointers are {pointer_size}-bit, while "target-pointer-width" is `{target}`"#), TargetDataLayoutErrors::InvalidBitsSize { err } => err, - TargetDataLayoutErrors::UnknownPointerSpecification { err } => format!(r#"use of unknown pointer specifer in "data-layout": {err}"#), + TargetDataLayoutErrors::UnknownPointerSpecification { err } => format!(r#"use of unknown pointer specifier in "data-layout": {err}"#), }.into()) } }, 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 597d035ebd857..7d5070ace6190 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 @@ -38,7 +38,7 @@ impl AssistConfig { } } - pub fn find_path_confg(&self, allow_unstable: bool) -> FindPathConfig { + pub fn find_path_config(&self, allow_unstable: bool) -> FindPathConfig { FindPathConfig { prefer_no_std: self.prefer_no_std, prefer_prelude: self.prefer_prelude, 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 3910921fbe03a..8802a54e7f240 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 @@ -80,7 +80,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) 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 cfg = ctx.config.find_path_config(ctx.sema.is_nightly(scope.krate())); let self_ty = if ctx.config.prefer_self_ty { scope .containing_function() 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 80445578fcef9..2ad13362378ed 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 @@ -346,7 +346,7 @@ fn augment_references_with_imports( 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())); + ctx.config.find_path_config(ctx.sema.is_nightly(target_module.krate())); let path = ref_module .find_use_path( ctx.sema.db, 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 3a464a3dc6aae..8f02d28b82454 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.find_path_confg(ctx.sema.is_nightly(module.krate())); + let cfg = ctx.config.find_path_config(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 80ffb4db3e84d..9876e14203fe1 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 @@ -199,7 +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 cfg = ctx.config.find_path_config(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 27755db93c882..8b24d33bf9965 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 @@ -88,7 +88,7 @@ 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 cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); let mod_path = module.find_use_path( ctx.sema.db, ModuleDef::from(control_flow_enum), 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 20ebd8f09c73f..2cec3296c87e1 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,7 +400,7 @@ 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 cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); let mod_path = module.find_use_path( ctx.sema.db, *enum_module_def, 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 a1fc2c6023597..b02e3e435c814 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,7 +57,7 @@ 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 cfg = ctx.config.find_path_config(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_), cfg)?; @@ -99,7 +99,7 @@ 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 cfg = ctx.config.find_path_config(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_), cfg)?; 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 9760fd62aab4f..cd968b97105af 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,7 +77,7 @@ 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 cfg = ctx.config.find_path_config(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)?, 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 cad14d929648a..6c302a2a6fbdf 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,7 +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())); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); types .iter() .map(|ty| { 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 e4494f0492ece..d8dbefd59e28a 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,7 +45,7 @@ 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 cfg = ctx.config.find_path_config(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)?, 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 25c5593007bcb..2bf4406cc6a9c 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,7 +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 cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_crate)); let found_traits = items_locator::items_with_name( ctx.db(), 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 5fc4d7a6170de..f6526cdba4a9f 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 @@ -64,7 +64,7 @@ pub(crate) fn replace_qualified_name_with_use( let path_to_qualifier = starts_with_name_ref .then(|| { let mod_ = ctx.sema.scope(original_path.syntax())?.module(); - let cfg = ctx.config.find_path_confg(ctx.sema.is_nightly(mod_.krate())); + let cfg = ctx.config.find_path_config(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 209d3f08eb888..d64a76eb8b37a 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.find_path_confg(ctx.sema.is_nightly(scope.module().krate())), + ctx.config.find_path_config(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 aed66d3d8344c..fa6fca8150ac6 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,7 +132,7 @@ 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 cfg = ctx.config.find_path_config(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), cfg)?; let edition = scope.krate().edition(ctx.db()); 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 079dedda000c3..0da9ee097ac3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -116,7 +116,7 @@ pub struct HighlightConfig { // |arithmetic| Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.| // |bitwise| Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.| // |comparison| Emitted for the comparison oerators `>`, `<`, `==`, `>=`, `<=`, `!=`.| -// |logical| Emitted for the logical operatos `||`, `&&`, `!`.| +// |logical| Emitted for the logical operators `||`, `&&`, `!`.| // // - For punctuation: // From 45ca9b5a4c989b6d0d31eb737cc939d2a6ca9cad Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 7 Oct 2025 09:46:40 +0800 Subject: [PATCH 49/59] Fix empty closure completion analysis Example --- ```rust fn foo() { bar(|| $0); } fn bar(f: impl FnOnce() -> u32) {} ``` **Before this PR**: ``` ty: impl FnOnce() -> u32, name: ? ``` **After this PR**: ``` ty: u32, name: ? ``` --- .../crates/ide-completion/src/context/analysis.rs | 15 ++++++++++++--- .../crates/ide-completion/src/context/tests.rs | 13 ++++++++++++- 2 files changed, 24 insertions(+), 4 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 6cd098462f4db..0b8ba808e53bb 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,10 +562,10 @@ fn analyze<'db>( /// Calculate the expected type and name of the cursor position. fn expected_type_and_name<'db>( sema: &Semantics<'db, RootDatabase>, - token: &SyntaxToken, + self_token: &SyntaxToken, name_like: &ast::NameLike, ) -> (Option>, Option) { - let token = prev_special_biased_token_at_trivia(token.clone()); + let token = prev_special_biased_token_at_trivia(self_token.clone()); let mut node = match token.parent() { Some(it) => it, None => return (None, None), @@ -755,7 +755,15 @@ fn expected_type_and_name<'db>( .map(|c| (Some(c.return_type()), None)) .unwrap_or((None, None)) }, - ast::ParamList(_) => (None, None), + ast::ParamList(it) => { + let closure = it.syntax().parent().and_then(ast::ClosureExpr::cast); + let ty = closure + .filter(|_| it.syntax().text_range().end() <= self_token.text_range().start()) + .and_then(|it| sema.type_of_expr(&it.into())); + ty.and_then(|ty| ty.original.as_callable(sema.db)) + .map(|c| (Some(c.return_type()), None)) + .unwrap_or((None, None)) + }, ast::Stmt(_) => (None, None), ast::Item(_) => (None, None), _ => { @@ -1940,6 +1948,7 @@ fn prev_special_biased_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken { | T![|=] | T![&=] | T![^=] + | T![|] | T![return] | T![break] | T![continue] = prev.kind() 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 24647ab6279dc..e798f3b23af4c 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 @@ -373,7 +373,6 @@ fn foo() -> u32 { #[test] fn expected_type_closure_param_return() { - // FIXME: make this work with `|| $0` check_expected_type_and_name( r#" //- minicore: fn @@ -381,6 +380,18 @@ fn foo() { bar(|| a$0); } +fn bar(f: impl FnOnce() -> u32) {} +"#, + expect![[r#"ty: u32, name: ?"#]], + ); + + check_expected_type_and_name( + r#" +//- minicore: fn +fn foo() { + bar(|| $0); +} + fn bar(f: impl FnOnce() -> u32) {} "#, expect![[r#"ty: u32, name: ?"#]], From ddf8dd7875f9d94d7ce49f7ca87ec3cecaef6200 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 3 Oct 2025 17:03:00 +0800 Subject: [PATCH 50/59] Fix not applicable c-str and byte-str for raw_string Example --- Assist: `make_raw_string` ```rust fn f() { let s = $0b"random\nstring"; } ``` -> ```rust fn f() { let s = br#"random string"#; } ``` --- Assist: `make_raw_string` ```rust fn f() { let s = $0c"random\nstring"; } ``` -> ```rust fn f() { let s = cr#"random string"#; } ``` --- Assist: `add_hash` ```rust fn f() { let s = $0cr"random string"; } ``` -> ```rust fn f() { let s = cr#"random string"#; } ``` --- Assist: `remove_hash` ```rust fn f() { let s = $0cr#"random string"#; } ``` -> ```rust fn f() { let s = cr"random string"; } ``` --- Assist: `make_usual_string` ```rust fn f() { let s = $0cr#"random string"#; } ``` -> ```rust fn f() { let s = c"random string"; } ``` --- .../ide-assists/src/handlers/raw_string.rs | 116 +++++++++++++++--- .../crates/ide-assists/src/utils.rs | 15 +++ .../rust-analyzer/crates/syntax/src/ast.rs | 4 +- .../crates/syntax/src/ast/token_ext.rs | 94 ++++++++++++-- 4 files changed, 202 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs index 2cbb24a64fd5a..ca6d88870cced 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs @@ -4,7 +4,7 @@ use syntax::{AstToken, TextRange, TextSize, ast, ast::IsString}; use crate::{ AssistContext, AssistId, Assists, - utils::{required_hashes, string_suffix}, + utils::{required_hashes, string_prefix, string_suffix}, }; // Assist: make_raw_string @@ -23,8 +23,7 @@ use crate::{ // } // ``` pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - // FIXME: This should support byte and c strings as well. - let token = ctx.find_token_at_offset::()?; + let token = ctx.find_token_at_offset::()?; if token.is_raw() { return None; } @@ -37,14 +36,15 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt |edit| { let hashes = "#".repeat(required_hashes(&value).max(1)); let range = token.syntax().text_range(); + let raw_prefix = token.raw_prefix(); let suffix = string_suffix(token.text()).unwrap_or_default(); let range = TextRange::new(range.start(), range.end() - TextSize::of(suffix)); if matches!(value, Cow::Borrowed(_)) { // Avoid replacing the whole string to better position the cursor. - edit.insert(range.start(), format!("r{hashes}")); + edit.insert(range.start(), format!("{raw_prefix}{hashes}")); edit.insert(range.end(), hashes); } else { - edit.replace(range, format!("r{hashes}\"{value}\"{hashes}")); + edit.replace(range, format!("{raw_prefix}{hashes}\"{value}\"{hashes}")); } }, ) @@ -66,7 +66,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt // } // ``` pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let token = ctx.find_token_at_offset::()?; + let token = ctx.find_token_at_offset::()?; if !token.is_raw() { return None; } @@ -80,18 +80,22 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O // parse inside string to escape `"` let escaped = value.escape_default().to_string(); let suffix = string_suffix(token.text()).unwrap_or_default(); + let prefix = string_prefix(token.text()).map_or("", |s| s.trim_end_matches('r')); if let Some(offsets) = token.quote_offsets() && token.text()[offsets.contents - token.syntax().text_range().start()] == escaped { + let start_quote = offsets.quotes.0; + let start_quote = + TextRange::new(start_quote.start() + TextSize::of(prefix), start_quote.end()); let end_quote = offsets.quotes.1; let end_quote = TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix)); - edit.replace(offsets.quotes.0, "\""); edit.replace(end_quote, "\""); + edit.replace(start_quote, "\""); return; } - edit.replace(token.syntax().text_range(), format!("\"{escaped}\"{suffix}")); + edit.replace(token.syntax().text_range(), format!("{prefix}\"{escaped}\"{suffix}")); }, ) } @@ -112,7 +116,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O // } // ``` pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let token = ctx.find_token_at_offset::()?; + let token = ctx.find_token_at_offset::()?; if !token.is_raw() { return None; } @@ -120,7 +124,7 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> let target = text_range; acc.add(AssistId::refactor("add_hash"), "Add #", target, |edit| { let suffix = string_suffix(token.text()).unwrap_or_default(); - edit.insert(text_range.start() + TextSize::of('r'), "#"); + edit.insert(text_range.start() + TextSize::of(token.raw_prefix()), "#"); edit.insert(text_range.end() - TextSize::of(suffix), "#"); }) } @@ -141,17 +145,15 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> // } // ``` pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let token = ctx.find_token_at_offset::()?; + let token = ctx.find_token_at_offset::()?; if !token.is_raw() { return None; } let text = token.text(); - if !text.starts_with("r#") && text.ends_with('#') { - return None; - } - let existing_hashes = text.chars().skip(1).take_while(|&it| it == '#').count(); + let existing_hashes = + text.chars().skip(token.raw_prefix().len()).take_while(|&it| it == '#').count(); let text_range = token.syntax().text_range(); let internal_text = &text[token.text_range_between_quotes()? - text_range.start()]; @@ -163,7 +165,10 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< acc.add(AssistId::refactor_rewrite("remove_hash"), "Remove #", text_range, |edit| { let suffix = string_suffix(text).unwrap_or_default(); - edit.delete(TextRange::at(text_range.start() + TextSize::of('r'), TextSize::of('#'))); + edit.delete(TextRange::at( + text_range.start() + TextSize::of(token.raw_prefix()), + TextSize::of('#'), + )); edit.delete( TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()) - TextSize::of(suffix), @@ -224,6 +229,42 @@ string"#; ) } + #[test] + fn make_raw_byte_string_works() { + check_assist( + make_raw_string, + r#" +fn f() { + let s = $0b"random\nstring"; +} +"#, + r##" +fn f() { + let s = br#"random +string"#; +} +"##, + ) + } + + #[test] + fn make_raw_c_string_works() { + check_assist( + make_raw_string, + r#" +fn f() { + let s = $0c"random\nstring"; +} +"#, + r##" +fn f() { + let s = cr#"random +string"#; +} +"##, + ) + } + #[test] fn make_raw_string_hashes_inside_works() { check_assist( @@ -348,6 +389,23 @@ string"###; ) } + #[test] + fn add_hash_works_for_c_str() { + check_assist( + add_hash, + r#" + fn f() { + let s = $0cr"random string"; + } + "#, + r##" + fn f() { + let s = cr#"random string"#; + } + "##, + ) + } + #[test] fn add_hash_has_suffix_works() { check_assist( @@ -433,6 +491,15 @@ string"###; ) } + #[test] + fn remove_hash_works_for_c_str() { + check_assist( + remove_hash, + r##"fn f() { let s = $0cr#"random string"#; }"##, + r#"fn f() { let s = cr"random string"; }"#, + ) + } + #[test] fn remove_hash_has_suffix_works() { check_assist( @@ -529,6 +596,23 @@ string"###; ) } + #[test] + fn make_usual_string_for_c_str() { + check_assist( + make_usual_string, + r##" + fn f() { + let s = $0cr#"random string"#; + } + "##, + r#" + fn f() { + let s = c"random string"; + } + "#, + ) + } + #[test] fn make_usual_string_has_suffix_works() { check_assist( 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 20e0302b57d70..6ed4467aa359b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1057,6 +1057,21 @@ fn test_string_suffix() { assert_eq!(Some("i32"), string_suffix(r##"r#""#i32"##)); } +/// Calculate the string literal prefix length +pub(crate) fn string_prefix(s: &str) -> Option<&str> { + s.split_once(['"', '\'', '#']).map(|(prefix, _)| prefix) +} +#[test] +fn test_string_prefix() { + assert_eq!(Some(""), string_prefix(r#""abc""#)); + assert_eq!(Some(""), string_prefix(r#""""#)); + assert_eq!(Some(""), string_prefix(r#"""suffix"#)); + assert_eq!(Some("c"), string_prefix(r#"c"""#)); + assert_eq!(Some("r"), string_prefix(r#"r"""#)); + assert_eq!(Some("cr"), string_prefix(r#"cr"""#)); + assert_eq!(Some("r"), string_prefix(r##"r#""#"##)); +} + /// Replaces the record expression, handling field shorthands including inside macros. pub(crate) fn replace_record_field_expr( ctx: &AssistContext<'_>, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index 19c1c5ebea333..aea99a4389b9b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -29,7 +29,9 @@ pub use self::{ SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind, }, operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, - token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix}, + token_ext::{ + AnyString, CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix, + }, traits::{ AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index 4afdda78a0e70..d9223e8216da3 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -151,10 +151,10 @@ impl QuoteOffsets { } pub trait IsString: AstToken { - const RAW_PREFIX: &'static str; - fn unescape(s: &str, callback: impl FnMut(Range, Result)); + fn raw_prefix(&self) -> &'static str; + fn unescape(&self, s: &str, callback: impl FnMut(Range, Result)); fn is_raw(&self) -> bool { - self.text().starts_with(Self::RAW_PREFIX) + self.text().starts_with(self.raw_prefix()) } fn quote_offsets(&self) -> Option { let text = self.text(); @@ -187,7 +187,7 @@ pub trait IsString: AstToken { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - Self::unescape(text, &mut |range: Range, unescaped_char| { + self.unescape(text, &mut |range: Range, unescaped_char| { if let Some((s, e)) = range.start.try_into().ok().zip(range.end.try_into().ok()) { cb(TextRange::new(s, e) + offset, unescaped_char); } @@ -204,8 +204,10 @@ pub trait IsString: AstToken { } impl IsString for ast::String { - const RAW_PREFIX: &'static str = "r"; - fn unescape(s: &str, cb: impl FnMut(Range, Result)) { + fn raw_prefix(&self) -> &'static str { + "r" + } + fn unescape(&self, s: &str, cb: impl FnMut(Range, Result)) { unescape_str(s, cb) } } @@ -246,8 +248,10 @@ impl ast::String { } impl IsString for ast::ByteString { - const RAW_PREFIX: &'static str = "br"; - fn unescape(s: &str, mut callback: impl FnMut(Range, Result)) { + fn raw_prefix(&self) -> &'static str { + "br" + } + fn unescape(&self, s: &str, mut callback: impl FnMut(Range, Result)) { unescape_byte_str(s, |range, res| callback(range, res.map(char::from))) } } @@ -288,10 +292,12 @@ impl ast::ByteString { } impl IsString for ast::CString { - const RAW_PREFIX: &'static str = "cr"; + fn raw_prefix(&self) -> &'static str { + "cr" + } // NOTE: This method should only be used for highlighting ranges. The unescaped // char/byte is not used. For simplicity, we return an arbitrary placeholder char. - fn unescape(s: &str, mut callback: impl FnMut(Range, Result)) { + fn unescape(&self, s: &str, mut callback: impl FnMut(Range, Result)) { unescape_c_str(s, |range, _res| callback(range, Ok('_'))) } } @@ -465,6 +471,74 @@ impl ast::Byte { } } +pub enum AnyString { + ByteString(ast::ByteString), + CString(ast::CString), + String(ast::String), +} + +impl AnyString { + pub fn value(&self) -> Result, EscapeError> { + fn from_utf8(s: Cow<'_, [u8]>) -> Result, EscapeError> { + match s { + Cow::Borrowed(s) => str::from_utf8(s) + .map_err(|_| EscapeError::NonAsciiCharInByte) + .map(Cow::Borrowed), + Cow::Owned(s) => String::from_utf8(s) + .map_err(|_| EscapeError::NonAsciiCharInByte) + .map(Cow::Owned), + } + } + + match self { + AnyString::String(s) => s.value(), + AnyString::ByteString(s) => s.value().and_then(from_utf8), + AnyString::CString(s) => s.value().and_then(from_utf8), + } + } +} + +impl ast::AstToken for AnyString { + fn can_cast(kind: crate::SyntaxKind) -> bool { + ast::String::can_cast(kind) + || ast::ByteString::can_cast(kind) + || ast::CString::can_cast(kind) + } + + fn cast(syntax: crate::SyntaxToken) -> Option { + ast::String::cast(syntax.clone()) + .map(Self::String) + .or_else(|| ast::ByteString::cast(syntax.clone()).map(Self::ByteString)) + .or_else(|| ast::CString::cast(syntax).map(Self::CString)) + } + + fn syntax(&self) -> &crate::SyntaxToken { + match self { + Self::ByteString(it) => it.syntax(), + Self::CString(it) => it.syntax(), + Self::String(it) => it.syntax(), + } + } +} + +impl IsString for AnyString { + fn raw_prefix(&self) -> &'static str { + match self { + AnyString::ByteString(s) => s.raw_prefix(), + AnyString::CString(s) => s.raw_prefix(), + AnyString::String(s) => s.raw_prefix(), + } + } + + fn unescape(&self, s: &str, callback: impl FnMut(Range, Result)) { + match self { + AnyString::ByteString(it) => it.unescape(s, callback), + AnyString::CString(it) => it.unescape(s, callback), + AnyString::String(it) => it.unescape(s, callback), + } + } +} + #[cfg(test)] mod tests { use rustc_apfloat::ieee::Quad as f128; From d1ecdca22f67c97f354dab6b9e66022ecb4b506e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 10 Oct 2025 19:00:30 +0800 Subject: [PATCH 51/59] Migrate `raw_string` assist to use `SyntaxEditor` --- .../ide-assists/src/handlers/raw_string.rs | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs index ca6d88870cced..d6d99b8b6d9dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs @@ -1,6 +1,8 @@ -use std::borrow::Cow; - -use syntax::{AstToken, TextRange, TextSize, ast, ast::IsString}; +use ide_db::source_change::SourceChangeBuilder; +use syntax::{ + AstToken, + ast::{self, IsString, make::tokens::literal}, +}; use crate::{ AssistContext, AssistId, Assists, @@ -35,17 +37,10 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt target, |edit| { let hashes = "#".repeat(required_hashes(&value).max(1)); - let range = token.syntax().text_range(); let raw_prefix = token.raw_prefix(); let suffix = string_suffix(token.text()).unwrap_or_default(); - let range = TextRange::new(range.start(), range.end() - TextSize::of(suffix)); - if matches!(value, Cow::Borrowed(_)) { - // Avoid replacing the whole string to better position the cursor. - edit.insert(range.start(), format!("{raw_prefix}{hashes}")); - edit.insert(range.end(), hashes); - } else { - edit.replace(range, format!("{raw_prefix}{hashes}\"{value}\"{hashes}")); - } + let new_str = format!("{raw_prefix}{hashes}\"{value}\"{hashes}{suffix}"); + replace_literal(&token, &new_str, edit, ctx); }, ) } @@ -81,21 +76,8 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let escaped = value.escape_default().to_string(); let suffix = string_suffix(token.text()).unwrap_or_default(); let prefix = string_prefix(token.text()).map_or("", |s| s.trim_end_matches('r')); - if let Some(offsets) = token.quote_offsets() - && token.text()[offsets.contents - token.syntax().text_range().start()] == escaped - { - let start_quote = offsets.quotes.0; - let start_quote = - TextRange::new(start_quote.start() + TextSize::of(prefix), start_quote.end()); - let end_quote = offsets.quotes.1; - let end_quote = - TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix)); - edit.replace(end_quote, "\""); - edit.replace(start_quote, "\""); - return; - } - - edit.replace(token.syntax().text_range(), format!("{prefix}\"{escaped}\"{suffix}")); + let new_str = format!("{prefix}\"{escaped}\"{suffix}"); + replace_literal(&token, &new_str, edit, ctx); }, ) } @@ -120,12 +102,14 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> if !token.is_raw() { return None; } - let text_range = token.syntax().text_range(); - let target = text_range; + let target = token.syntax().text_range(); acc.add(AssistId::refactor("add_hash"), "Add #", target, |edit| { - let suffix = string_suffix(token.text()).unwrap_or_default(); - edit.insert(text_range.start() + TextSize::of(token.raw_prefix()), "#"); - edit.insert(text_range.end() - TextSize::of(suffix), "#"); + let str = token.text(); + let suffix = string_suffix(str).unwrap_or_default(); + let raw_prefix = token.raw_prefix(); + let wrap_range = raw_prefix.len()..str.len() - suffix.len(); + let new_str = [raw_prefix, "#", &str[wrap_range], "#", suffix].concat(); + replace_literal(&token, &new_str, edit, ctx); }) } @@ -165,17 +149,38 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< acc.add(AssistId::refactor_rewrite("remove_hash"), "Remove #", text_range, |edit| { let suffix = string_suffix(text).unwrap_or_default(); - edit.delete(TextRange::at( - text_range.start() + TextSize::of(token.raw_prefix()), - TextSize::of('#'), - )); - edit.delete( - TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()) - - TextSize::of(suffix), - ); + let prefix = token.raw_prefix(); + let wrap_range = prefix.len() + 1..text.len() - suffix.len() - 1; + let new_str = [prefix, &text[wrap_range], suffix].concat(); + replace_literal(&token, &new_str, edit, ctx); }) } +fn replace_literal( + token: &impl AstToken, + new: &str, + builder: &mut SourceChangeBuilder, + ctx: &AssistContext<'_>, +) { + let token = token.syntax(); + let node = token.parent().expect("no parent token"); + let mut edit = builder.make_editor(&node); + let new_literal = literal(new); + + edit.replace(token, mut_token(new_literal)); + + builder.add_file_edits(ctx.vfs_file_id(), edit); +} + +fn mut_token(token: syntax::SyntaxToken) -> syntax::SyntaxToken { + let node = token.parent().expect("no parent token"); + node.clone_for_update() + .children_with_tokens() + .filter_map(|it| it.into_token()) + .find(|it| it.text_range() == token.text_range() && it.text() == token.text()) + .unwrap() +} + #[cfg(test)] mod tests { use super::*; From 35142a6ab8ca9178e189a826dc829e2a6c650098 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 8 Oct 2025 16:02:42 +0300 Subject: [PATCH 52/59] Migrate MIR to next solver --- src/tools/rust-analyzer/Cargo.lock | 11 + src/tools/rust-analyzer/Cargo.toml | 1 + .../crates/hir-def/src/signatures.rs | 14 + .../rust-analyzer/crates/hir-ty/Cargo.toml | 1 + .../crates/hir-ty/src/builder.rs | 15 +- .../crates/hir-ty/src/consteval.rs | 396 ++++---- .../crates/hir-ty/src/consteval/tests.rs | 33 +- .../crates/hir-ty/src/consteval_chalk.rs | 185 ++++ .../crates/hir-ty/src/consteval_nextsolver.rs | 250 ----- .../rust-analyzer/crates/hir-ty/src/db.rs | 30 +- .../crates/hir-ty/src/display.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 4 +- .../hir-ty/src/infer/closure/analysis.rs | 41 +- .../crates/hir-ty/src/infer/expr.rs | 10 +- .../crates/hir-ty/src/infer/pat.rs | 8 +- .../crates/hir-ty/src/infer/path.rs | 4 +- .../crates/hir-ty/src/inhabitedness.rs | 15 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 18 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- .../crates/hir-ty/src/lower/path.rs | 2 +- .../crates/hir-ty/src/lower_nextsolver.rs | 2 +- .../hir-ty/src/lower_nextsolver/path.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 124 +-- .../rust-analyzer/crates/hir-ty/src/mir.rs | 393 ++++---- .../crates/hir-ty/src/mir/borrowck.rs | 191 ++-- .../crates/hir-ty/src/mir/eval.rs | 922 ++++++++---------- .../crates/hir-ty/src/mir/eval/shim.rs | 301 +++--- .../crates/hir-ty/src/mir/eval/shim/simd.rs | 39 +- .../crates/hir-ty/src/mir/eval/tests.rs | 21 +- .../crates/hir-ty/src/mir/lower.rs | 543 ++++++----- .../crates/hir-ty/src/mir/lower/as_place.rs | 120 +-- .../hir-ty/src/mir/lower/pattern_matching.rs | 160 ++- .../crates/hir-ty/src/mir/lower/tests.rs | 21 +- .../crates/hir-ty/src/mir/monomorphization.rs | 302 ++---- .../crates/hir-ty/src/mir/pretty.rs | 66 +- .../crates/hir-ty/src/next_solver/consts.rs | 82 +- .../crates/hir-ty/src/next_solver/def_id.rs | 14 +- .../hir-ty/src/next_solver/generic_arg.rs | 75 +- .../hir-ty/src/next_solver/infer/select.rs | 7 +- .../hir-ty/src/next_solver/infer/traits.rs | 38 +- .../crates/hir-ty/src/next_solver/interner.rs | 126 ++- .../crates/hir-ty/src/next_solver/mapping.rs | 8 +- .../hir-ty/src/next_solver/predicate.rs | 25 +- .../crates/hir-ty/src/next_solver/solver.rs | 65 +- .../crates/hir-ty/src/next_solver/ty.rs | 35 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 22 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 33 +- .../crates/hir/src/source_analyzer.rs | 13 +- .../crates/ide/src/hover/tests.rs | 10 +- .../ide/src/inlay_hints/implicit_drop.rs | 4 +- .../rust-analyzer/crates/macros/Cargo.toml | 19 + .../rust-analyzer/crates/macros/src/lib.rs | 164 ++++ 53 files changed, 2493 insertions(+), 2504 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs delete mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs create mode 100644 src/tools/rust-analyzer/crates/macros/Cargo.toml create mode 100644 src/tools/rust-analyzer/crates/macros/src/lib.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 8e2c371bceaa5..6625403572b0b 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -788,6 +788,7 @@ dependencies = [ "intern", "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "macros", "oorandom", "petgraph", "project-model", @@ -1329,6 +1330,16 @@ dependencies = [ "url", ] +[[package]] +name = "macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "mbe" version = "0.0.0" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 1438d4638922a..6702bfed872c9 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -52,6 +52,7 @@ debug = 2 [workspace.dependencies] # local crates +macros = { path = "./crates/macros", version = "0.0.0" } base-db = { path = "./crates/base-db", version = "0.0.0" } cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] } hir = { path = "./crates/hir", version = "0.0.0" } 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 47638610ed734..ebbf87cad668b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -349,6 +349,7 @@ bitflags::bitflags! { #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] pub struct ImplFlags: u8 { const NEGATIVE = 1 << 1; + const DEFAULT = 1 << 2; const UNSAFE = 1 << 3; } } @@ -374,6 +375,9 @@ impl ImplSignature { if src.value.excl_token().is_some() { flags.insert(ImplFlags::NEGATIVE); } + if src.value.default_token().is_some() { + flags.insert(ImplFlags::DEFAULT); + } let (store, source_map, self_ty, target_trait, generic_params) = crate::expr_store::lower::lower_impl(db, loc.container, src, id); @@ -389,6 +393,16 @@ impl ImplSignature { Arc::new(source_map), ) } + + #[inline] + pub fn is_negative(&self) -> bool { + self.flags.contains(ImplFlags::NEGATIVE) + } + + #[inline] + pub fn is_default(&self) -> bool { + self.flags.contains(ImplFlags::DEFAULT) + } } bitflags::bitflags! { diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 4013d19ad08eb..ec6563315407a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -50,6 +50,7 @@ tracing-tree.workspace = true # local deps stdx.workspace = true +macros.workspace = true intern.workspace = true hir-def.workspace = true hir-expand.workspace = true 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 798b0f2c0c246..706bbe856c67d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -130,11 +130,14 @@ impl TyBuilder { } pub fn fill_with_unknown(self) -> Self { + let interner = DbInterner::conjure(); // self.fill is inlined to make borrow checker happy let mut this = self; let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x { ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), + ParamKind::Const(ty) => { + unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner) + } ParamKind::Lifetime => error_lifetime().cast(Interner), }); this.vec.extend(filler.casted(Interner)); @@ -219,13 +222,16 @@ impl TyBuilder<()> { } pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into) -> Substitution { + let interner = DbInterner::conjure(); let params = generics(db, def.into()); Substitution::from_iter( Interner, params.iter_id().map(|id| match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => { - unknown_const_as_generic(db.const_param_ty(id)).cast(Interner) + unknown_const_as_generic(db.const_param_ty_ns(id)) + .to_chalk(interner) + .cast(Interner) } GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }), @@ -267,6 +273,7 @@ impl TyBuilder { db: &dyn HirDatabase, mut fallback: impl FnMut() -> Ty, ) -> Self { + let interner = DbInterner::conjure(); // Note that we're building ADT, so we never have parent generic parameters. let defaults = db.generic_defaults(self.data.into()); @@ -287,7 +294,9 @@ impl TyBuilder { // The defaults may be missing if no param has default, so fill that. let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x { ParamKind::Type => fallback().cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), + ParamKind::Const(ty) => { + unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner) + } ParamKind::Lifetime => error_lifetime().cast(Interner), }); self.vec.extend(filler.casted(Interner)); 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 8b12c5fd890c1..002e0823b9d17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -1,59 +1,88 @@ //! Constant evaluation details +#[cfg(test)] +mod tests; + use base_db::Crate; -use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast}; use hir_def::{ - EnumVariantId, GeneralConstId, HasModule as _, StaticId, - expr_store::{HygieneId, path::Path}, - hir::Expr, + EnumVariantId, GeneralConstId, + expr_store::{Body, HygieneId, path::Path}, + hir::{Expr, ExprId}, resolver::{Resolver, ValueNs}, type_ref::LiteralConstRef, }; +use hir_def::{HasModule, StaticId}; use hir_expand::Lookup; +use rustc_type_ir::{UnevaluatedConst, inherent::IntoKind}; use stdx::never; use triomphe::Arc; use crate::{ - Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, + MemoryMap, TraitEnvironment, db::HirDatabase, display::DisplayTarget, generics::Generics, - lower::ParamLoweringMode, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, - to_placeholder_idx, + infer::InferenceContext, + mir::{MirEvalError, MirLowerError}, + next_solver::{ + Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + ParamConst, SolverDefId, Ty, ValueConst, + }, }; -use super::mir::{MirEvalError, MirLowerError, interpret_mir, pad16}; - -/// Extension trait for [`Const`] -pub trait ConstExt { - /// Is a [`Const`] unknown? - fn is_unknown(&self) -> bool; -} +use super::mir::{interpret_mir, lower_to_mir, pad16}; -impl ConstExt for Const { - fn is_unknown(&self) -> bool { - match self.data(Interner).value { - // interned Unknown - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Unknown, - }) => true, - - // interned concrete anything else - chalk_ir::ConstValue::Concrete(..) => false, - - _ => { - tracing::error!( - "is_unknown was called on a non-concrete constant value! {:?}", - self - ); - true +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, id: p })) + } + 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() +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstEvalError<'db> { MirLowerError(MirLowerError<'db>), @@ -94,149 +123,189 @@ impl<'db> From> for ConstEvalError<'db> { } } -pub(crate) fn path_to_const<'g>( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - path: &Path, - mode: ParamLoweringMode, - args: impl FnOnce() -> &'g Generics, - debruijn: DebruijnIndex, - expected_ty: Ty, -) -> Option { - 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 => { - let idx = args.type_or_const_param_idx(p.into()).unwrap(); - ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32)) - } - 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)) - } - Some(ValueNs::ConstId(c)) => Some(intern_const_scalar( - ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)), - expected_ty, - )), - // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors. - _ => None, - } -} - -pub fn unknown_const(ty: Ty) -> Const { - ConstData { - ty, - value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }), - } - .intern(Interner) -} - -pub fn unknown_const_as_generic(ty: Ty) -> GenericArg { - unknown_const(ty).cast(Interner) -} - -/// Interns a constant scalar with the given type -pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { - ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) } - .intern(Interner) -} - /// Interns a constant scalar with the given type -pub fn intern_const_ref( - db: &dyn HirDatabase, +pub fn intern_const_ref<'a>( + db: &'a dyn HirDatabase, value: &LiteralConstRef, - ty: Ty, + ty: Ty<'a>, krate: Crate, -) -> Const { +) -> Const<'a> { 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 { + 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. - let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: i.to_le_bytes()[0..size].into(), + memory_map: MemoryMap::default(), + }, + )) } LiteralConstRef::UInt(i) => { - let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) - } - LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()), - LiteralConstRef::Char(c) => { - ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default()) + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: i.to_le_bytes()[0..size].into(), + memory_map: MemoryMap::default(), + }, + )) } - LiteralConstRef::Unknown => ConstScalar::Unknown, + LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() }, + )), + LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: (*c as u32).to_le_bytes().into(), + memory_map: MemoryMap::default(), + }, + )), + LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), }; - intern_const_scalar(bytes, ty) + Const::new(interner, kind) } /// Interns a possibly-unknown target usize -pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: Crate) -> Const { +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), - TyBuilder::usize(), + Ty::new_uint(DbInterner::new_with(db, Some(krate), None), rustc_type_ir::UintTy::Usize), krate, ) } -pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { - match &c.data(Interner).value { - chalk_ir::ConstValue::BoundVar(_) => None, - chalk_ir::ConstValue::InferenceVar(_) => None, - chalk_ir::ConstValue::Placeholder(_) => None, - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(it, false))), - ConstScalar::UnevaluatedConst(c, subst) => { - let ec = db.const_eval(*c, subst.clone(), None).ok()?; - try_const_usize(db, &ec) - } - _ => None, - }, +pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { + 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 = unevaluated_const.args; + let ec = db.const_eval(c, subst, None).ok()?; + try_const_usize(db, ec) + } + ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))), + ConstKind::Error(_) => None, + ConstKind::Expr(_) => None, } } -pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option { - match &c.data(Interner).value { - chalk_ir::ConstValue::BoundVar(_) => None, - chalk_ir::ConstValue::InferenceVar(_) => None, - chalk_ir::ConstValue::Placeholder(_) => None, - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))), - ConstScalar::UnevaluatedConst(c, subst) => { - let ec = db.const_eval(*c, subst.clone(), None).ok()?; - try_const_isize(db, &ec) +pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option { + 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 = unevaluated_const.args; + let ec = db.const_eval(c, subst, None).ok()?; + try_const_isize(db, &ec) + } + ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))), + ConstKind::Error(_) => None, + ConstKind::Expr(_) => None, + } +} + +pub(crate) fn const_eval_discriminant_variant<'db>( + db: &'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, + )? } - _ => None, - }, + _ => 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, + GenericArgs::new_from_iter(interner, []), + db.trait_environment_for_body(def), + )?; + let c = interpret_mir(db, mir_body, false, None)?.0?; + 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 infer = ctx.fixme_resolve_all_clone(); + 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]); + } + 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]) { + 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; + } + unknown_const(infer[expr]) } pub(crate) fn const_eval_cycle_result<'db>( _: &'db dyn HirDatabase, _: GeneralConstId, - _: Substitution, + _: GenericArgs<'db>, _: Option>>, -) -> Result> { +) -> Result, ConstEvalError<'db>> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } pub(crate) fn const_eval_static_cycle_result<'db>( _: &'db dyn HirDatabase, _: StaticId, -) -> Result> { +) -> Result, ConstEvalError<'db>> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -250,9 +319,9 @@ pub(crate) fn const_eval_discriminant_cycle_result<'db>( pub(crate) fn const_eval_query<'db>( db: &'db dyn HirDatabase, def: GeneralConstId, - subst: Substitution, + subst: GenericArgs<'db>, trait_env: Option>>, -) -> Result> { +) -> Result, ConstEvalError<'db>> { let body = match def { GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? @@ -269,52 +338,13 @@ pub(crate) fn const_eval_query<'db>( pub(crate) fn const_eval_static_query<'db>( db: &'db dyn HirDatabase, def: StaticId, -) -> Result> { +) -> Result, ConstEvalError<'db>> { + let interner = DbInterner::new_with(db, None, None); let body = db.monomorphized_mir_body( def.into(), - Substitution::empty(Interner), + GenericArgs::new_from_iter(interner, []), db.trait_environment_for_body(def.into()), )?; let c = interpret_mir(db, body, false, None)?.0?; Ok(c) } - -pub(crate) fn const_eval_discriminant_variant<'db>( - db: &'db dyn HirDatabase, - variant_id: EnumVariantId, -) -> Result> { - 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 = if is_signed { - try_const_isize(db, &c).unwrap() - } else { - try_const_usize(db, &c).unwrap() as i128 - }; - Ok(c) -} - -#[cfg(test)] -mod tests; 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 70a8ae766c0ba..f1aa06d488d44 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 @@ -1,17 +1,23 @@ use base_db::RootQueryDb; -use chalk_ir::Substitution; use hir_def::db::DefDatabase; use hir_expand::EditionedFileId; use rustc_apfloat::{ Float, ieee::{Half as f16, Quad as f128}, }; +use rustc_type_ir::inherent::IntoKind; use test_fixture::WithFixture; use test_utils::skip_slow_tests; use crate::{ - Const, ConstScalar, Interner, MemoryMap, consteval::try_const_usize, db::HirDatabase, - display::DisplayTarget, mir::pad16, setup_tracing, test_db::TestDB, + MemoryMap, + consteval::try_const_usize, + db::HirDatabase, + display::DisplayTarget, + mir::pad16, + next_solver::{Const, ConstBytes, ConstKind, DbInterner, GenericArgs}, + setup_tracing, + test_db::TestDB, }; use super::{ @@ -88,14 +94,12 @@ fn check_answer( panic!("Error in evaluating goal: {err}"); } }; - match &r.data(Interner).value { - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(b, mm) => { - check(b, mm); - } - x => panic!("Expected number but found {x:?}"), - }, - _ => panic!("result of const eval wasn't a concrete const"), + match r.kind() { + ConstKind::Value(value) => { + let ConstBytes { memory, memory_map } = value.value.inner(); + check(memory, memory_map); + } + _ => panic!("Expected number but found {r:?}"), } }); } @@ -117,8 +121,9 @@ fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { err } -fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result> { +fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError<'_>> { let _tracing = setup_tracing(); + let interner = DbInterner::new_with(db, None, None); 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; @@ -137,7 +142,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result None, }) .expect("No const named GOAL found in the test"); - db.const_eval(const_id.into(), Substitution::empty(Interner), None) + db.const_eval(const_id.into(), GenericArgs::new_from_iter(interner, []), None) } #[test] @@ -2508,7 +2513,7 @@ fn enums() { ); crate::attach_db(&db, || { let r = eval_goal(&db, file_id).unwrap(); - assert_eq!(try_const_usize(&db, &r), Some(1)); + assert_eq!(try_const_usize(&db, r), Some(1)); }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs new file mode 100644 index 0000000000000..458974384dca3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs @@ -0,0 +1,185 @@ +//! Constant evaluation details + +use base_db::Crate; +use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast}; +use hir_def::{ + expr_store::{HygieneId, path::Path}, + resolver::{Resolver, ValueNs}, + type_ref::LiteralConstRef, +}; +use stdx::never; + +use crate::{ + Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, + TraitEnvironment, Ty, TyBuilder, + db::HirDatabase, + generics::Generics, + lower::ParamLoweringMode, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, + to_placeholder_idx, +}; + +use super::mir::pad16; + +/// Extension trait for [`Const`] +pub trait ConstExt { + /// Is a [`Const`] unknown? + fn is_unknown(&self) -> bool; +} + +impl ConstExt for Const { + fn is_unknown(&self) -> bool { + match self.data(Interner).value { + // interned Unknown + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { + interned: ConstScalar::Unknown, + }) => true, + + // interned concrete anything else + chalk_ir::ConstValue::Concrete(..) => false, + + _ => { + tracing::error!( + "is_unknown was called on a non-concrete constant value! {:?}", + self + ); + true + } + } + } +} + +pub fn path_to_const<'g>( + db: &dyn HirDatabase, + resolver: &Resolver<'_>, + path: &Path, + mode: ParamLoweringMode, + args: impl FnOnce() -> &'g Generics, + debruijn: DebruijnIndex, + expected_ty: Ty, +) -> Option { + 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 => { + let idx = args.type_or_const_param_idx(p.into()).unwrap(); + ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32)) + } + 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)) + } + Some(ValueNs::ConstId(c)) => Some(intern_const_scalar( + ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)), + expected_ty, + )), + // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors. + _ => None, + } +} + +pub fn unknown_const(ty: Ty) -> Const { + ConstData { + ty, + value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }), + } + .intern(Interner) +} + +pub fn unknown_const_as_generic(ty: Ty) -> GenericArg { + unknown_const(ty).cast(Interner) +} + +/// Interns a constant scalar with the given type +pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { + ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) } + .intern(Interner) +} + +/// Interns a constant scalar with the given type +pub fn intern_const_ref( + db: &dyn HirDatabase, + value: &LiteralConstRef, + ty: Ty, + krate: Crate, +) -> Const { + 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. + let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); + ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) + } + LiteralConstRef::UInt(i) => { + let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); + ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) + } + LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()), + LiteralConstRef::Char(c) => { + ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default()) + } + LiteralConstRef::Unknown => ConstScalar::Unknown, + }; + intern_const_scalar(bytes, ty) +} + +/// Interns a possibly-unknown target usize +pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: Crate) -> Const { + intern_const_ref( + db, + &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), + TyBuilder::usize(), + krate, + ) +} + +pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { + let interner = DbInterner::new_with(db, None, None); + match &c.data(Interner).value { + chalk_ir::ConstValue::BoundVar(_) => None, + chalk_ir::ConstValue::InferenceVar(_) => None, + chalk_ir::ConstValue::Placeholder(_) => None, + chalk_ir::ConstValue::Concrete(c) => match &c.interned { + ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(it, false))), + ConstScalar::UnevaluatedConst(c, subst) => { + let ec = db.const_eval(*c, subst.to_nextsolver(interner), None).ok()?; + try_const_usize(db, &ec.to_chalk(interner)) + } + _ => None, + }, + } +} + +pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option { + let interner = DbInterner::new_with(db, None, None); + match &c.data(Interner).value { + chalk_ir::ConstValue::BoundVar(_) => None, + chalk_ir::ConstValue::InferenceVar(_) => None, + chalk_ir::ConstValue::Placeholder(_) => None, + chalk_ir::ConstValue::Concrete(c) => match &c.interned { + ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))), + ConstScalar::UnevaluatedConst(c, subst) => { + let ec = db.const_eval(*c, subst.to_nextsolver(interner), None).ok()?; + try_const_isize(db, &ec.to_chalk(interner)) + } + _ => None, + }, + } +} 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 deleted file mode 100644 index 2509ba2ef2603..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! 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, NextSolverToChalk, 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, id: p })) - } - 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(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 = unevaluated_const.args.to_chalk(interner); - 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 = unevaluated_const.args.to_chalk(interner); - 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>( - db: &'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.fixme_resolve_all_clone(); - 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]); - } - 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]) { - 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]) -} 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 11d3be5c3c487..4b33c8a84a810 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -16,8 +16,8 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty, - TyDefId, ValueTyDefId, chalk_db, + Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId, + chalk_db, consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, @@ -37,50 +37,56 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::mir::mir_body_query)] #[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)] - fn mir_body<'db>(&'db self, def: DefWithBodyId) -> Result, MirLowerError<'db>>; + fn mir_body<'db>( + &'db self, + def: DefWithBodyId, + ) -> Result>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::mir_body_for_closure_query)] fn mir_body_for_closure<'db>( &'db self, def: InternedClosureId, - ) -> Result, MirLowerError<'db>>; + ) -> Result>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::monomorphized_mir_body_query)] #[salsa::cycle(cycle_result = crate::mir::monomorphized_mir_body_cycle_result)] fn monomorphized_mir_body<'db>( &'db self, def: DefWithBodyId, - subst: Substitution, + subst: crate::next_solver::GenericArgs<'db>, env: Arc>, - ) -> Result, MirLowerError<'db>>; + ) -> Result>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] fn monomorphized_mir_body_for_closure<'db>( &'db self, def: InternedClosureId, - subst: Substitution, + subst: crate::next_solver::GenericArgs<'db>, env: Arc>, - ) -> Result, MirLowerError<'db>>; + ) -> Result>, MirLowerError<'db>>; #[salsa::invoke(crate::mir::borrowck_query)] #[salsa::lru(2024)] fn borrowck<'db>( &'db self, def: DefWithBodyId, - ) -> Result, MirLowerError<'db>>; + ) -> Result]>, MirLowerError<'db>>; #[salsa::invoke(crate::consteval::const_eval_query)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_cycle_result)] fn const_eval<'db>( &'db self, def: GeneralConstId, - subst: Substitution, + subst: crate::next_solver::GenericArgs<'db>, trait_env: Option>>, - ) -> Result>; + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_static_query)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)] - fn const_eval_static<'db>(&'db self, def: StaticId) -> Result>; + fn const_eval_static<'db>( + &'db self, + def: StaticId, + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)] 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 d79069901ebb8..bcd93c6699ccd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -52,7 +52,7 @@ use crate::{ 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, + TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval, db::{HirDatabase, InternedClosure}, from_assoc_type_id, from_placeholder_idx, generics::generics, @@ -750,8 +750,8 @@ impl<'db> HirDisplay for crate::next_solver::Const<'db> { } rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns( f, - &const_bytes.value.inner().0, - &const_bytes.value.inner().1, + &const_bytes.value.inner().memory, + &const_bytes.value.inner().memory_map, const_bytes.ty, ), rustc_type_ir::ConstKind::Unevaluated(unev) => { @@ -1025,7 +1025,7 @@ fn render_const_scalar_inner<'db>( ty.hir_fmt(f) } TyKind::Array(ty, len) => { - let Some(len) = consteval_nextsolver::try_const_usize(f.db, len) else { + let Some(len) = consteval::try_const_usize(f.db, len) else { return f.write_str(""); }; let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else { 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 4bd9691ea0795..aaf274799c63f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -7,7 +7,7 @@ use stdx::never; use triomphe::Arc; use crate::{ - TraitEnvironment, consteval_nextsolver, + TraitEnvironment, consteval, db::HirDatabase, method_resolution::TyFingerprint, next_solver::{ @@ -128,7 +128,7 @@ fn has_drop_glue_impl<'db>( .max() .unwrap_or(DropGlue::None), TyKind::Array(ty, len) => { - if consteval_nextsolver::try_const_usize(db, len) == Some(0) { + if consteval::try_const_usize(db, len) == Some(0) { // Arrays of size 0 don't have drop glue. return DropGlue::None; } 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 index 8a6ce0a69bda7..763b145812815 100644 --- 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 @@ -28,10 +28,7 @@ use crate::{ db::{HirDatabase, InternedClosure, InternedClosureId}, infer::InferenceContext, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, - next_solver::{ - DbInterner, EarlyBinder, GenericArgs, Ty, TyKind, - mapping::{ChalkToNextSolver, NextSolverToChalk}, - }, + next_solver::{DbInterner, EarlyBinder, GenericArgs, Ty, TyKind}, traits::FnTrait, }; @@ -47,16 +44,14 @@ impl<'db> HirPlace<'db> { fn ty(&self, ctx: &mut InferenceContext<'_, 'db>) -> Ty<'db> { let mut ty = ctx.table.resolve_completely(ctx.result[self.local]); for p in &self.projections { - ty = p - .projected_ty( - ty.to_chalk(ctx.interner()), - ctx.db, - |_, _, _| { - unreachable!("Closure field only happens in MIR"); - }, - ctx.owner.module(ctx.db).krate(), - ) - .to_nextsolver(ctx.interner()); + ty = p.projected_ty( + &ctx.table.infer_ctxt, + ty, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + ctx.owner.module(ctx.db).krate(), + ); } ty } @@ -865,16 +860,14 @@ impl<'db> InferenceContext<'_, 'db> { continue; } for (i, p) in capture.place.projections.iter().enumerate() { - ty = p - .projected_ty( - ty.to_chalk(self.interner()), - self.db, - |_, _, _| { - unreachable!("Closure field only happens in MIR"); - }, - self.owner.module(self.db).krate(), - ) - .to_nextsolver(self.interner()); + ty = p.projected_ty( + &self.table.infer_ctxt, + ty, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + self.owner.module(self.db).krate(), + ); if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); self.truncate_capture_spans(capture, i + 1); 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 b4140d88db349..859dfef70fed4 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 @@ -28,7 +28,7 @@ use crate::{ Adjust, Adjustment, AutoBorrow, CallableDefId, DeclContext, DeclOrigin, IncorrectGenericsLenKind, Rawness, TraitEnvironment, autoderef::overloaded_deref_ty, - consteval_nextsolver, + consteval, generics::generics, infer::{ AllowTwoPhase, BreakableKind, @@ -896,7 +896,7 @@ impl<'db> InferenceContext<'_, 'db> { Literal::ByteString(bs) => { let byte_type = self.types.u8; - let len = consteval_nextsolver::usize_const( + let len = consteval::usize_const( self.db, Some(bs.len() as u128), self.resolver.krate(), @@ -1221,7 +1221,7 @@ impl<'db> InferenceContext<'_, 'db> { let expected = Expectation::has_type(elem_ty); let (elem_ty, len) = match array { Array::ElementList { elements, .. } if elements.is_empty() => { - (elem_ty, consteval_nextsolver::usize_const(self.db, Some(0), krate)) + (elem_ty, consteval::usize_const(self.db, Some(0), krate)) } Array::ElementList { elements, .. } => { let mut coerce = CoerceMany::with_coercion_sites(elem_ty, elements); @@ -1231,7 +1231,7 @@ impl<'db> InferenceContext<'_, 'db> { } ( coerce.complete(self), - consteval_nextsolver::usize_const(self.db, Some(elements.len() as u128), krate), + consteval::usize_const(self.db, Some(elements.len() as u128), krate), ) } &Array::Repeat { initializer, repeat } => { @@ -1248,7 +1248,7 @@ impl<'db> InferenceContext<'_, 'db> { _ => _ = self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes), } - (elem_ty, consteval_nextsolver::eval_to_const(repeat, self)) + (elem_ty, consteval::eval_to_const(repeat, self)) } }; // Try to evaluate unevaluated constant, and insert variable if is not possible. 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 9f2f86dd3ef50..452ae316620f2 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 @@ -14,7 +14,7 @@ use stdx::TupleExt; use crate::{ DeclContext, DeclOrigin, InferenceDiagnostic, - consteval_nextsolver::{self, try_const_usize, usize_const}, + consteval::{self, try_const_usize, usize_const}, infer::{ AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, expr::ExprIsRead, @@ -591,11 +591,7 @@ impl<'db> InferenceContext<'_, 'db> { } let len = before.len() + suffix.len(); - let size = consteval_nextsolver::usize_const( - self.db, - Some(len as u128), - self.owner.krate(self.db), - ); + let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db)); let elem_ty = self.table.next_ty_var(); let array_ty = Ty::new_array_with_const_len(self.interner(), elem_ty, size); 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 e649e381ddd4a..110f767967c10 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,7 @@ use rustc_type_ir::inherent::{SliceLike, Ty as _}; use stdx::never; use crate::{ - InferenceDiagnostic, ValueTyDefId, consteval_nextsolver, + InferenceDiagnostic, ValueTyDefId, consteval, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, lower_nextsolver::LifetimeElisionKind, @@ -128,7 +128,7 @@ impl<'db> InferenceContext<'_, 'db> { match id { GenericParamId::TypeParamId(_) => self.types.error.into(), GenericParamId::ConstParamId(id) => { - consteval_nextsolver::unknown_const_as_generic(self.db.const_param_ty_ns(id)) + consteval::unknown_const_as_generic(self.db.const_param_ty_ns(id)) } GenericParamId::LifetimeParamId(_) => self.types.re_error.into(), } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index bdebe41b29989..826f19cf0b68d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -11,7 +11,9 @@ use triomphe::Arc; use crate::{ AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind, - consteval::try_const_usize, db::HirDatabase, + consteval::try_const_usize, + db::HirDatabase, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, }; // FIXME: Turn this into a query, it can be quite slow @@ -79,14 +81,17 @@ impl TypeVisitor for UninhabitedFrom<'_> { } self.recursive_ty.insert(ty.clone()); self.max_depth -= 1; + let interner = DbInterner::new_with(self.db, None, None); let r = match ty.kind(Interner) { TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst), TyKind::Never => BREAK_VISIBLY_UNINHABITED, TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder), - TyKind::Array(item_ty, len) => match try_const_usize(self.db, len) { - Some(0) | None => CONTINUE_OPAQUELY_INHABITED, - Some(1..) => item_ty.super_visit_with(self, outer_binder), - }, + TyKind::Array(item_ty, len) => { + match try_const_usize(self.db, len.to_nextsolver(interner)) { + Some(0) | None => CONTINUE_OPAQUELY_INHABITED, + Some(1..) => item_ty.super_visit_with(self, outer_binder), + } + } TyKind::Alias(AliasTy::Projection(projection)) => { // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle // `TyKind::AssociatedType`, but perhaps in the future it will. 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 eed36b1bb7f5d..a857602fa08a8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -21,7 +21,7 @@ use triomphe::Arc; use crate::{ TraitEnvironment, - consteval_nextsolver::try_const_usize, + consteval::try_const_usize, db::HirDatabase, next_solver::{ DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode, 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 4ff5cc5588bfe..76cc65277cd3d 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,8 @@ extern crate ra_ap_rustc_type_ir as rustc_type_ir; extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; +extern crate self as hir_ty; + mod builder; mod chalk_db; mod chalk_ext; @@ -37,7 +39,7 @@ mod utils; pub mod autoderef; pub mod consteval; -pub mod consteval_nextsolver; +pub mod consteval_chalk; pub mod db; pub mod diagnostics; pub mod display; @@ -782,7 +784,12 @@ where _var: InferenceVar, _outer_binder: DebruijnIndex, ) -> Fallible { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } + if cfg!(debug_assertions) { + Err(NoSolution) + } else { + let interner = DbInterner::conjure(); + Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner)) + } } fn try_fold_free_var_const( @@ -791,7 +798,12 @@ where _bound_var: BoundVar, _outer_binder: DebruijnIndex, ) -> Fallible { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } + if cfg!(debug_assertions) { + Err(NoSolution) + } else { + let interner = DbInterner::conjure(); + Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner)) + } } fn try_fold_inference_lifetime( 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 a9b523a4a6edf..ee7b0cdd1fe34 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -49,7 +49,7 @@ use crate::{ ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, all_super_traits, - consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, + consteval_chalk::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, generics::{Generics, generics, trait_self_param_idx}, 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 cdac1c9829810..f988b6160ba51 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 @@ -23,7 +23,7 @@ use crate::{ Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, TyLoweringContext, WhereClause, - consteval::{unknown_const, unknown_const_as_generic}, + consteval_chalk::{unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, generics::{Generics, generics}, 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 98881004bb9a1..5a0bccea5f9c1 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,7 +62,7 @@ use crate::next_solver::ParamConst; use crate::{ FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, - consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic}, + consteval::{intern_const_ref, path_to_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics, trait_self_param_idx}, lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics}, 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 babc39694ff1c..b003cc574d5b5 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 @@ -30,7 +30,7 @@ use stdx::never; use crate::{ GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource, PathLoweringDiagnostic, TyDefId, ValueTyDefId, - consteval_nextsolver::{unknown_const, unknown_const_as_generic}, + consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics}, lower::PathDiagnosticCallbackData, 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 086abc95917ef..110fee824cb2d 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 @@ -4,13 +4,12 @@ //! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs. use std::ops::ControlFlow; -use arrayvec::ArrayVec; use base_db::Crate; use chalk_ir::{UniverseIndex, WithKind, cast::Cast}; use hir_def::{ AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleId, TraitId, TypeAliasId, - nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map}, + nameres::{DefMap, block_def_map, crate_def_map}, signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags}, }; use hir_expand::name::Name; @@ -18,7 +17,7 @@ use intern::sym; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ - FloatTy, IntTy, UintTy, + FloatTy, IntTy, TypeVisitableExt, UintTy, inherent::{ AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _, }, @@ -27,6 +26,8 @@ use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; +use crate::next_solver::infer::InferCtxt; +use crate::next_solver::infer::select::ImplSource; use crate::{ CanonicalVarKinds, DebruijnIndex, GenericArgData, InEnvironment, Interner, TraitEnvironment, TyBuilder, VariableKind, @@ -36,10 +37,10 @@ use crate::{ lang_items::is_box, next_solver::{ Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId, - TraitRef, Ty, TyKind, + TraitRef, Ty, TyKind, TypingMode, infer::{ - DefineOpaqueTypes, - traits::{ObligationCause, PredicateObligation}, + DbInternerInferExt, DefineOpaqueTypes, + traits::{Obligation, ObligationCause, PredicateObligation}, }, mapping::NextSolverToChalk, obligation_ctxt::ObligationCtxt, @@ -689,11 +690,12 @@ pub(crate) fn iterate_method_candidates<'db, T>( } pub fn lookup_impl_const<'db>( - interner: DbInterner<'db>, + infcx: &InferCtxt<'db>, env: Arc>, const_id: ConstId, subs: GenericArgs<'db>, ) -> (ConstId, GenericArgs<'db>) { + let interner = infcx.interner; let db = interner.db; let trait_id = match const_id.lookup(db).container { @@ -708,7 +710,7 @@ pub fn lookup_impl_const<'db>( None => return (const_id, subs), }; - lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) + lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name) .and_then( |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None }, ) @@ -759,6 +761,7 @@ pub(crate) fn lookup_impl_method_query<'db>( fn_subst: GenericArgs<'db>, ) -> (FunctionId, GenericArgs<'db>) { let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else { return (func, fn_subst); @@ -772,7 +775,7 @@ pub(crate) fn lookup_impl_method_query<'db>( let name = &db.function_signature(func).name; let Some((impl_fn, impl_subst)) = - lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name).and_then(|assoc| { + lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env, name).and_then(|assoc| { if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None } }) else { @@ -789,78 +792,53 @@ pub(crate) fn lookup_impl_method_query<'db>( } fn lookup_impl_assoc_item_for_trait_ref<'db>( + infcx: &InferCtxt<'db>, trait_ref: TraitRef<'db>, - db: &'db dyn HirDatabase, env: Arc>, name: &Name, ) -> Option<(AssocItemId, GenericArgs<'db>)> { - let hir_trait_id = trait_ref.def_id.0; - let self_ty = trait_ref.self_ty(); - let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?; - let impls = db.trait_impls_in_deps(env.krate); - - let trait_module = hir_trait_id.module(db); - let type_module = match self_ty_fp { - TyFingerprint::Adt(adt_id) => Some(adt_id.module(db)), - TyFingerprint::ForeignType(type_id) => Some(type_id.module(db)), - TyFingerprint::Dyn(trait_id) => Some(trait_id.module(db)), - _ => None, - }; - - let def_blocks: ArrayVec<_, 2> = - [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())] - .into_iter() - .flatten() - .filter_map(|block_id| db.trait_impls_in_block(block_id)) - .collect(); - - let impls = impls - .iter() - .chain(&def_blocks) - .flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp)); - - let table = InferenceTable::new(db, env); - - let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?; - let item = impl_data.items.iter().find_map(|(n, it)| match *it { - AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)), - AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)), - AssocItemId::TypeAliasId(_) => None, - })?; + let (impl_id, impl_subst) = find_matching_impl(infcx, &env, trait_ref)?; + let item = + impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it { + AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)), + AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)), + AssocItemId::TypeAliasId(_) => None, + })?; Some((item, impl_subst)) } -fn find_matching_impl<'db>( - mut impls: impl Iterator, - mut table: InferenceTable<'db>, - actual_trait_ref: TraitRef<'db>, -) -> Option<(&'db ImplItems, GenericArgs<'db>)> { - let db = table.db; - impls.find_map(|impl_| { - table.run_in_snapshot(|table| { - let impl_substs = table.fresh_args_for_item(impl_.into()); - let trait_ref = db - .impl_trait(impl_) - .expect("non-trait method in find_matching_impl") - .instantiate(table.interner(), impl_substs); - - if !table.unify(trait_ref, actual_trait_ref) { - return None; - } +pub(crate) fn find_matching_impl<'db>( + infcx: &InferCtxt<'db>, + env: &TraitEnvironment<'db>, + trait_ref: TraitRef<'db>, +) -> Option<(ImplId, GenericArgs<'db>)> { + let trait_ref = + infcx.at(&ObligationCause::dummy(), env.env).deeply_normalize(trait_ref).ok()?; - if let Some(predicates) = - db.generic_predicates_ns(impl_.into()).instantiate(table.interner(), impl_substs) - { - for predicate in predicates { - if table.try_obligation(predicate.0).no_solution() { - return None; - } - table.register_obligation(predicate.0); - } - } - Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) - }) - }) + let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env.env, trait_ref); + + let selection = infcx.select(&obligation).ok()??; + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut ocx = ObligationCtxt::new(infcx); + let impl_source = selection.map(|obligation| ocx.register_obligation(obligation)); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + return None; + } + + let impl_source = infcx.resolve_vars_if_possible(impl_source); + if impl_source.has_non_region_infer() { + return None; + } + + match impl_source { + ImplSource::UserDefined(impl_source) => Some((impl_source.impl_def_id, impl_source.args)), + ImplSource::Param(_) | ImplSource::Builtin(..) => None, + } } fn is_inherent_impl_coherent<'db>( 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 a05cc2a02b70e..936895fb7fd3b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -2,18 +2,7 @@ use std::{collections::hash_map::Entry, fmt::Display, iter}; -use crate::{ - CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap, - Substitution, TraitEnvironment, Ty, TyExt, TyKind, - consteval::usize_const, - db::HirDatabase, - display::{DisplayTarget, HirDisplay}, - infer::{PointerCast, normalize}, - lang_items::is_box, - mapping::ToChalk, -}; use base_db::Crate; -use chalk_ir::Mutability; use either::Either; use hir_def::{ DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, @@ -21,6 +10,25 @@ use hir_def::{ hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId}, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; +use rustc_ast_ir::Mutability; +use rustc_hash::FxHashMap; +use rustc_type_ir::inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _}; +use smallvec::{SmallVec, smallvec}; +use stdx::{impl_from, never}; + +use crate::{ + CallableDefId, InferenceResult, MemoryMap, + consteval::usize_const, + db::{HirDatabase, InternedClosureId}, + display::{DisplayTarget, HirDisplay}, + infer::PointerCast, + lang_items::is_box, + next_solver::{ + Const, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + }, +}; mod borrowck; mod eval; @@ -36,25 +44,22 @@ pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_bod pub use monomorphization::{ monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query, }; -use rustc_hash::FxHashMap; -use smallvec::{SmallVec, smallvec}; -use stdx::{impl_from, never}; pub(crate) use lower::mir_body_cycle_result; pub(crate) use monomorphization::monomorphized_mir_body_cycle_result; -use super::consteval::{intern_const_scalar, try_const_usize}; +use super::consteval::try_const_usize; -pub type BasicBlockId = Idx; -pub type LocalId = Idx; +pub type BasicBlockId<'db> = Idx>; +pub type LocalId<'db> = Idx>; -fn return_slot() -> LocalId { +fn return_slot<'db>() -> LocalId<'db> { LocalId::from_raw(RawIdx::from(0)) } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Local { - pub ty: Ty, +pub struct Local<'db> { + pub ty: Ty<'db>, } /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of @@ -76,19 +81,19 @@ pub struct Local { /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Operand { - kind: OperandKind, +pub struct Operand<'db> { + kind: OperandKind<'db>, // FIXME : This should actually just be of type `MirSpan`. span: Option, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum OperandKind { +pub enum OperandKind<'db> { /// Creates a value by loading the given place. /// /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there /// is no such requirement. - Copy(Place), + Copy(Place<'db>), /// Creates a value by performing loading the place, just like the `Copy` operand. /// @@ -97,41 +102,41 @@ pub enum OperandKind { /// place without first re-initializing it. /// /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 - Move(Place), + Move(Place<'db>), /// Constants are already semantically values, and remain unchanged. - Constant(Const), + Constant { konst: Const<'db>, ty: Ty<'db> }, /// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc /// handles it with the `Constant` variant somehow. Static(StaticId), } -impl Operand { - fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'static>, ty: Ty) -> Self { +impl<'db> Operand<'db> { + fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'db>, ty: Ty<'db>) -> Self { + let interner = DbInterner::conjure(); Operand { - kind: OperandKind::Constant(intern_const_scalar( - ConstScalar::Bytes(data, memory_map), + kind: OperandKind::Constant { + konst: Const::new_valtree(interner, ty, data, memory_map), ty, - )), + }, span: None, } } - fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self { + fn from_bytes(data: Box<[u8]>, ty: Ty<'db>) -> Self { Operand::from_concrete_const(data, MemoryMap::default(), ty) } - fn const_zst(ty: Ty) -> Operand { + fn const_zst(ty: Ty<'db>) -> Operand<'db> { Self::from_bytes(Box::default(), ty) } fn from_fn( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, func_id: hir_def::FunctionId, - generic_args: Substitution, - ) -> Operand { - let ty = - chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args) - .intern(Interner); + generic_args: GenericArgs<'db>, + ) -> Operand<'db> { + let interner = DbInterner::new_with(db, None, None); + let ty = Ty::new_fn_def(interner, CallableDefId::FunctionId(func_id).into(), generic_args); Operand::from_bytes(Box::default(), ty) } } @@ -150,83 +155,81 @@ pub enum ProjectionElem { } impl ProjectionElem { - pub fn projected_ty( + pub fn projected_ty<'db>( &self, - mut base: Ty, - db: &dyn HirDatabase, - closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty, + infcx: &InferCtxt<'db>, + mut base: Ty<'db>, + closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>, krate: Crate, - ) -> Ty { + ) -> Ty<'db> { + let interner = infcx.interner; + let db = interner.db; + // we only bail on mir building when there are type mismatches // but error types may pop up resulting in us still attempting to build the mir // so just propagate the error type - if base.is_unknown() { - return TyKind::Error.intern(Interner); + if base.is_ty_error() { + return Ty::new_error(interner, ErrorGuaranteed); } - if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) { - base = normalize( - db, - // FIXME: we should get this from caller - TraitEnvironment::empty(krate), - base, - ); + if matches!(base.kind(), TyKind::Alias(..)) { + let mut ocx = ObligationCtxt::new(infcx); + // FIXME: we should get this from caller + let env = ParamEnv::empty(); + match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) { + Ok(it) => base = it, + Err(_) => return Ty::new_error(interner, ErrorGuaranteed), + } } + match self { - ProjectionElem::Deref => match &base.kind(Interner) { - TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(), - TyKind::Adt(adt, subst) if is_box(db, adt.0) => { - subst.at(Interner, 0).assert_ty_ref(Interner).clone() - } + ProjectionElem::Deref => match base.kind() { + TyKind::RawPtr(inner, _) | TyKind::Ref(_, inner, _) => inner, + TyKind::Adt(adt_def, subst) if is_box(db, adt_def.def_id().0) => subst.type_at(0), _ => { never!( "Overloaded deref on type {} is not a projection", base.display(db, DisplayTarget::from_crate(db, krate)) ); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::Field(Either::Left(f)) => match base.kind(Interner) { + ProjectionElem::Field(Either::Left(f)) => match base.kind() { TyKind::Adt(_, subst) => { - db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst) + db.field_types_ns(f.parent)[f.local_id].instantiate(interner, subst) } ty => { never!("Only adt has field, found {:?}", ty); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) { - TyKind::Tuple(_, subst) => subst - .as_slice(Interner) - .get(f.index as usize) - .map(|x| x.assert_ty_ref(Interner)) - .cloned() - .unwrap_or_else(|| { + ProjectionElem::Field(Either::Right(f)) => match base.kind() { + TyKind::Tuple(subst) => { + subst.as_slice().get(f.index as usize).copied().unwrap_or_else(|| { never!("Out of bound tuple field"); - TyKind::Error.intern(Interner) - }), + Ty::new_error(interner, ErrorGuaranteed) + }) + } ty => { never!("Only tuple has tuple field: {:?}", ty); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::ClosureField(f) => match &base.kind(Interner) { - TyKind::Closure(id, subst) => closure_field(*id, subst, *f), + ProjectionElem::ClosureField(f) => match base.kind() { + TyKind::Closure(id, subst) => closure_field(id.0, subst, *f), _ => { never!("Only closure has closure field"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { - match &base.kind(Interner) { - TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(), - _ => { - never!("Overloaded index is not a projection"); - TyKind::Error.intern(Interner) - } + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => match base.kind() { + TyKind::Array(inner, _) | TyKind::Slice(inner) => inner, + _ => { + never!("Overloaded index is not a projection"); + Ty::new_error(interner, ErrorGuaranteed) } - } - &ProjectionElem::Subslice { from, to } => match &base.kind(Interner) { + }, + &ProjectionElem::Subslice { from, to } => match base.kind() { TyKind::Array(inner, c) => { let next_c = usize_const( db, @@ -236,34 +239,34 @@ impl ProjectionElem { }, krate, ); - TyKind::Array(inner.clone(), next_c).intern(Interner) + Ty::new_array_with_const_len(interner, inner, next_c) } - TyKind::Slice(_) => base.clone(), + TyKind::Slice(_) => base, _ => { never!("Subslice projection should only happen on slice and array"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } }, ProjectionElem::OpaqueCast(_) => { never!("We don't emit these yet"); - TyKind::Error.intern(Interner) + Ty::new_error(interner, ErrorGuaranteed) } } } } -type PlaceElem = ProjectionElem; +type PlaceElem<'db> = ProjectionElem, Ty<'db>>; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProjectionId(u32); #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProjectionStore { - id_to_proj: FxHashMap>, - proj_to_id: FxHashMap, ProjectionId>, +pub struct ProjectionStore<'db> { + id_to_proj: FxHashMap]>>, + proj_to_id: FxHashMap]>, ProjectionId>, } -impl Default for ProjectionStore { +impl Default for ProjectionStore<'_> { fn default() -> Self { let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() }; // Ensure that [] will get the id 0 which is used in `ProjectionId::Empty` @@ -272,17 +275,17 @@ impl Default for ProjectionStore { } } -impl ProjectionStore { +impl<'db> ProjectionStore<'db> { pub fn shrink_to_fit(&mut self) { self.id_to_proj.shrink_to_fit(); self.proj_to_id.shrink_to_fit(); } - pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option { + pub fn intern_if_exist(&self, projection: &[PlaceElem<'db>]) -> Option { self.proj_to_id.get(projection).copied() } - pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId { + pub fn intern(&mut self, projection: Box<[PlaceElem<'db>]>) -> ProjectionId { let new_id = ProjectionId(self.proj_to_id.len() as u32); match self.proj_to_id.entry(projection) { Entry::Occupied(id) => *id.get(), @@ -303,11 +306,15 @@ impl ProjectionId { self == ProjectionId::EMPTY } - pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] { + pub fn lookup<'a, 'db>(self, store: &'a ProjectionStore<'db>) -> &'a [PlaceElem<'db>] { store.id_to_proj.get(&self).unwrap() } - pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId { + pub fn project<'db>( + self, + projection: PlaceElem<'db>, + store: &mut ProjectionStore<'db>, + ) -> ProjectionId { let mut current = self.lookup(store).to_vec(); current.push(projection); store.intern(current.into()) @@ -315,13 +322,13 @@ impl ProjectionId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Place { - pub local: LocalId, +pub struct Place<'db> { + pub local: LocalId<'db>, pub projection: ProjectionId, } -impl Place { - fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool { +impl<'db> Place<'db> { + fn is_parent(&self, child: &Place<'db>, store: &ProjectionStore<'db>) -> bool { self.local == child.local && child.projection.lookup(store).starts_with(self.projection.lookup(store)) } @@ -329,39 +336,39 @@ impl Place { /// The place itself is not included fn iterate_over_parents<'a>( &'a self, - store: &'a ProjectionStore, - ) -> impl Iterator + 'a { + store: &'a ProjectionStore<'db>, + ) -> impl Iterator> + 'a { let projection = self.projection.lookup(store); (0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| { Some(Place { local: self.local, projection: store.intern_if_exist(x)? }) }) } - fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place { + fn project(&self, projection: PlaceElem<'db>, store: &mut ProjectionStore<'db>) -> Place<'db> { Place { local: self.local, projection: self.projection.project(projection, store) } } } -impl From for Place { - fn from(local: LocalId) -> Self { +impl<'db> From> for Place<'db> { + fn from(local: LocalId<'db>) -> Self { Self { local, projection: ProjectionId::EMPTY } } } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum AggregateKind { +pub enum AggregateKind<'db> { /// The type is of the element - Array(Ty), + Array(Ty<'db>), /// The type is of the tuple - Tuple(Ty), - Adt(VariantId, Substitution), + Tuple(Ty<'db>), + Adt(VariantId, GenericArgs<'db>), Union(UnionId, FieldId), - Closure(Ty), + Closure(Ty<'db>), //Coroutine(LocalDefId, SubstsRef, Movability), } #[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct SwitchTargets { +pub struct SwitchTargets<'db> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. values: SmallVec<[u128; 1]>, @@ -378,17 +385,17 @@ pub struct SwitchTargets { // // However we’ve decided to keep this as-is until we figure a case // where some other approach seems to be strictly better than other. - targets: SmallVec<[BasicBlockId; 2]>, + targets: SmallVec<[BasicBlockId<'db>; 2]>, } -impl SwitchTargets { +impl<'db> SwitchTargets<'db> { /// Creates switch targets from an iterator of values and target blocks. /// /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to /// `goto otherwise;`. pub fn new( - targets: impl Iterator, - otherwise: BasicBlockId, + targets: impl Iterator)>, + otherwise: BasicBlockId<'db>, ) -> Self { let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); targets.push(otherwise); @@ -397,12 +404,12 @@ impl SwitchTargets { /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, /// and to `else_` if not. - pub fn static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self { + pub fn static_if(value: u128, then: BasicBlockId<'db>, else_: BasicBlockId<'db>) -> Self { Self { values: smallvec![value], targets: smallvec![then, else_] } } /// Returns the fallback target that is jumped to when none of the values match the operand. - pub fn otherwise(&self) -> BasicBlockId { + pub fn otherwise(&self) -> BasicBlockId<'db> { *self.targets.last().unwrap() } @@ -412,33 +419,33 @@ impl SwitchTargets { /// including the `otherwise` fallback target. /// /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator)> + '_ { iter::zip(&self.values, &self.targets).map(|(x, y)| (*x, *y)) } /// Returns a slice with all possible jump targets (including the fallback target). - pub fn all_targets(&self) -> &[BasicBlockId] { + pub fn all_targets(&self) -> &[BasicBlockId<'db>] { &self.targets } /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the /// specific value. This cannot fail, as it'll return the `otherwise` /// branch if there's not a specific match for the value. - pub fn target_for_value(&self, value: u128) -> BasicBlockId { + pub fn target_for_value(&self, value: u128) -> BasicBlockId<'db> { self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise()) } } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Terminator { +pub struct Terminator<'db> { pub span: MirSpan, - pub kind: TerminatorKind, + pub kind: TerminatorKind<'db>, } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum TerminatorKind { +pub enum TerminatorKind<'db> { /// Block has one successor; we continue execution there. - Goto { target: BasicBlockId }, + Goto { target: BasicBlockId<'db> }, /// Switches based on the computed value. /// @@ -450,9 +457,9 @@ pub enum TerminatorKind { /// Target values may not appear more than once. SwitchInt { /// The discriminant value being tested. - discr: Operand, + discr: Operand<'db>, - targets: SwitchTargets, + targets: SwitchTargets<'db>, }, /// Indicates that the landing pad is finished and that the process should continue unwinding. @@ -503,7 +510,7 @@ pub enum TerminatorKind { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place, target: BasicBlockId, unwind: Option }, + Drop { place: Place<'db>, target: BasicBlockId<'db>, unwind: Option> }, /// Drops the place and assigns a new value to it. /// @@ -536,10 +543,10 @@ pub enum TerminatorKind { /// /// Disallowed after drop elaboration. DropAndReplace { - place: Place, - value: Operand, - target: BasicBlockId, - unwind: Option, + place: Place<'db>, + value: Operand<'db>, + target: BasicBlockId<'db>, + unwind: Option>, }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of @@ -554,18 +561,18 @@ pub enum TerminatorKind { /// [#71117]: https://github.com/rust-lang/rust/issues/71117 Call { /// The function that’s being called. - func: Operand, + func: Operand<'db>, /// Arguments the function is called with. /// These are owned by the callee, which is free to modify them. /// This allows the memory occupied by "by-value" arguments to be /// reused across function calls without duplicating the contents. - args: Box<[Operand]>, + args: Box<[Operand<'db>]>, /// Where the returned value will be written - destination: Place, + destination: Place<'db>, /// Where to go after this call returns. If none, the call necessarily diverges. - target: Option, + target: Option>, /// Cleanups to be done if the call unwinds. - cleanup: Option, + cleanup: Option>, /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, @@ -581,11 +588,11 @@ pub enum TerminatorKind { /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the /// assertion does not fail, execution continues at the specified basic block. Assert { - cond: Operand, + cond: Operand<'db>, expected: bool, //msg: AssertMessage, - target: BasicBlockId, - cleanup: Option, + target: BasicBlockId<'db>, + cleanup: Option>, }, /// Marks a suspend point. @@ -602,13 +609,13 @@ pub enum TerminatorKind { /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? Yield { /// The value to return. - value: Operand, + value: Operand<'db>, /// Where to resume to. - resume: BasicBlockId, + resume: BasicBlockId<'db>, /// The place to store the resume argument in. - resume_arg: Place, + resume_arg: Place<'db>, /// Cleanup to be done if the coroutine is dropped at this suspend point. - drop: Option, + drop: Option>, }, /// Indicates the end of dropping a coroutine. @@ -631,10 +638,10 @@ pub enum TerminatorKind { /// Disallowed after drop elaboration. FalseEdge { /// The target normal control flow will take. - real_target: BasicBlockId, + real_target: BasicBlockId<'db>, /// A block control flow could conceptually jump to, but won't in /// practice. - imaginary_target: BasicBlockId, + imaginary_target: BasicBlockId<'db>, }, /// A terminator for blocks that only take one path in reality, but where we reserve the right @@ -646,14 +653,14 @@ pub enum TerminatorKind { /// Disallowed after drop elaboration. FalseUnwind { /// The target normal control flow will take. - real_target: BasicBlockId, + real_target: BasicBlockId<'db>, /// The imaginary cleanup block link. This particular path will never be taken /// in practice, but in order to avoid fragility we want to always /// consider it in borrowck. We don't want to accept programs which /// pass borrowck only when `panic=abort` or some assertions are disabled /// due to release vs. debug mode builds. This needs to be an `Option` because /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. - unwind: Option, + unwind: Option>, }, } @@ -840,8 +847,8 @@ impl From for BinOp { } } -impl From for Rvalue { - fn from(x: Operand) -> Self { +impl<'db> From> for Rvalue<'db> { + fn from(x: Operand<'db>) -> Self { Self::Use(x) } } @@ -870,14 +877,14 @@ pub enum CastKind { } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Rvalue { +pub enum Rvalue<'db> { /// Yields the operand unchanged - Use(Operand), + Use(Operand<'db>), /// Creates an array where each element is the value of the operand. /// /// Corresponds to source code like `[x; 32]`. - Repeat(Operand, Const), + Repeat(Operand<'db>, Const<'db>), /// Creates a reference of the indicated kind to the place. /// @@ -886,7 +893,7 @@ pub enum Rvalue { /// exactly what the behavior of this operation should be. /// /// `Shallow` borrows are disallowed after drop lowering. - Ref(BorrowKind, Place), + Ref(BorrowKind, Place<'db>), /// Creates a pointer/reference to the given thread local. /// @@ -917,7 +924,7 @@ pub enum Rvalue { /// If the type of the place is an array, this is the array length. For slices (`[T]`, not /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is /// ill-formed for places of other types. - Len(Place), + Len(Place<'db>), /// Performs essentially all of the casts that can be performed via `as`. /// @@ -925,7 +932,7 @@ pub enum Rvalue { /// /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why /// `ArrayToPointer` and `MutToConstPointer` are special. - Cast(CastKind, Operand, Ty), + Cast(CastKind, Operand<'db>, Ty<'db>), // FIXME link to `pointer::offset` when it hits stable. /// * `Offset` has the same semantics as `pointer::offset`, except that the second @@ -957,7 +964,7 @@ pub enum Rvalue { /// when the value of right-hand side is negative. /// /// Other combinations of types and operators are unsupported. - CheckedBinaryOp(BinOp, Operand, Operand), + CheckedBinaryOp(BinOp, Operand<'db>, Operand<'db>), /// Computes a value as described by the operation. //NullaryOp(NullOp, Ty), @@ -968,7 +975,7 @@ pub enum Rvalue { /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds /// return a value with the same type as their operand. - UnaryOp(UnOp, Operand), + UnaryOp(UnOp, Operand<'db>), /// Computes the discriminant of the place, returning it as an integer of type /// [`discriminant_ty`]. Returns zero for types without discriminant. @@ -980,7 +987,7 @@ pub enum Rvalue { /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty /// [#91095]: https://github.com/rust-lang/rust/issues/91095 /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant - Discriminant(Place), + Discriminant(Place<'db>), /// Creates an aggregate value, like a tuple or struct. /// @@ -990,17 +997,17 @@ pub enum Rvalue { /// /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. - Aggregate(AggregateKind, Box<[Operand]>), + Aggregate(AggregateKind<'db>, Box<[Operand<'db>]>), /// Transmutes a `*mut u8` into shallow-initialized `Box`. /// /// This is different from a normal transmute because dataflow analysis will treat the box as /// initialized but its content as uninitialized. Like other pointer casts, this in general /// affects alias analysis. - ShallowInitBox(Operand, Ty), + ShallowInitBox(Operand<'db>, Ty<'db>), /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer. - ShallowInitBoxWithAlloc(Ty), + ShallowInitBoxWithAlloc(Ty<'db>), /// A CopyForDeref is equivalent to a read from a place at the /// codegen level, but is treated specially by drop elaboration. When such a read happens, it @@ -1010,41 +1017,41 @@ pub enum Rvalue { /// read never happened and just projects further. This allows simplifying various MIR /// optimizations and codegen backends that previously had to handle deref operations anywhere /// in a place. - CopyForDeref(Place), + CopyForDeref(Place<'db>), } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum StatementKind { - Assign(Place, Rvalue), - FakeRead(Place), +pub enum StatementKind<'db> { + Assign(Place<'db>, Rvalue<'db>), + FakeRead(Place<'db>), //SetDiscriminant { // place: Box, // variant_index: VariantIdx, //}, - Deinit(Place), - StorageLive(LocalId), - StorageDead(LocalId), + Deinit(Place<'db>), + StorageLive(LocalId<'db>), + StorageDead(LocalId<'db>), //Retag(RetagKind, Box), //AscribeUserType(Place, UserTypeProjection, Variance), //Intrinsic(Box), Nop, } -impl StatementKind { - fn with_span(self, span: MirSpan) -> Statement { +impl<'db> StatementKind<'db> { + fn with_span(self, span: MirSpan) -> Statement<'db> { Statement { kind: self, span } } } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct Statement { - pub kind: StatementKind, +pub struct Statement<'db> { + pub kind: StatementKind<'db>, pub span: MirSpan, } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct BasicBlock { +pub struct BasicBlock<'db> { /// List of statements in this block. - pub statements: Vec, + pub statements: Vec>, /// Terminator for this block. /// @@ -1054,7 +1061,7 @@ pub struct BasicBlock { /// exception is that certain passes, such as `simplify_cfg`, swap /// out the terminator temporarily with `None` while they continue /// to recurse over the set of basic blocks. - pub terminator: Option, + pub terminator: Option>, /// If true, this block lies on an unwind path. This is used /// during codegen where distinct kinds of basic blocks may be @@ -1064,35 +1071,35 @@ pub struct BasicBlock { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct MirBody { - pub projection_store: ProjectionStore, - pub basic_blocks: Arena, - pub locals: Arena, - pub start_block: BasicBlockId, +pub struct MirBody<'db> { + pub projection_store: ProjectionStore<'db>, + pub basic_blocks: Arena>, + pub locals: Arena>, + pub start_block: BasicBlockId<'db>, pub owner: DefWithBodyId, - pub binding_locals: ArenaMap, - pub param_locals: Vec, + pub binding_locals: ArenaMap>, + pub param_locals: Vec>, /// This field stores the closures directly owned by this body. It is used /// in traversing every mir body. - pub closures: Vec, + pub closures: Vec, } -impl MirBody { - pub fn local_to_binding_map(&self) -> ArenaMap { +impl<'db> MirBody<'db> { + pub fn local_to_binding_map(&self) -> ArenaMap, BindingId> { self.binding_locals.iter().map(|(it, y)| (*y, it)).collect() } - fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) { - fn for_operand( - op: &mut Operand, - f: &mut impl FnMut(&mut Place, &mut ProjectionStore), - store: &mut ProjectionStore, + fn walk_places(&mut self, mut f: impl FnMut(&mut Place<'db>, &mut ProjectionStore<'db>)) { + fn for_operand<'db>( + op: &mut Operand<'db>, + f: &mut impl FnMut(&mut Place<'db>, &mut ProjectionStore<'db>), + store: &mut ProjectionStore<'db>, ) { match &mut op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { f(p, store); } - OperandKind::Constant(_) | OperandKind::Static(_) => (), + OperandKind::Constant { .. } | OperandKind::Static(_) => (), } } for (_, block) in self.basic_blocks.iter_mut() { 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 08b1e03726d70..db16c943968fd 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 @@ -11,14 +11,15 @@ use rustc_hash::FxHashMap; use stdx::never; use triomphe::Arc; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ - ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags, - db::{HirDatabase, InternedClosure}, + TraitEnvironment, + db::{HirDatabase, InternedClosure, InternedClosureId}, display::DisplayTarget, mir::OperandKind, - utils::ClosureSubst, + next_solver::{ + DbInterner, GenericArgs, SolverDefIds, Ty, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, + }, }; use super::{ @@ -35,45 +36,45 @@ pub enum MutabilityReason { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct MovedOutOfRef { - pub ty: Ty, +pub struct MovedOutOfRef<'db> { + pub ty: Ty<'db>, pub span: MirSpan, } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct PartiallyMoved { - pub ty: Ty, +pub struct PartiallyMoved<'db> { + pub ty: Ty<'db>, pub span: MirSpan, - pub local: LocalId, + pub local: LocalId<'db>, } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct BorrowRegion { - pub local: LocalId, +pub struct BorrowRegion<'db> { + pub local: LocalId<'db>, pub kind: BorrowKind, pub places: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct BorrowckResult { - pub mir_body: Arc, - pub mutability_of_locals: ArenaMap, - pub moved_out_of_ref: Vec, - pub partially_moved: Vec, - pub borrow_regions: Vec, +pub struct BorrowckResult<'db> { + pub mir_body: Arc>, + pub mutability_of_locals: ArenaMap, MutabilityReason>, + pub moved_out_of_ref: Vec>, + pub partially_moved: Vec>, + pub borrow_regions: Vec>, } fn all_mir_bodies<'db>( db: &'db dyn HirDatabase, def: DefWithBodyId, - mut cb: impl FnMut(Arc), + mut cb: impl FnMut(Arc>), ) -> Result<(), MirLowerError<'db>> { fn for_closure<'db>( db: &'db dyn HirDatabase, - c: ClosureId, - cb: &mut impl FnMut(Arc), + c: InternedClosureId, + cb: &mut impl FnMut(Arc>), ) -> Result<(), MirLowerError<'db>> { - match db.mir_body_for_closure(c.into()) { + match db.mir_body_for_closure(c) { Ok(body) => { cb(body.clone()); body.closures.iter().try_for_each(|&it| for_closure(db, it, cb)) @@ -93,14 +94,21 @@ fn all_mir_bodies<'db>( pub fn borrowck_query<'db>( db: &'db dyn HirDatabase, def: DefWithBodyId, -) -> Result, MirLowerError<'db>> { +) -> Result]>, MirLowerError<'db>> { let _p = tracing::info_span!("borrowck_query").entered(); + let module = def.module(db); + let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block()); + let env = db.trait_environment_for_body(def); let mut res = vec![]; all_mir_bodies(db, def, |body| { + // FIXME(next-solver): Opaques. + let infcx = interner.infer_ctxt().build(TypingMode::Borrowck { + defining_opaque_types: SolverDefIds::new_from_iter(interner, []), + }); res.push(BorrowckResult { - mutability_of_locals: mutability_of_locals(db, &body), - moved_out_of_ref: moved_out_of_ref(db, &body), - partially_moved: partially_moved(db, &body), + mutability_of_locals: mutability_of_locals(&infcx, &body), + moved_out_of_ref: moved_out_of_ref(&infcx, &env, &body), + partially_moved: partially_moved(&infcx, &env, &body), borrow_regions: borrow_regions(db, &body), mir_body: body, }); @@ -108,51 +116,49 @@ pub fn borrowck_query<'db>( Ok(res.into()) } -fn make_fetch_closure_field( - db: &dyn HirDatabase, -) -> impl FnOnce(ClosureId, &Substitution, usize) -> Ty + '_ { - |c: ClosureId, subst: &Substitution, f: usize| { - let InternedClosure(def, _) = db.lookup_intern_closure(c.into()); +fn make_fetch_closure_field<'db>( + db: &'db dyn HirDatabase, +) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> { + |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| { + let InternedClosure(def, _) = db.lookup_intern_closure(c); let infer = db.infer(def); - let (captures, _) = infer.closure_info(c.into()); - let parent_subst = ClosureSubst(subst).parent_subst(db); + let (captures, _) = infer.closure_info(c); + let parent_subst = subst.split_closure_args_untupled().parent_args; let interner = DbInterner::new_with(db, None, None); - let parent_subst: crate::next_solver::GenericArgs<'_> = - parent_subst.to_nextsolver(interner); - captures - .get(f) - .expect("broken closure field") - .ty - .instantiate(interner, parent_subst) - .to_chalk(interner) + captures.get(f).expect("broken closure field").ty.instantiate(interner, parent_subst) } } -fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec { +fn moved_out_of_ref<'db>( + infcx: &InferCtxt<'db>, + env: &TraitEnvironment<'db>, + body: &MirBody<'db>, +) -> Vec> { + let db = infcx.interner.db; let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { - let mut ty: Ty = body.locals[p.local].ty.clone(); + let mut ty: Ty<'db> = body.locals[p.local].ty; let mut is_dereference_of_ref = false; for proj in p.projection.lookup(&body.projection_store) { if *proj == ProjectionElem::Deref && ty.as_reference().is_some() { is_dereference_of_ref = true; } ty = proj.projected_ty( + infcx, ty, - db, make_fetch_closure_field(db), body.owner.module(db).krate(), ); } if is_dereference_of_ref - && !ty.clone().is_copy(db, body.owner) - && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR) + && !infcx.type_is_copy_modulo_regions(env.env, ty) + && !ty.references_non_lt_error() { result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty }); } } - OperandKind::Constant(_) | OperandKind::Static(_) => (), + OperandKind::Constant { .. } | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -223,26 +229,29 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec result } -fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec { +fn partially_moved<'db>( + infcx: &InferCtxt<'db>, + env: &TraitEnvironment<'db>, + body: &MirBody<'db>, +) -> Vec> { + let db = infcx.interner.db; let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { - let mut ty: Ty = body.locals[p.local].ty.clone(); + let mut ty: Ty<'db> = body.locals[p.local].ty; for proj in p.projection.lookup(&body.projection_store) { ty = proj.projected_ty( + infcx, ty, - db, make_fetch_closure_field(db), body.owner.module(db).krate(), ); } - if !ty.clone().is_copy(db, body.owner) - && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR) - { + if !infcx.type_is_copy_modulo_regions(env.env, ty) && !ty.references_non_lt_error() { result.push(PartiallyMoved { span, ty, local: p.local }); } } - OperandKind::Constant(_) | OperandKind::Static(_) => (), + OperandKind::Constant { .. } | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -313,7 +322,7 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec result } -fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec { +fn borrow_regions<'db>(db: &'db dyn HirDatabase, body: &MirBody<'db>) -> Vec> { let mut borrows = FxHashMap::default(); for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -321,7 +330,7 @@ fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec { if let StatementKind::Assign(_, Rvalue::Ref(kind, p)) = &statement.kind { borrows .entry(p.local) - .and_modify(|it: &mut BorrowRegion| { + .and_modify(|it: &mut BorrowRegion<'db>| { it.places.push(statement.span); }) .or_insert_with(|| BorrowRegion { @@ -363,9 +372,14 @@ enum ProjectionCase { Indirect, } -fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase { +fn place_case<'db>( + infcx: &InferCtxt<'db>, + body: &MirBody<'db>, + lvalue: &Place<'db>, +) -> ProjectionCase { + let db = infcx.interner.db; let mut is_part_of = false; - let mut ty = body.locals[lvalue.local].ty.clone(); + let mut ty = body.locals[lvalue.local].ty; for proj in lvalue.projection.lookup(&body.projection_store).iter() { match proj { ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw @@ -379,7 +393,12 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio } ProjectionElem::OpaqueCast(_) => (), } - ty = proj.projected_ty(ty, db, make_fetch_closure_field(db), body.owner.module(db).krate()); + ty = proj.projected_ty( + infcx, + ty, + make_fetch_closure_field(db), + body.owner.module(db).krate(), + ); } if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct } } @@ -387,18 +406,18 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio /// Returns a map from basic blocks to the set of locals that might be ever initialized before /// the start of the block. Only `StorageDead` can remove something from this map, and we ignore /// `Uninit` and `drop` and similar after initialization. -fn ever_initialized_map( - db: &dyn HirDatabase, - body: &MirBody, -) -> ArenaMap> { - let mut result: ArenaMap> = +fn ever_initialized_map<'db>( + db: &'db dyn HirDatabase, + body: &MirBody<'db>, +) -> ArenaMap, ArenaMap, bool>> { + let mut result: ArenaMap, ArenaMap, bool>> = body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect(); - fn dfs( - db: &dyn HirDatabase, - body: &MirBody, - l: LocalId, - stack: &mut Vec, - result: &mut ArenaMap>, + fn dfs<'db>( + db: &'db dyn HirDatabase, + body: &MirBody<'db>, + l: LocalId<'db>, + stack: &mut Vec>, + result: &mut ArenaMap, ArenaMap, bool>>, ) { while let Some(b) = stack.pop() { let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs @@ -486,7 +505,11 @@ fn ever_initialized_map( result } -fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap) { +fn push_mut_span<'db>( + local: LocalId<'db>, + span: MirSpan, + result: &mut ArenaMap, MutabilityReason>, +) { match &mut result[local] { MutabilityReason::Mut { spans } => spans.push(span), it @ (MutabilityReason::Not | MutabilityReason::Unused) => { @@ -495,23 +518,27 @@ fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap) { +fn record_usage<'db>(local: LocalId<'db>, result: &mut ArenaMap, MutabilityReason>) { if let it @ MutabilityReason::Unused = &mut result[local] { *it = MutabilityReason::Not; }; } -fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap) { +fn record_usage_for_operand<'db>( + arg: &Operand<'db>, + result: &mut ArenaMap, MutabilityReason>, +) { if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind { record_usage(p.local, result); } } -fn mutability_of_locals( - db: &dyn HirDatabase, - body: &MirBody, -) -> ArenaMap { - let mut result: ArenaMap = +fn mutability_of_locals<'db>( + infcx: &InferCtxt<'db>, + body: &MirBody<'db>, +) -> ArenaMap, MutabilityReason> { + let db = infcx.interner.db; + let mut result: ArenaMap, MutabilityReason> = body.locals.iter().map(|it| (it.0, MutabilityReason::Unused)).collect(); let ever_init_maps = ever_initialized_map(db, body); @@ -520,7 +547,7 @@ fn mutability_of_locals( for statement in &block.statements { match &statement.kind { StatementKind::Assign(place, value) => { - match place_case(db, body, place) { + match place_case(infcx, body, place) { ProjectionCase::Direct => { if ever_init_map.get(place.local).copied().unwrap_or_default() { push_mut_span(place.local, statement.span, &mut result); @@ -569,7 +596,7 @@ fn mutability_of_locals( }, p, ) = value - && place_case(db, body, p) != ProjectionCase::Indirect + && place_case(infcx, body, p) != ProjectionCase::Indirect { push_mut_span(p.local, statement.span, &mut result); } 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 6e09cf9aeb882..444336ca3f9b2 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 @@ -2,14 +2,11 @@ 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 base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, - VariantId, - builtin_type::BuiltinType, + AdtId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, HasModule, ItemContainerId, + Lookup, StaticId, VariantId, expr_store::HygieneId, item_tree::FieldsShape, lang_item::LangItem, @@ -25,33 +22,33 @@ use rustc_apfloat::{ Float, ieee::{Half as f16, Quad as f128}, }; +use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; +use rustc_type_ir::{ + AliasTyKind, + inherent::{AdtDef, IntoKind, Region as _, 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, Interner, - MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, - consteval::{ConstEvalError, intern_const_scalar, try_const_usize}, - consteval_nextsolver, - db::{HirDatabase, InternedClosure}, + CallableDefId, ComplexMemoryMap, MemoryMap, TraitEnvironment, + consteval::{self, ConstEvalError, try_const_usize}, + db::{HirDatabase, InternedClosure, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, infer::PointerCast, layout::{Layout, LayoutError, RustcEnumVariantIdx}, method_resolution::{is_dyn_method, lookup_impl_const}, next_solver::{ - DbInterner, TypingMode, - infer::{DbInternerInferExt, InferCtxt}, - mapping::{ - ChalkToNextSolver, NextSolverToChalk, convert_args_for_result, convert_ty_for_result, - }, + Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, Region, + SolverDefId, Ty, TyKind, TypingMode, UnevaluatedConst, ValueConst, + infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, }, - static_lifetime, traits::FnTrait, - utils::{ClosureSubst, detect_variant_from_bytes}, + utils::detect_variant_from_bytes, }; use super::{ @@ -88,14 +85,14 @@ macro_rules! not_supported { #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct VTableMap<'db> { - ty_to_id: FxHashMap, usize>, - id_to_ty: Vec>, + ty_to_id: FxHashMap, usize>, + id_to_ty: Vec>, } 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: crate::next_solver::Ty<'db>) -> usize { + fn id(&mut self, ty: Ty<'db>) -> usize { if let Some(it) = self.ty_to_id.get(&ty) { return *it; } @@ -105,13 +102,13 @@ impl<'db> VTableMap<'db> { id } - pub(crate) fn ty(&self, id: usize) -> Result<'db, crate::next_solver::Ty<'db>> { + pub(crate) fn ty(&self, id: usize) -> Result<'db, Ty<'db>> { id.checked_sub(VTableMap::OFFSET) .and_then(|id| self.id_to_ty.get(id).copied()) .ok_or(MirEvalError::InvalidVTableId(id)) } - fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, crate::next_solver::Ty<'db>> { + fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, Ty<'db>> { let id = from_bytes!(usize, bytes); self.ty(id) } @@ -153,45 +150,45 @@ impl TlsData { } } -struct StackFrame { - locals: Locals, - destination: Option, +struct StackFrame<'db> { + locals: Locals<'db>, + destination: Option>, prev_stack_ptr: usize, span: (MirSpan, DefWithBodyId), } #[derive(Clone)] -enum MirOrDynIndex { - Mir(Arc), +enum MirOrDynIndex<'db> { + Mir(Arc>), Dyn(usize), } -pub struct Evaluator<'a> { - db: &'a dyn HirDatabase, - trait_env: Arc>, +pub struct Evaluator<'db> { + db: &'db dyn HirDatabase, + trait_env: Arc>, target_data_layout: Arc, stack: Vec, heap: Vec, - code_stack: Vec, + code_stack: Vec>, /// Stores the global location of the statics. We const evaluate every static first time we need it /// and see it's missing, then we add it to this to reuse. static_locations: FxHashMap, /// 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<'a>, + vtable_map: VTableMap<'db>, thread_local_storage: TlsData, random_state: oorandom::Rand64, stdout: Vec, stderr: Vec, - layout_cache: RefCell, Arc>>, - projected_ty_cache: RefCell>, + layout_cache: RefCell, Arc>>, + projected_ty_cache: RefCell, PlaceElem<'db>), Ty<'db>>>, not_special_fn_cache: RefCell>, - mir_or_dyn_index_cache: RefCell>, - /// Constantly dropping and creating `Locals` is very costly. We store + mir_or_dyn_index_cache: RefCell), MirOrDynIndex<'db>>>, + /// Constantly dropping and creating `Locals<'db>` is very costly. We store /// old locals that we normally want to drop here, to reuse their allocations /// later. - unused_locals_store: RefCell>>, + unused_locals_store: RefCell>>>, cached_ptr_size: usize, cached_fn_trait_func: Option, cached_fn_mut_trait_func: Option, @@ -205,8 +202,7 @@ pub struct Evaluator<'a> { stack_depth_limit: usize, /// Maximum count of bytes that heap and stack can grow memory_limit: usize, - interner: DbInterner<'a>, - infcx: InferCtxt<'a>, + infcx: InferCtxt<'db>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -225,9 +221,9 @@ struct Interval { } #[derive(Debug, Clone)] -struct IntervalAndTy { +struct IntervalAndTy<'db> { interval: Interval, - ty: Ty, + ty: Ty<'db>, } impl Interval { @@ -256,18 +252,18 @@ impl Interval { } } -impl IntervalAndTy { - fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> { +impl<'db> IntervalAndTy<'db> { + fn get<'a>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> { memory.read_memory(self.interval.addr, self.interval.size) } - fn new<'db>( + fn new( addr: Address, - ty: Ty, + ty: Ty<'db>, evaluator: &Evaluator<'db>, - locals: &Locals, - ) -> Result<'db, IntervalAndTy> { - let size = evaluator.size_of_sized(&ty, locals, "type of interval")?; + locals: &Locals<'db>, + ) -> Result<'db, IntervalAndTy<'db>> { + let size = evaluator.size_of_sized(ty, locals, "type of interval")?; Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) } } @@ -346,7 +342,7 @@ impl Address { #[derive(Clone, PartialEq, Eq)] pub enum MirEvalError<'db> { ConstEvalError(String, Box>), - LayoutError(LayoutError, Ty), + LayoutError(LayoutError, Ty<'db>), 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. @@ -354,20 +350,20 @@ pub enum MirEvalError<'db> { Panic(String), // FIXME: This should be folded into ConstEvalError? MirLowerError(FunctionId, MirLowerError<'db>), - MirLowerErrorForClosure(ClosureId, MirLowerError<'db>), - TypeIsUnsized(Ty, &'static str), + MirLowerErrorForClosure(InternedClosureId, MirLowerError<'db>), + TypeIsUnsized(Ty<'db>, &'static str), NotSupported(String), - InvalidConst(Const), + InvalidConst(Const<'db>), InFunction( Box>, - Vec<(Either, MirSpan, DefWithBodyId)>, + Vec<(Either, MirSpan, DefWithBodyId)>, ), ExecutionLimitExceeded, StackOverflow, /// FIXME: Fold this into InternalError InvalidVTableId(usize), /// ? - CoerceUnsizedError(Ty), + CoerceUnsizedError(Ty<'db>), /// These should not occur, usually indicates a bug in mir lowering. InternalError(Box), } @@ -443,13 +439,8 @@ impl MirEvalError<'_> { let function_name = db.function_signature(*func); let self_ = match func.lookup(db).container { ItemContainerId::ImplId(impl_id) => Some({ - let generics = crate::generics::generics(db, impl_id.into()); - let interner = DbInterner::new_with(db, None, None); - let substs = generics.placeholder_subst(db); - let args: crate::next_solver::GenericArgs<'_> = - substs.to_nextsolver(interner); db.impl_self_ty(impl_id) - .instantiate(interner, args) + .instantiate_identity() .display(db, display_target) .to_string() }), @@ -535,10 +526,7 @@ impl std::fmt::Debug for MirEvalError<'_> { Self::InternalError(arg0) => f.debug_tuple("InternalError").field(arg0).finish(), Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(), Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(), - Self::InvalidConst(arg0) => { - let data = &arg0.data(Interner); - f.debug_struct("InvalidConst").field("ty", &data.ty).field("value", &arg0).finish() - } + Self::InvalidConst(arg0) => f.debug_tuple("InvalidConst").field(&arg0).finish(), Self::InFunction(e, stack) => { f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish() } @@ -549,12 +537,12 @@ impl std::fmt::Debug for MirEvalError<'_> { type Result<'db, T> = std::result::Result>; #[derive(Debug, Default)] -struct DropFlags { - need_drop: FxHashSet, +struct DropFlags<'db> { + need_drop: FxHashSet>, } -impl DropFlags { - fn add_place(&mut self, p: Place, store: &ProjectionStore) { +impl<'db> DropFlags<'db> { + fn add_place(&mut self, p: Place<'db>, store: &ProjectionStore<'db>) { if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) { return; } @@ -562,7 +550,7 @@ impl DropFlags { self.need_drop.insert(p); } - fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool { + fn remove_place(&mut self, p: &Place<'db>, store: &ProjectionStore<'db>) -> bool { // FIXME: replace parents with parts if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(it)) { self.need_drop.remove(&parent); @@ -577,10 +565,10 @@ impl DropFlags { } #[derive(Debug)] -struct Locals { - ptr: ArenaMap, - body: Arc, - drop_flags: DropFlags, +struct Locals<'db> { + ptr: ArenaMap, Interval>, + body: Arc>, + drop_flags: DropFlags<'db>, } pub struct MirOutput { @@ -599,7 +587,7 @@ impl MirOutput { pub fn interpret_mir<'db>( db: &'db dyn HirDatabase, - body: Arc, + body: Arc>, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has @@ -607,10 +595,10 @@ pub fn interpret_mir<'db>( // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, trait_env: Option>>, -) -> Result<'db, (Result<'db, Const>, MirOutput)> { - let ty = body.locals[return_slot()].ty.clone(); +) -> Result<'db, (Result<'db, Const<'db>>, MirOutput)> { + let ty = body.locals[return_slot()].ty; let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?; - let it: Result<'db, Const> = (|| { + let it: Result<'db, Const<'db>> = (|| { if evaluator.ptr_size() != size_of::() { not_supported!("targets with different pointer size from host"); } @@ -618,7 +606,7 @@ pub fn interpret_mir<'db>( let bytes = interval.get(&evaluator)?; let mut memory_map = evaluator.create_memory_map( bytes, - &ty, + ty, &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() }, )?; let bytes = bytes.into(); @@ -629,13 +617,7 @@ pub fn interpret_mir<'db>( memory_map.vtable.shrink_to_fit(); MemoryMap::Complex(Box::new(memory_map)) }; - // 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(Const::new_valtree(evaluator.interner(), ty, bytes, memory_map)) })(); Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr })) } @@ -652,13 +634,15 @@ impl<'db> Evaluator<'db> { assert_placeholder_ty_is_unused: bool, trait_env: Option>>, ) -> Result<'db, Evaluator<'db>> { - let crate_id = owner.module(db).krate(); + let module = owner.module(db); + let crate_id = module.krate(); let target_data_layout = match db.target_data_layout(crate_id) { Ok(target_data_layout) => target_data_layout, Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)), }; let cached_ptr_size = target_data_layout.pointer_size().bytes_usize(); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_with(db, Some(crate_id), module.containing_block()); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); Ok(Evaluator { target_data_layout, stack: vec![0], @@ -692,21 +676,25 @@ impl<'db> Evaluator<'db> { cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| { x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once)) }), - interner, - infcx: interner.infer_ctxt().build(TypingMode::non_body_analysis()), + infcx, }) } - fn place_addr(&self, p: &Place, locals: &Locals) -> Result<'db, Address> { + #[inline] + fn interner(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn place_addr(&self, p: &Place<'db>, locals: &Locals<'db>) -> Result<'db, Address> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) } - fn place_interval(&self, p: &Place, locals: &Locals) -> Result<'db, Interval> { + fn place_interval(&self, p: &Place<'db>, locals: &Locals<'db>) -> Result<'db, Interval> { let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; Ok(Interval { addr: place_addr_and_ty.0, size: self.size_of_sized( - &place_addr_and_ty.1, + place_addr_and_ty.1, locals, "Type of place that we need its interval", )?, @@ -717,54 +705,46 @@ impl<'db> Evaluator<'db> { self.cached_ptr_size } - fn projected_ty(&self, ty: Ty, proj: PlaceElem) -> Ty { + fn projected_ty(&self, ty: Ty<'db>, proj: PlaceElem<'db>) -> Ty<'db> { let pair = (ty, proj); if let Some(r) = self.projected_ty_cache.borrow().get(&pair) { - return r.clone(); + return *r; } let (ty, proj) = pair; let r = proj.projected_ty( - ty.clone(), - self.db, + &self.infcx, + ty, |c, subst, f| { - let InternedClosure(def, _) = self.db.lookup_intern_closure(c.into()); + let InternedClosure(def, _) = self.db.lookup_intern_closure(c); let infer = self.db.infer(def); - let (captures, _) = infer.closure_info(c.into()); - let parent_subst = ClosureSubst(subst).parent_subst(self.db); + let (captures, _) = infer.closure_info(c); + let parent_subst = subst.split_closure_args_untupled().parent_args; captures .get(f) .expect("broken closure field") .ty - .instantiate( - self.interner, - <_ as ChalkToNextSolver<'db, crate::next_solver::GenericArgs<'db>>>::to_nextsolver( - &parent_subst, - self.interner, - ), - ) - .to_chalk(self.interner) + .instantiate(self.interner(), parent_subst) }, self.crate_id, ); - self.projected_ty_cache.borrow_mut().insert((ty, proj), r.clone()); + self.projected_ty_cache.borrow_mut().insert((ty, proj), r); r } fn place_addr_and_ty_and_metadata<'a>( &'a self, - p: &Place, - locals: &'a Locals, - ) -> Result<'db, (Address, Ty, Option)> { - let interner = DbInterner::new_with(self.db, None, None); + p: &Place<'db>, + locals: &'a Locals<'db>, + ) -> Result<'db, (Address, Ty<'db>, Option)> { let mut addr = locals.ptr[p.local].addr; - let mut ty: Ty = locals.body.locals[p.local].ty.clone(); + let mut ty: Ty<'db> = locals.body.locals[p.local].ty; let mut metadata: Option = None; // locals are always sized for proj in p.projection.lookup(&locals.body.projection_store) { - let prev_ty = ty.clone(); + let prev_ty = ty; ty = self.projected_ty(ty, proj.clone()); match proj { ProjectionElem::Deref => { - metadata = if self.size_align_of(&ty, locals)?.is_none() { + metadata = if self.size_align_of(ty, locals)?.is_none() { Some( Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() } .into(), @@ -782,12 +762,12 @@ impl<'db> Evaluator<'db> { ); metadata = None; // Result of index is always sized let ty_size = - self.size_of_sized(&ty, locals, "array inner type should be sized")?; + self.size_of_sized(ty, locals, "array inner type should be sized")?; addr = addr.offset(ty_size * offset); } &ProjectionElem::ConstantIndex { from_end, offset } => { let offset = if from_end { - let len = match prev_ty.kind(Interner) { + let len = match prev_ty.kind() { TyKind::Array(_, c) => match try_const_usize(self.db, c) { Some(it) => it as u64, None => { @@ -806,13 +786,13 @@ impl<'db> Evaluator<'db> { }; metadata = None; // Result of index is always sized let ty_size = - self.size_of_sized(&ty, locals, "array inner type should be sized")?; + self.size_of_sized(ty, locals, "array inner type should be sized")?; addr = addr.offset(ty_size * offset); } &ProjectionElem::Subslice { from, to } => { - let inner_ty = match &ty.kind(Interner) { - TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(), - _ => TyKind::Error.intern(Interner), + let inner_ty = match ty.kind() { + TyKind::Array(inner, _) | TyKind::Slice(inner) => inner, + _ => Ty::new_error(self.interner(), ErrorGuaranteed), }; metadata = match metadata { Some(it) => { @@ -824,23 +804,23 @@ impl<'db> Evaluator<'db> { None => None, }; let ty_size = - self.size_of_sized(&inner_ty, locals, "array inner type should be sized")?; + self.size_of_sized(inner_ty, locals, "array inner type should be sized")?; addr = addr.offset(ty_size * (from as usize)); } &ProjectionElem::ClosureField(f) => { - let layout = self.layout(prev_ty.to_nextsolver(interner))?; + let layout = self.layout(prev_ty)?; 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.to_nextsolver(interner))?; + let layout = self.layout(prev_ty)?; 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.to_nextsolver(interner))?; + let layout = self.layout(prev_ty)?; let variant_layout = match &layout.variants { Variants::Single { .. } | Variants::Empty => &layout, Variants::Multiple { variants, .. } => { @@ -862,7 +842,7 @@ impl<'db> Evaluator<'db> { .bytes_usize(); addr = addr.offset(offset); // Unsized field metadata is equal to the metadata of the struct - if self.size_align_of(&ty, locals)?.is_some() { + if self.size_align_of(ty, locals)?.is_some() { metadata = None; } } @@ -872,51 +852,47 @@ impl<'db> Evaluator<'db> { Ok((addr, ty, metadata)) } - fn layout(&self, ty: crate::next_solver::Ty<'db>) -> Result<'db, Arc> { + fn layout(&self, ty: Ty<'db>) -> Result<'db, Arc> { 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, self.trait_env.clone()) - .map_err(|e| MirEvalError::LayoutError(e, convert_ty_for_result(interner, ty)))?; + .map_err(|e| MirEvalError::LayoutError(e, ty))?; self.layout_cache.borrow_mut().insert(ty, r.clone()); Ok(r) } - fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<'db, Arc> { - 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 layout_adt(&self, adt: AdtId, subst: GenericArgs<'db>) -> Result<'db, Arc> { + self.layout(Ty::new_adt(self.interner(), adt, subst)) } - fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<'db, Ty> { + fn place_ty<'a>(&'a self, p: &Place<'db>, locals: &'a Locals<'db>) -> Result<'db, Ty<'db>> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty> { + fn operand_ty(&self, o: &Operand<'db>, locals: &Locals<'db>) -> Result<'db, Ty<'db>> { Ok(match &o.kind { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, - OperandKind::Constant(c) => c.data(Interner).ty.clone(), + OperandKind::Constant { konst: _, ty } => *ty, &OperandKind::Static(s) => { - let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr] - .to_chalk(self.interner); - TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner) + let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr]; + Ty::new_ref( + self.interner(), + Region::new_static(self.interner()), + ty, + Mutability::Not, + ) } }) } fn operand_ty_and_eval( &mut self, - o: &Operand, - locals: &mut Locals, - ) -> Result<'db, IntervalAndTy> { + o: &Operand<'db>, + locals: &mut Locals<'db>, + ) -> Result<'db, IntervalAndTy<'db>> { Ok(IntervalAndTy { interval: self.eval_operand(o, locals)?, ty: self.operand_ty(o, locals)?, @@ -925,7 +901,7 @@ impl<'db> Evaluator<'db> { fn interpret_mir( &mut self, - body: Arc, + body: Arc>, args: impl Iterator, ) -> Result<'db, Interval> { if let Some(it) = self.stack_depth_limit.checked_sub(1) { @@ -989,8 +965,8 @@ impl<'db> Evaluator<'db> { .iter() .map(|it| self.operand_ty_and_eval(it, locals)) .collect::>>()?; - let stack_frame = match &fn_ty.kind(Interner) { - TyKind::Function(_) => { + let stack_frame = match fn_ty.kind() { + TyKind::FnPtr(..) => { let bytes = self.eval_operand(func, locals)?; self.exec_fn_pointer( bytes, @@ -1002,7 +978,7 @@ impl<'db> Evaluator<'db> { )? } TyKind::FnDef(def, generic_args) => self.exec_fn_def( - CallableDefId::from_chalk(self.db, *def), + def.0, generic_args, destination_interval, &args, @@ -1089,8 +1065,8 @@ impl<'db> Evaluator<'db> { fn fill_locals_for_body( &mut self, - body: &MirBody, - locals: &mut Locals, + body: &MirBody<'db>, + locals: &mut Locals<'db>, args: impl Iterator, ) -> Result<'db, ()> { let mut remain_args = body.param_locals.len(); @@ -1113,9 +1089,9 @@ impl<'db> Evaluator<'db> { fn create_locals_for_body( &mut self, - body: &Arc, + body: &Arc>, destination: Option, - ) -> Result<'db, (Locals, usize)> { + ) -> Result<'db, (Locals<'db>, usize)> { let mut locals = match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() { None => Locals { @@ -1139,7 +1115,7 @@ impl<'db> Evaluator<'db> { continue; } let (size, align) = self.size_align_of_sized( - &it.ty, + it.ty, &locals, "no unsized local in extending stack", )?; @@ -1162,8 +1138,11 @@ impl<'db> Evaluator<'db> { Ok((locals, prev_stack_pointer)) } - fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result<'db, IntervalOrOwned> { - let interner = DbInterner::new_with(self.db, None, None); + fn eval_rvalue( + &mut self, + r: &Rvalue<'db>, + locals: &mut Locals<'db>, + ) -> Result<'db, IntervalOrOwned> { use IntervalOrOwned::*; Ok(match r { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), @@ -1189,33 +1168,33 @@ impl<'db> Evaluator<'db> { Rvalue::UnaryOp(op, val) => { let mut c = self.eval_operand(val, locals)?.get(self)?; let mut ty = self.operand_ty(val, locals)?; - while let TyKind::Ref(_, _, z) = ty.kind(Interner) { - ty = z.clone(); - let size = self.size_of_sized(&ty, locals, "operand of unary op")?; + while let TyKind::Ref(_, z, _) = ty.kind() { + ty = z; + let size = self.size_of_sized(ty, locals, "operand of unary op")?; c = self.read_memory(Address::from_bytes(c)?, size)?; } - if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { + if let TyKind::Float(f) = ty.kind() { match f { - chalk_ir::FloatTy::F16 => { + rustc_type_ir::FloatTy::F16 => { let c = -from_bytes!(f16, u16, c); Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into()) } - chalk_ir::FloatTy::F32 => { + rustc_type_ir::FloatTy::F32 => { let c = -from_bytes!(f32, c); Owned(c.to_le_bytes().into()) } - chalk_ir::FloatTy::F64 => { + rustc_type_ir::FloatTy::F64 => { let c = -from_bytes!(f64, c); Owned(c.to_le_bytes().into()) } - chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F128 => { let c = -from_bytes!(f128, u128, c); Owned(c.to_bits().to_le_bytes().into()) } } } else { let mut c = c.to_vec(); - if ty.as_builtin() == Some(BuiltinType::Bool) { + if matches!(ty.kind(), TyKind::Bool) { c[0] = 1 - c[0]; } else { match op { @@ -1241,8 +1220,8 @@ impl<'db> Evaluator<'db> { let mut lc = lc.get(self)?; let mut rc = rc.get(self)?; let mut ty = self.operand_ty(lhs, locals)?; - while let TyKind::Ref(_, _, z) = ty.kind(Interner) { - ty = z.clone(); + while let TyKind::Ref(_, z, _) = ty.kind() { + ty = z; let size = if ty.is_str() { if *op != BinOp::Eq { never!("Only eq is builtin for `str`"); @@ -1258,14 +1237,14 @@ impl<'db> Evaluator<'db> { rc = self.read_memory(Address::from_bytes(rc)?, ls)?; break 'binary_op Owned(vec![u8::from(lc == rc)]); } else { - self.size_of_sized(&ty, locals, "operand of binary op")? + self.size_of_sized(ty, locals, "operand of binary op")? }; lc = self.read_memory(Address::from_bytes(lc)?, size)?; rc = self.read_memory(Address::from_bytes(rc)?, size)?; } - if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { + if let TyKind::Float(f) = ty.kind() { match f { - chalk_ir::FloatTy::F16 => { + rustc_type_ir::FloatTy::F16 => { let l = from_bytes!(f16, u16, lc); let r = from_bytes!(f16, u16, rc); match op { @@ -1298,7 +1277,7 @@ impl<'db> Evaluator<'db> { ), } } - chalk_ir::FloatTy::F32 => { + rustc_type_ir::FloatTy::F32 => { let l = from_bytes!(f32, lc); let r = from_bytes!(f32, rc); match op { @@ -1326,7 +1305,7 @@ impl<'db> Evaluator<'db> { ), } } - chalk_ir::FloatTy::F64 => { + rustc_type_ir::FloatTy::F64 => { let l = from_bytes!(f64, lc); let r = from_bytes!(f64, rc); match op { @@ -1354,7 +1333,7 @@ impl<'db> Evaluator<'db> { ), } } - chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F128 => { let l = from_bytes!(f128, u128, lc); let r = from_bytes!(f128, u128, rc); match op { @@ -1384,7 +1363,7 @@ impl<'db> Evaluator<'db> { } } } else { - let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); + let is_signed = matches!(ty.kind(), TyKind::Int(_)); let l128 = IntValue::from_bytes(lc, is_signed); let r128 = IntValue::from_bytes(rc, is_signed); match op { @@ -1455,7 +1434,7 @@ impl<'db> Evaluator<'db> { Owned(result.to_le_bytes().to_vec()) } Rvalue::Repeat(it, len) => { - let len = match try_const_usize(self.db, len) { + let len = match try_const_usize(self.db, *len) { Some(it) => it as usize, None => not_supported!("non evaluatable array len in repeat Rvalue"), }; @@ -1465,7 +1444,7 @@ impl<'db> Evaluator<'db> { } Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"), Rvalue::ShallowInitBoxWithAlloc(ty) => { - let Some((size, align)) = self.size_align_of(ty, locals)? else { + let Some((size, align)) = self.size_align_of(*ty, locals)? else { not_supported!("unsized box initialization"); }; let addr = self.heap_allocate(size, align)?; @@ -1487,7 +1466,7 @@ impl<'db> Evaluator<'db> { Owned(r) } AggregateKind::Tuple(ty) => { - let layout = self.layout(ty.to_nextsolver(interner))?; + let layout = self.layout(*ty)?; Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1496,8 +1475,10 @@ impl<'db> Evaluator<'db> { )?) } AggregateKind::Union(it, f) => { - let layout = - self.layout_adt((*it).into(), Substitution::empty(Interner))?; + let layout = self.layout_adt( + (*it).into(), + GenericArgs::new_from_iter(self.interner(), []), + )?; let offset = layout .fields .offset(u32::from(f.local_id.into_raw()) as usize) @@ -1509,7 +1490,7 @@ impl<'db> Evaluator<'db> { } AggregateKind::Adt(it, subst) => { let (size, variant_layout, tag) = - self.layout_of_variant(*it, subst.clone(), locals)?; + self.layout_of_variant(*it, *subst, locals)?; Owned(self.construct_with_layout( size, &variant_layout, @@ -1518,7 +1499,7 @@ impl<'db> Evaluator<'db> { )?) } AggregateKind::Closure(ty) => { - let layout = self.layout(ty.to_nextsolver(interner))?; + let layout = self.layout(*ty)?; Owned(self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1532,11 +1513,7 @@ impl<'db> Evaluator<'db> { CastKind::PointerCoercion(cast) => match cast { PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => { let current_ty = self.operand_ty(operand, locals)?; - 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); + if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = current_ty.kind() { let id = self.vtable_map.id(current_ty); let ptr_size = self.ptr_size(); Owned(id.to_le_bytes()[0..ptr_size].to_vec()) @@ -1549,7 +1526,7 @@ impl<'db> Evaluator<'db> { PointerCast::Unsize => { let current_ty = self.operand_ty(operand, locals)?; let addr = self.eval_operand(operand, locals)?; - self.coerce_unsized(addr, ¤t_ty, target_ty)? + self.coerce_unsized(addr, current_ty, *target_ty)? } PointerCast::MutToConstPointer | PointerCast::UnsafeFnPointer => { // This is no-op @@ -1566,40 +1543,34 @@ impl<'db> Evaluator<'db> { | CastKind::PointerExposeAddress | CastKind::PointerFromExposedAddress => { let current_ty = self.operand_ty(operand, locals)?; - let is_signed = matches!( - current_ty.kind(Interner), - TyKind::Scalar(chalk_ir::Scalar::Int(_)) - ); + let is_signed = matches!(current_ty.kind(), TyKind::Int(_)); let current = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed); let dest_size = - self.size_of_sized(target_ty, locals, "destination of int to int cast")?; + self.size_of_sized(*target_ty, locals, "destination of int to int cast")?; Owned(current[0..dest_size].to_vec()) } CastKind::FloatToInt => { let ty = self.operand_ty(operand, locals)?; - let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else { + let TyKind::Float(ty) = ty.kind() else { not_supported!("invalid float to int cast"); }; let value = self.eval_operand(operand, locals)?.get(self)?; let value = match ty { - chalk_ir::FloatTy::F32 => { + rustc_type_ir::FloatTy::F32 => { let value = value.try_into().unwrap(); f32::from_le_bytes(value) as f64 } - chalk_ir::FloatTy::F64 => { + rustc_type_ir::FloatTy::F64 => { let value = value.try_into().unwrap(); f64::from_le_bytes(value) } - chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => { not_supported!("unstable floating point type f16 and f128"); } }; - let is_signed = matches!( - target_ty.kind(Interner), - TyKind::Scalar(chalk_ir::Scalar::Int(_)) - ); + let is_signed = matches!(target_ty.kind(), TyKind::Int(_)); let dest_size = - self.size_of_sized(target_ty, locals, "destination of float to int cast")?; + self.size_of_sized(*target_ty, locals, "destination of float to int cast")?; let dest_bits = dest_size * 8; let (max, min) = if dest_bits == 128 { (i128::MAX, i128::MIN) @@ -1615,53 +1586,46 @@ impl<'db> Evaluator<'db> { } CastKind::FloatToFloat => { let ty = self.operand_ty(operand, locals)?; - let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else { + let TyKind::Float(ty) = ty.kind() else { not_supported!("invalid float to int cast"); }; let value = self.eval_operand(operand, locals)?.get(self)?; let value = match ty { - chalk_ir::FloatTy::F32 => { + rustc_type_ir::FloatTy::F32 => { let value = value.try_into().unwrap(); f32::from_le_bytes(value) as f64 } - chalk_ir::FloatTy::F64 => { + rustc_type_ir::FloatTy::F64 => { let value = value.try_into().unwrap(); f64::from_le_bytes(value) } - chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => { not_supported!("unstable floating point type f16 and f128"); } }; - let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) = - target_ty.kind(Interner) - else { + let TyKind::Float(target_ty) = target_ty.kind() else { not_supported!("invalid float to float cast"); }; match target_ty { - chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()), - chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()), - chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()), + rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()), + rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => { not_supported!("unstable floating point type f16 and f128"); } } } CastKind::IntToFloat => { let current_ty = self.operand_ty(operand, locals)?; - let is_signed = matches!( - current_ty.kind(Interner), - TyKind::Scalar(chalk_ir::Scalar::Int(_)) - ); + let is_signed = matches!(current_ty.kind(), TyKind::Int(_)); let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed); let value = i128::from_le_bytes(value); - let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) = - target_ty.kind(Interner) - else { + let TyKind::Float(target_ty) = target_ty.kind() else { not_supported!("invalid int to float cast"); }; match target_ty { - chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()), - chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()), - chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => { + rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()), + rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()), + rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => { not_supported!("unstable floating point type f16 and f128"); } } @@ -1675,10 +1639,12 @@ impl<'db> Evaluator<'db> { }) } - fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result<'db, i128> { - 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 { + fn compute_discriminant(&self, ty: Ty<'db>, bytes: &[u8]) -> Result<'db, i128> { + let layout = self.layout(ty)?; + let TyKind::Adt(adt_def, _) = ty.kind() else { + return Ok(0); + }; + let AdtId::EnumId(e) = adt_def.def_id().0 else { return Ok(0); }; match &layout.variants { @@ -1720,35 +1686,35 @@ impl<'db> Evaluator<'db> { fn coerce_unsized_look_through_fields( &self, - ty: &Ty, - goal: impl Fn(&TyKind) -> Option, + ty: Ty<'db>, + goal: impl Fn(TyKind<'db>) -> Option, ) -> Result<'db, T> { - let kind = ty.kind(Interner); + let kind = ty.kind(); if let Some(it) = goal(kind) { return Ok(it); } - if let TyKind::Adt(id, subst) = kind - && let AdtId::StructId(struct_id) = id.0 + if let TyKind::Adt(adt_ef, subst) = kind + && let AdtId::StructId(struct_id) = adt_ef.def_id().0 { - let field_types = self.db.field_types(struct_id.into()); + let field_types = self.db.field_types_ns(struct_id.into()); if let Some(ty) = - field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst)) + field_types.iter().last().map(|it| it.1.instantiate(self.interner(), subst)) { - return self.coerce_unsized_look_through_fields(&ty, goal); + return self.coerce_unsized_look_through_fields(ty, goal); } } - Err(MirEvalError::CoerceUnsizedError(ty.clone())) + Err(MirEvalError::CoerceUnsizedError(ty)) } fn coerce_unsized( &mut self, addr: Interval, - current_ty: &Ty, - target_ty: &Ty, + current_ty: Ty<'db>, + target_ty: Ty<'db>, ) -> Result<'db, IntervalOrOwned> { - fn for_ptr(it: &TyKind) -> Option { + fn for_ptr<'db>(it: TyKind<'db>) -> Option> { match it { - TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()), + TyKind::RawPtr(ty, _) | TyKind::Ref(_, ty, _) => Some(ty), _ => None, } } @@ -1761,15 +1727,15 @@ impl<'db> Evaluator<'db> { /// Adds metadata to the address and create the fat pointer result of the unsizing operation. fn unsizing_ptr_from_addr( &mut self, - target_ty: Ty, - current_ty: Ty, + target_ty: Ty<'db>, + current_ty: Ty<'db>, addr: Interval, ) -> Result<'db, IntervalOrOwned> { use IntervalOrOwned::*; - Ok(match &target_ty.kind(Interner) { - TyKind::Slice(_) => match ¤t_ty.kind(Interner) { + Ok(match &target_ty.kind() { + TyKind::Slice(_) => match ¤t_ty.kind() { TyKind::Array(_, size) => { - let len = match try_const_usize(self.db, size) { + let len = match try_const_usize(self.db, *size) { None => { not_supported!("unevaluatble len of array in coerce unsized") } @@ -1785,9 +1751,7 @@ impl<'db> Evaluator<'db> { not_supported!("slice unsizing from non array type {t:?}") } }, - TyKind::Dyn(_) => { - let interner = DbInterner::new_with(self.db, None, None); - let current_ty = current_ty.to_nextsolver(interner); + TyKind::Dynamic(..) => { let vtable = self.vtable_map.id(current_ty); let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; @@ -1795,12 +1759,14 @@ impl<'db> Evaluator<'db> { r.extend(vtable.to_le_bytes()); Owned(r) } - TyKind::Adt(id, target_subst) => match ¤t_ty.kind(Interner) { - TyKind::Adt(current_id, current_subst) => { + TyKind::Adt(adt_def, target_subst) => match ¤t_ty.kind() { + TyKind::Adt(current_adt_def, current_subst) => { + let id = adt_def.def_id().0; + let current_id = current_adt_def.def_id().0; if id != current_id { not_supported!("unsizing struct with different type"); } - let id = match id.0 { + let id = match id { AdtId::StructId(s) => s, AdtId::UnionId(_) => not_supported!("unsizing unions"), AdtId::EnumId(_) => not_supported!("unsizing enums"), @@ -1809,12 +1775,10 @@ impl<'db> Evaluator<'db> { else { not_supported!("unsizing struct without field"); }; - let target_last_field = self.db.field_types(id.into())[last_field] - .clone() - .substitute(Interner, target_subst); - let current_last_field = self.db.field_types(id.into())[last_field] - .clone() - .substitute(Interner, current_subst); + let target_last_field = self.db.field_types_ns(id.into())[last_field] + .instantiate(self.interner(), target_subst); + let current_last_field = self.db.field_types_ns(id.into())[last_field] + .instantiate(self.interner(), current_subst); return self.unsizing_ptr_from_addr( target_last_field, current_last_field, @@ -1830,10 +1794,9 @@ impl<'db> Evaluator<'db> { fn layout_of_variant( &mut self, it: VariantId, - subst: Substitution, - locals: &Locals, + subst: GenericArgs<'db>, + locals: &Locals<'db>, ) -> Result<'db, (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 @@ -1843,11 +1806,7 @@ impl<'db> Evaluator<'db> { // 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(crate::next_solver::Ty::new_empty_tuple(interner))?, - Some((0, 16, i)), - )); + return Ok((16, self.layout(Ty::new_empty_tuple(self.interner()))?, Some((0, 16, i)))); } let layout = self.layout_adt(adt, subst)?; Ok(match &layout.variants { @@ -1930,7 +1889,11 @@ impl<'db> Evaluator<'db> { Ok(result) } - fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<'db, Interval> { + fn eval_operand( + &mut self, + it: &Operand<'db>, + locals: &mut Locals<'db>, + ) -> Result<'db, Interval> { Ok(match &it.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p, &locals.body.projection_store); @@ -1940,32 +1903,30 @@ impl<'db> Evaluator<'db> { let addr = self.eval_static(*st, locals)?; Interval::new(addr, self.ptr_size()) } - OperandKind::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, + OperandKind::Constant { konst, .. } => self.allocate_const_in_heap(locals, *konst)?, }) } #[allow(clippy::double_parens)] - fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result<'db, Interval> { - let interner = self.interner; - let ConstData { ty, value: chalk_ir::ConstValue::Concrete(c) } = &konst.data(Interner) - else { - not_supported!("evaluating non concrete constant"); - }; + fn allocate_const_in_heap( + &mut self, + locals: &Locals<'db>, + konst: Const<'db>, + ) -> Result<'db, Interval> { let result_owner; - let (v, memory_map) = match &c.interned { - ConstScalar::Bytes(v, mm) => (v, mm), - ConstScalar::UnevaluatedConst(const_id, subst) => 'b: { - let mut const_id = *const_id; - let mut subst = subst.clone(); + let value = match konst.kind() { + ConstKind::Value(value) => value, + ConstKind::Unevaluated(UnevaluatedConst { def: const_id, args: subst }) => 'b: { + let mut const_id = match const_id { + SolverDefId::ConstId(it) => GeneralConstId::from(it), + SolverDefId::StaticId(it) => it.into(), + _ => unreachable!("unevaluated consts should be consts or statics"), + }; + let mut subst = subst; if let hir_def::GeneralConstId::ConstId(c) = const_id { - let (c, s) = lookup_impl_const( - self.interner, - self.trait_env.clone(), - c, - subst.to_nextsolver(self.interner), - ); + let (c, s) = lookup_impl_const(&self.infcx, self.trait_env.clone(), c, subst); const_id = hir_def::GeneralConstId::ConstId(c); - subst = s.to_chalk(self.interner); + subst = s; } result_owner = self .db @@ -1974,15 +1935,15 @@ impl<'db> Evaluator<'db> { let name = const_id.name(self.db); MirEvalError::ConstEvalError(name, Box::new(e)) })?; - if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value - && let ConstScalar::Bytes(v, mm) = &c.interned - { - break 'b (v, mm); + if let ConstKind::Value(value) = result_owner.kind() { + break 'b value; } not_supported!("unevaluatable constant"); } - ConstScalar::Unknown => not_supported!("evaluating unknown const"), + _ => not_supported!("evaluating unknown const"), }; + let ValueConst { ty, value } = value; + let ConstBytes { memory: v, memory_map } = value.inner(); let patch_map = memory_map.transform_addresses(|b, align| { let addr = self.heap_allocate(b.len(), align)?; self.write_memory(addr, b)?; @@ -1996,7 +1957,7 @@ impl<'db> Evaluator<'db> { } else if size < 16 && v.len() == 16 { Cow::Borrowed(&v[0..size]) } else { - return Err(MirEvalError::InvalidConst(konst.clone())); + return Err(MirEvalError::InvalidConst(konst)); } } else { Cow::Borrowed(v) @@ -2012,17 +1973,17 @@ impl<'db> Evaluator<'db> { MemoryMap::Complex(cm) => cm.vtable.ty_of_bytes(bytes), }, addr, - ty.to_nextsolver(interner), + ty, locals, )?; Ok(Interval::new(addr, size)) } - fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<'db, Interval> { + fn eval_place(&mut self, p: &Place<'db>, locals: &Locals<'db>) -> Result<'db, Interval> { let addr = self.place_addr(p, locals)?; Ok(Interval::new( addr, - self.size_of_sized(&self.place_ty(p, locals)?, locals, "type of this place")?, + self.size_of_sized(self.place_ty(p, locals)?, locals, "type of this place")?, )) } @@ -2118,9 +2079,12 @@ impl<'db> Evaluator<'db> { Ok(()) } - fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<'db, Option<(usize, usize)>> { - let interner = DbInterner::new_with(self.db, None, None); - if let Some(layout) = self.layout_cache.borrow().get(&ty.to_nextsolver(interner)) { + fn size_align_of( + &self, + ty: Ty<'db>, + locals: &Locals<'db>, + ) -> Result<'db, Option<(usize, usize)>> { + if let Some(layout) = self.layout_cache.borrow().get(&ty) { return Ok(layout .is_sized() .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))); @@ -2133,7 +2097,7 @@ impl<'db> Evaluator<'db> { // infinite sized type errors) we use a dummy size return Ok(Some((16, 16))); } - let layout = self.layout(ty.to_nextsolver(interner)); + let layout = self.layout(ty); if self.assert_placeholder_ty_is_unused && matches!(layout, Err(MirEvalError::LayoutError(LayoutError::HasPlaceholder, _))) { @@ -2145,10 +2109,15 @@ impl<'db> Evaluator<'db> { /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` - fn size_of_sized(&self, ty: &Ty, locals: &Locals, what: &'static str) -> Result<'db, usize> { + fn size_of_sized( + &self, + ty: Ty<'db>, + locals: &Locals<'db>, + what: &'static str, + ) -> Result<'db, usize> { match self.size_align_of(ty, locals)? { Some(it) => Ok(it.0), - None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), + None => Err(MirEvalError::TypeIsUnsized(ty, what)), } } @@ -2156,13 +2125,13 @@ impl<'db> Evaluator<'db> { /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` fn size_align_of_sized( &self, - ty: &Ty, - locals: &Locals, + ty: Ty<'db>, + locals: &Locals<'db>, what: &'static str, ) -> Result<'db, (usize, usize)> { match self.size_align_of(ty, locals)? { Some(it) => Ok(it), - None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), + None => Err(MirEvalError::TypeIsUnsized(ty, what)), } } @@ -2197,23 +2166,22 @@ impl<'db> Evaluator<'db> { fn create_memory_map( &self, bytes: &[u8], - ty: &Ty, - locals: &Locals, + ty: Ty<'db>, + locals: &Locals<'db>, ) -> Result<'db, ComplexMemoryMap<'db>> { fn rec<'db>( this: &Evaluator<'db>, bytes: &[u8], - ty: &Ty, - locals: &Locals, + ty: Ty<'db>, + locals: &Locals<'db>, mm: &mut ComplexMemoryMap<'db>, stack_depth_limit: usize, ) -> Result<'db, ()> { - let interner = DbInterner::new_with(this.db, None, None); if stack_depth_limit.checked_sub(1).is_none() { return Err(MirEvalError::StackOverflow); } - match ty.kind(Interner) { - TyKind::Ref(_, _, t) => { + match ty.kind() { + TyKind::Ref(_, t, _) => { let size = this.size_align_of(t, locals)?; match size { Some((size, _)) => { @@ -2226,29 +2194,28 @@ impl<'db> Evaluator<'db> { None => { let mut check_inner = None; let (addr, meta) = bytes.split_at(bytes.len() / 2); - let element_size = match t.kind(Interner) { + let element_size = match t.kind() { TyKind::Str => 1, TyKind::Slice(t) => { - check_inner = Some(t.clone()); + check_inner = Some(t); this.size_of_sized(t, locals, "slice inner type")? } - TyKind::Dyn(_) => { + TyKind::Dynamic(..) => { let t = this.vtable_map.ty_of_bytes(meta)?; - let t = convert_ty_for_result(interner, t); - check_inner = Some(t.clone()); - this.size_of_sized(&t, locals, "dyn concrete type")? + check_inner = Some(t); + this.size_of_sized(t, locals, "dyn concrete type")? } _ => return Ok(()), }; - let count = match t.kind(Interner) { - TyKind::Dyn(_) => 1, + let count = match t.kind() { + TyKind::Dynamic(..) => 1, _ => from_bytes!(usize, meta), }; let size = element_size * count; 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( @@ -2282,12 +2249,11 @@ impl<'db> Evaluator<'db> { )?; } } - TyKind::Tuple(_, subst) => { - 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 + TyKind::Tuple(subst) => { + let layout = this.layout(ty)?; + for (id, ty) in subst.iter().enumerate() { let offset = layout.fields.offset(id).bytes_usize(); - let size = this.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); + let size = this.layout(ty)?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2298,18 +2264,18 @@ impl<'db> Evaluator<'db> { )?; } } - TyKind::Adt(adt, subst) => match adt.0 { + TyKind::Adt(adt, subst) => match adt.def_id().0 { AdtId::StructId(s) => { let data = s.fields(this.db); - let layout = this.layout(ty.to_nextsolver(interner))?; - let field_types = this.db.field_types(s.into()); + let layout = this.layout(ty)?; + let field_types = this.db.field_types_ns(s.into()); for (f, _) in data.fields().iter() { let offset = layout .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.to_nextsolver(interner))?.size.bytes_usize(); + let ty = field_types[f].instantiate(this.interner(), subst); + let size = this.layout(ty)?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2321,7 +2287,7 @@ impl<'db> Evaluator<'db> { } } AdtId::EnumId(e) => { - let layout = this.layout(ty.to_nextsolver(interner))?; + let layout = this.layout(ty)?; if let Some((v, l)) = detect_variant_from_bytes( &layout, this.db, @@ -2330,13 +2296,12 @@ impl<'db> Evaluator<'db> { e, ) { let data = v.fields(this.db); - let field_types = this.db.field_types(v.into()); + let field_types = this.db.field_types_ns(v.into()); for (f, _) in data.fields().iter() { 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.to_nextsolver(interner))?.size.bytes_usize(); + let ty = field_types[f].instantiate(this.interner(), subst); + let size = this.layout(ty)?.size.bytes_usize(); rec( this, &bytes[offset..offset + size], @@ -2350,9 +2315,17 @@ impl<'db> Evaluator<'db> { } AdtId::UnionId(_) => (), }, - TyKind::Alias(AliasTy::Projection(proj)) => { - let ty = this.db.normalize_projection(proj.clone(), this.trait_env.clone()); - rec(this, bytes, &ty, locals, mm, stack_depth_limit - 1)?; + TyKind::Alias(AliasTyKind::Projection, _) => { + let mut ocx = ObligationCtxt::new(&this.infcx); + let ty = ocx + .structurally_normalize_ty( + &ObligationCause::dummy(), + this.trait_env.env, + ty, + ) + .map_err(|_| MirEvalError::NotSupported("couldn't normalize".to_owned()))?; + + rec(this, bytes, ty, locals, mm, stack_depth_limit - 1)?; } _ => (), } @@ -2366,23 +2339,18 @@ impl<'db> Evaluator<'db> { fn patch_addresses( &mut self, patch_map: &FxHashMap, - ty_of_bytes: impl Fn(&[u8]) -> Result<'db, crate::next_solver::Ty<'db>> + Copy, + ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy, addr: Address, - ty: crate::next_solver::Ty<'db>, - locals: &Locals, + ty: Ty<'db>, + locals: &Locals<'db>, ) -> Result<'db, ()> { - 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( - &convert_ty_for_result(interner, ty), - locals, - "value to patch address", - )?; + let my_size = self.size_of_sized(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)?; + let size = self.size_align_of(t, locals)?; match size { Some(_) => { let current = from_bytes!(usize, self.read_memory(addr, my_size)?); @@ -2407,7 +2375,7 @@ impl<'db> Evaluator<'db> { 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); + let ty = ty.instantiate(self.interner(), args); self.patch_addresses( patch_map, ty_of_bytes, @@ -2428,7 +2396,7 @@ impl<'db> Evaluator<'db> { ) { for (i, (_, ty)) in self.db.field_types_ns(ev.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); - let ty = ty.instantiate(interner, args); + let ty = ty.instantiate(self.interner(), args); self.patch_addresses( patch_map, ty_of_bytes, @@ -2447,15 +2415,11 @@ impl<'db> Evaluator<'db> { } } TyKind::Array(inner, len) => { - let len = match consteval_nextsolver::try_const_usize(self.db, len) { + let len = match consteval::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( - &convert_ty_for_result(interner, inner), - locals, - "inner of array", - )?; + let size = self.size_of_sized(inner, locals, "inner of array")?; for i in 0..len { self.patch_addresses( patch_map, @@ -2498,29 +2462,22 @@ impl<'db> Evaluator<'db> { &mut self, bytes: Interval, destination: Interval, - args: &[IntervalAndTy], - locals: &Locals, - target_bb: Option, + args: &[IntervalAndTy<'db>], + locals: &Locals<'db>, + target_bb: Option>, span: MirSpan, - ) -> Result<'db, Option> { + ) -> Result<'db, Option>> { let id = from_bytes!(usize, bytes.get(self)?); 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.0, - &convert_args_for_result(interner, generic_args.as_slice()), - destination, - args, - locals, - target_bb, - span, - ), + TyKind::FnDef(def, generic_args) => { + self.exec_fn_def(def.0, generic_args, destination, args, locals, target_bb, span) + } TyKind::Closure(id, generic_args) => self.exec_closure( - id.0.into(), + id.0, bytes.slice(0..0), - &convert_args_for_result(interner, generic_args.as_slice()), + generic_args, destination, args, locals, @@ -2532,21 +2489,17 @@ impl<'db> Evaluator<'db> { fn exec_closure( &mut self, - closure: ClosureId, + closure: InternedClosureId, closure_data: Interval, - generic_args: &Substitution, + generic_args: GenericArgs<'db>, destination: Interval, - args: &[IntervalAndTy], - locals: &Locals, + args: &[IntervalAndTy<'db>], + locals: &Locals<'db>, span: MirSpan, - ) -> Result<'db, Option> { + ) -> Result<'db, Option>> { let mir_body = self .db - .monomorphized_mir_body_for_closure( - closure.into(), - generic_args.clone(), - self.trait_env.clone(), - ) + .monomorphized_mir_body_for_closure(closure, generic_args, self.trait_env.clone()) .map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?; let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some() { @@ -2572,14 +2525,13 @@ impl<'db> Evaluator<'db> { fn exec_fn_def( &mut self, def: CallableDefId, - generic_args: &Substitution, + generic_args: GenericArgs<'db>, destination: Interval, - args: &[IntervalAndTy], - locals: &Locals, - target_bb: Option, + args: &[IntervalAndTy<'db>], + locals: &Locals<'db>, + target_bb: Option>, span: MirSpan, - ) -> Result<'db, Option> { - let generic_args = generic_args.clone(); + ) -> Result<'db, Option>> { match def { CallableDefId::FunctionId(def) => { if self.detect_fn_trait(def).is_some() { @@ -2633,36 +2585,26 @@ impl<'db> Evaluator<'db> { fn get_mir_or_dyn_index( &self, def: FunctionId, - generic_args: Substitution, - locals: &Locals, + generic_args: GenericArgs<'db>, + locals: &Locals<'db>, span: MirSpan, - ) -> Result<'db, MirOrDynIndex> { + ) -> Result<'db, MirOrDynIndex<'db>> { let pair = (def, generic_args); if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) { return Ok(r.clone()); } let (def, generic_args) = pair; - let r = if let Some(self_ty_idx) = is_dyn_method( - self.interner, - self.trait_env.clone(), - def, - generic_args.to_nextsolver(self.interner), - ) { + let r = if let Some(self_ty_idx) = + is_dyn_method(self.interner(), self.trait_env.clone(), def, generic_args) + { MirOrDynIndex::Dyn(self_ty_idx) } else { - let (imp, generic_args) = self.db.lookup_impl_method( - self.trait_env.clone(), - def, - generic_args.to_nextsolver(self.interner), - ); + let (imp, generic_args) = + self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args); let mir_body = self .db - .monomorphized_mir_body( - imp.into(), - generic_args.to_chalk(self.interner), - self.trait_env.clone(), - ) + .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone()) .map_err(|e| { MirEvalError::InFunction( Box::new(MirEvalError::MirLowerError(imp, e)), @@ -2678,18 +2620,17 @@ impl<'db> Evaluator<'db> { fn exec_fn_with_args( &mut self, mut def: FunctionId, - args: &[IntervalAndTy], - generic_args: Substitution, - locals: &Locals, + args: &[IntervalAndTy<'db>], + generic_args: GenericArgs<'db>, + locals: &Locals<'db>, destination: Interval, - target_bb: Option, + target_bb: Option>, span: MirSpan, - ) -> Result<'db, Option> { - let interner = DbInterner::new_with(self.db, None, None); + ) -> Result<'db, Option>> { if self.detect_and_exec_special_function( def, args, - &generic_args, + generic_args, locals, destination, span, @@ -2700,7 +2641,7 @@ impl<'db> Evaluator<'db> { def = redirect_def; } let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval)); - match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? { + match self.get_mir_or_dyn_index(def, generic_args, locals, span)? { MirOrDynIndex::Dyn(self_ty_idx) => { // In the layout of current possible receiver, which at the moment of writing this code is one of // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible receivers, @@ -2712,18 +2653,16 @@ impl<'db> Evaluator<'db> { .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(), + ty, }; - let ty = ty.clone().cast(Interner); - let generics_for_target = Substitution::from_iter( - Interner, + let generics_for_target = GenericArgs::new_from_iter( + self.interner(), generic_args - .iter(Interner) + .iter() .enumerate() - .map(|(i, it)| if i == self_ty_idx { &ty } else { it }), + .map(|(i, it)| if i == self_ty_idx { ty.into() } else { it }), ); self.exec_fn_with_args( def, @@ -2749,14 +2688,14 @@ impl<'db> Evaluator<'db> { fn exec_looked_up_function( &mut self, - mir_body: Arc, - locals: &Locals, + mir_body: Arc>, + locals: &Locals<'db>, def: FunctionId, arg_bytes: impl Iterator, span: MirSpan, destination: Interval, - target_bb: Option, - ) -> Result<'db, Option> { + target_bb: Option>, + ) -> Result<'db, Option>> { Ok(if let Some(target_bb) = target_bb { let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&mir_body, Some(destination))?; @@ -2778,47 +2717,40 @@ impl<'db> Evaluator<'db> { fn exec_fn_trait( &mut self, def: FunctionId, - args: &[IntervalAndTy], - generic_args: Substitution, - locals: &Locals, + args: &[IntervalAndTy<'db>], + generic_args: GenericArgs<'db>, + locals: &Locals<'db>, destination: Interval, - target_bb: Option, + target_bb: Option>, span: MirSpan, - ) -> Result<'db, Option> { - let interner = DbInterner::new_with(self.db, None, None); + ) -> Result<'db, Option>> { let func = args .first() .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?; - let mut func_ty = func.ty.clone(); + let mut func_ty = func.ty; let mut func_data = func.interval; - while let TyKind::Ref(_, _, z) = func_ty.kind(Interner) { - func_ty = z.clone(); - if matches!(func_ty.kind(Interner), TyKind::Dyn(_)) { + while let TyKind::Ref(_, z, _) = func_ty.kind() { + func_ty = z; + if matches!(func_ty.kind(), TyKind::Dynamic(..)) { 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 = convert_ty_for_result(interner, self.vtable_map.ty(id)?); + func_ty = self.vtable_map.ty(id)?; } - let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?; + 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( - CallableDefId::from_chalk(self.db, *def), - subst, - destination, - &args[1..], - locals, - target_bb, - span, - ), - TyKind::Function(_) => { + match func_ty.kind() { + TyKind::FnDef(def, subst) => { + self.exec_fn_def(def.0, subst, destination, &args[1..], locals, target_bb, span) + } + TyKind::FnPtr(..) => { self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span) } TyKind::Closure(closure, subst) => self.exec_closure( - *closure, + closure.0, func_data, - &ClosureSubst(subst).parent_subst(self.db), + subst.split_closure_args_untupled().parent_args, destination, &args[1..], locals, @@ -2829,12 +2761,8 @@ impl<'db> Evaluator<'db> { let arg0 = func; let args = &args[1..]; let arg1 = { - let ty = TyKind::Tuple( - args.len(), - Substitution::from_iter(Interner, args.iter().map(|it| it.ty.clone())), - ) - .intern(Interner); - let layout = self.layout(ty.to_nextsolver(interner))?; + let ty = Ty::new_tup_from_iter(self.interner(), args.iter().map(|it| it.ty)); + let layout = self.layout(ty)?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -2860,7 +2788,7 @@ impl<'db> Evaluator<'db> { } } - fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> { + fn eval_static(&mut self, st: StaticId, locals: &Locals<'db>) -> Result<'db, Address> { if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; @@ -2869,11 +2797,10 @@ impl<'db> Evaluator<'db> { let konst = self.db.const_eval_static(st).map_err(|e| { MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e)) })?; - self.allocate_const_in_heap(locals, &konst)? + self.allocate_const_in_heap(locals, konst)? } else { - let ty = - self.db.infer(st.into())[self.db.body(st.into()).body_expr].to_chalk(self.interner); - let Some((size, align)) = self.size_align_of(&ty, locals)? else { + let ty = self.db.infer(st.into())[self.db.body(st.into()).body_expr]; + let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; let addr = self.heap_allocate(size, align)?; @@ -2907,7 +2834,12 @@ impl<'db> Evaluator<'db> { } } - fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<'db, ()> { + fn drop_place( + &mut self, + place: &Place<'db>, + locals: &mut Locals<'db>, + span: MirSpan, + ) -> Result<'db, ()> { let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; if !locals.drop_flags.remove_place(place, &locals.body.projection_store) { return Ok(()); @@ -2921,8 +2853,8 @@ impl<'db> Evaluator<'db> { fn run_drop_glue_deep( &mut self, - ty: Ty, - locals: &Locals, + ty: Ty<'db>, + locals: &Locals<'db>, addr: Address, _metadata: &[u8], span: MirSpan, @@ -2936,7 +2868,7 @@ impl<'db> Evaluator<'db> { return Ok(()); }; - let generic_args = Substitution::from1(Interner, ty.clone()); + let generic_args = GenericArgs::new_from_iter(self.interner(), [ty.into()]); if let Ok(MirOrDynIndex::Mir(body)) = self.get_mir_or_dyn_index(drop_fn, generic_args, locals, span) { @@ -2950,26 +2882,27 @@ impl<'db> Evaluator<'db> { None, )?; } - match ty.kind(Interner) { - TyKind::Adt(id, subst) => { - match id.0 { + match ty.kind() { + TyKind::Adt(adt_def, subst) => { + let id = adt_def.def_id().0; + match id { AdtId::StructId(s) => { let data = self.db.struct_signature(s); if data.flags.contains(StructFlags::IS_MANUALLY_DROP) { return Ok(()); } - let layout = self.layout_adt(id.0, subst.clone())?; + let layout = self.layout_adt(id, subst)?; let variant_fields = s.fields(self.db); match variant_fields.shape { FieldsShape::Record | FieldsShape::Tuple => { - let field_types = self.db.field_types(s.into()); + let field_types = self.db.field_types_ns(s.into()); for (field, _) in variant_fields.fields().iter() { let offset = layout .fields .offset(u32::from(field.into_raw()) as usize) .bytes_usize(); let addr = addr.offset(offset); - let ty = field_types[field].clone().substitute(Interner, subst); + let ty = field_types[field].instantiate(self.interner(), subst); self.run_drop_glue_deep(ty, locals, addr, &[], span)?; } } @@ -2980,28 +2913,34 @@ impl<'db> Evaluator<'db> { AdtId::EnumId(_) => (), } } - TyKind::AssociatedType(_, _) - | TyKind::Scalar(_) - | TyKind::Tuple(_, _) + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Tuple(_) | TyKind::Array(_, _) | TyKind::Slice(_) - | TyKind::Raw(_, _) + | TyKind::RawPtr(_, _) | TyKind::Ref(_, _, _) - | TyKind::OpaqueType(_, _) + | TyKind::Alias(..) | TyKind::FnDef(_, _) | TyKind::Str | TyKind::Never | TyKind::Closure(_, _) | TyKind::Coroutine(_, _) + | TyKind::CoroutineClosure(..) | TyKind::CoroutineWitness(_, _) | TyKind::Foreign(_) - | TyKind::Error + | TyKind::Error(_) + | TyKind::Param(_) | TyKind::Placeholder(_) - | TyKind::Dyn(_) - | TyKind::Alias(_) - | TyKind::Function(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => (), + | TyKind::Dynamic(..) + | TyKind::FnPtr(..) + | TyKind::Bound(..) + | TyKind::Infer(..) + | TyKind::Pat(..) + | TyKind::UnsafeBinder(..) => (), }; Ok(()) } @@ -3020,9 +2959,9 @@ impl<'db> Evaluator<'db> { pub fn render_const_using_debug_impl<'db>( db: &'db dyn HirDatabase, owner: DefWithBodyId, - c: &Const, + c: Const<'db>, + ty: Ty<'db>, ) -> Result<'db, String> { - let interner = DbInterner::new_with(db, None, None); let mut evaluator = Evaluator::new(db, owner, false, None)?; let locals = &Locals { ptr: ArenaMap::new(), @@ -3051,12 +2990,11 @@ pub fn render_const_using_debug_impl<'db>( // and its ABI doesn't break yet, we put it in memory manually. let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?; evaluator.write_memory(a2, &data.addr.to_bytes())?; - let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef( - CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db), - Substitution::from1(Interner, c.data(Interner).ty.clone()), - ) - .intern(Interner) - .to_nextsolver(interner)); + let debug_fmt_fn_ptr = evaluator.vtable_map.id(Ty::new_fn_def( + evaluator.interner(), + CallableDefId::FunctionId(debug_fmt_fn).into(), + GenericArgs::new_from_iter(evaluator.interner(), [ty.into()]), + )); 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 9ef0012a89c1c..c45ae9dcc3d3e 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 @@ -3,32 +3,21 @@ //! use std::cmp::{self, Ordering}; -use chalk_ir::TyKind; -use hir_def::signatures::FunctionSignature; -use hir_def::{ - CrateRootModuleId, - builtin_type::{BuiltinInt, BuiltinUint}, - resolver::HasResolver, -}; +use hir_def::{CrateRootModuleId, resolver::HasResolver, signatures::FunctionSignature}; use hir_expand::name::Name; use intern::{Symbol, sym}; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; use stdx::never; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ display::DisplayTarget, drop::{DropGlue, has_drop_glue}, - error_lifetime, mir::eval::{ - Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay, - InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, - LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution, - Ty, TyBuilder, TyExt, pad16, - }, - next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay, + InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, LangItem, + Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16, }, + next_solver::Region, }; mod simd; @@ -53,9 +42,9 @@ impl<'db> Evaluator<'db> { pub(super) fn detect_and_exec_special_function( &mut self, def: FunctionId, - args: &[IntervalAndTy], - generic_args: &Substitution, - locals: &Locals, + args: &[IntervalAndTy<'db>], + generic_args: GenericArgs<'db>, + locals: &Locals<'db>, destination: Interval, span: MirSpan, ) -> Result<'db, bool> { @@ -118,18 +107,16 @@ impl<'db> Evaluator<'db> { if let ItemContainerId::TraitId(t) = def.lookup(self.db).container && self.db.lang_attr(t.into()) == Some(LangItem::Clone) { - let [self_ty] = generic_args.as_slice(Interner) else { + let [self_ty] = generic_args.as_slice() else { not_supported!("wrong generic arg count for clone"); }; - let Some(self_ty) = self_ty.ty(Interner) else { + let Some(self_ty) = self_ty.ty() else { not_supported!("wrong generic arg kind for clone"); }; // Clone has special impls for tuples and function pointers - if matches!( - self_ty.kind(Interner), - TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..) - ) { - self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?; + if matches!(self_ty.kind(), TyKind::FnPtr(..) | TyKind::Tuple(..) | TyKind::Closure(..)) + { + self.exec_clone(def, args, self_ty, locals, destination, span)?; return Ok(true); } // Return early to prevent caching clone as non special fn. @@ -161,15 +148,14 @@ impl<'db> Evaluator<'db> { fn exec_clone( &mut self, def: FunctionId, - args: &[IntervalAndTy], - self_ty: Ty, - locals: &Locals, + args: &[IntervalAndTy<'db>], + self_ty: Ty<'db>, + locals: &Locals<'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { - let interner = self.interner; - match self_ty.kind(Interner) { - TyKind::Function(_) => { + match self_ty.kind() { + TyKind::FnPtr(..) => { let [arg] = args else { not_supported!("wrong arg count for clone"); }; @@ -182,30 +168,35 @@ impl<'db> Evaluator<'db> { not_supported!("wrong arg count for clone"); }; let addr = Address::from_bytes(arg.get(self)?)?; - let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure((*id).into()); + let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0); let infer = self.db.infer(closure_owner); - let (captures, _) = infer.closure_info((*id).into()); - let layout = self.layout(self_ty.to_nextsolver(interner))?; + let (captures, _) = infer.closure_info(id.0); + let layout = self.layout(self_ty)?; let db = self.db; - let ty_iter = captures - .iter() - .map(|c| c.ty(db, subst.to_nextsolver(interner)).to_chalk(interner)); + let ty_iter = captures.iter().map(|c| c.ty(db, subst)); self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?; } - TyKind::Tuple(_, subst) => { + TyKind::Tuple(subst) => { let [arg] = args else { not_supported!("wrong arg count for clone"); }; let addr = Address::from_bytes(arg.get(self)?)?; - 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)?; + let layout = self.layout(self_ty)?; + self.exec_clone_for_fields( + subst.iter(), + layout, + addr, + def, + locals, + destination, + span, + )?; } _ => { self.exec_fn_with_args( def, args, - Substitution::from1(Interner, self_ty), + GenericArgs::new_from_iter(self.interner(), [self_ty.into()]), locals, destination, None, @@ -218,21 +209,25 @@ impl<'db> Evaluator<'db> { fn exec_clone_for_fields( &mut self, - ty_iter: impl Iterator, + ty_iter: impl Iterator>, layout: Arc, addr: Address, def: FunctionId, - locals: &Locals, + locals: &Locals<'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { - let interner = DbInterner::new_with(self.db, None, None); for (i, ty) in ty_iter.enumerate() { - let size = self.layout(ty.to_nextsolver(interner))?.size.bytes_usize(); + let size = self.layout(ty)?.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() }, - ty: TyKind::Ref(Mutability::Not, error_lifetime(), ty.clone()).intern(Interner), + ty: Ty::new_ref( + self.interner(), + Region::error(self.interner()), + ty, + Mutability::Not, + ), }; let offset = layout.fields.offset(i).bytes_usize(); self.write_memory(tmp, &addr.offset(offset).to_bytes())?; @@ -251,7 +246,7 @@ impl<'db> Evaluator<'db> { fn exec_alloc_fn( &mut self, alloc_fn: &Symbol, - args: &[IntervalAndTy], + args: &[IntervalAndTy<'db>], destination: Interval, ) -> Result<'db, ()> { match alloc_fn { @@ -313,9 +308,9 @@ impl<'db> Evaluator<'db> { fn exec_lang_item( &mut self, it: LangItem, - generic_args: &Substitution, - args: &[IntervalAndTy], - locals: &Locals, + generic_args: GenericArgs<'db>, + args: &[IntervalAndTy<'db>], + locals: &Locals<'db>, span: MirSpan, ) -> Result<'db, Vec> { use LangItem::*; @@ -328,7 +323,7 @@ impl<'db> Evaluator<'db> { "argument of BeginPanic is not provided".into(), ))? .clone(); - while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) { + while let TyKind::Ref(_, ty, _) = arg.ty.kind() { if ty.is_str() { let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size()); let len = from_bytes!(usize, metadata); @@ -347,13 +342,10 @@ impl<'db> Evaluator<'db> { let pointee = arg.interval.get(self)?; arg = IntervalAndTy { interval: Interval::new(Address::from_bytes(pointee)?, size), - ty: ty.clone(), + ty, }; } - Err(MirEvalError::Panic(format!( - "unknown-panic-payload: {:?}", - arg.ty.kind(Interner) - ))) + Err(MirEvalError::Panic(format!("unknown-panic-payload: {:?}", arg.ty.kind()))) } SliceLen => { let arg = args.next().ok_or(MirEvalError::InternalError( @@ -364,18 +356,17 @@ impl<'db> Evaluator<'db> { Ok(arg[ptr_size..].into()) } DropInPlace => { - let ty = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)).ok_or( - MirEvalError::InternalError( - "generic argument of drop_in_place is not provided".into(), - ), - )?; + let ty = generic_args.as_slice().first().and_then(|it| it.ty()).ok_or( + MirEvalError::InternalError( + "generic argument of drop_in_place is not provided".into(), + ), + )?; let arg = args.next().ok_or(MirEvalError::InternalError( "argument of drop_in_place is not provided".into(), ))?; let arg = arg.interval.get(self)?.to_owned(); self.run_drop_glue_deep( - ty.clone(), + ty, locals, Address::from_bytes(&arg[0..self.ptr_size()])?, &arg[self.ptr_size()..], @@ -390,9 +381,9 @@ impl<'db> Evaluator<'db> { fn exec_syscall( &mut self, id: i64, - args: &[IntervalAndTy], + args: &[IntervalAndTy<'db>], destination: Interval, - _locals: &Locals, + _locals: &Locals<'db>, _span: MirSpan, ) -> Result<'db, ()> { match id { @@ -420,10 +411,10 @@ impl<'db> Evaluator<'db> { fn exec_extern_c( &mut self, as_str: &str, - args: &[IntervalAndTy], - _generic_args: &Substitution, + args: &[IntervalAndTy<'db>], + _generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals, + locals: &Locals<'db>, span: MirSpan, ) -> Result<'db, ()> { match as_str { @@ -586,14 +577,13 @@ impl<'db> Evaluator<'db> { fn exec_intrinsic( &mut self, name: &str, - args: &[IntervalAndTy], - generic_args: &Substitution, + args: &[IntervalAndTy<'db>], + generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals, + locals: &Locals<'db>, span: MirSpan, needs_override: bool, ) -> Result<'db, bool> { - 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) @@ -751,9 +741,7 @@ impl<'db> Evaluator<'db> { } match name { "size_of" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "size_of generic arg is not provided".into(), )); @@ -764,20 +752,16 @@ impl<'db> Evaluator<'db> { // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89 // (https://github.com/rust-lang/rust/pull/142410) "min_align_of" | "align_of" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of generic arg is not provided".into(), )); }; - let align = self.layout(ty.to_nextsolver(interner))?.align.bytes(); + let align = self.layout(ty)?.align.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "size_of_val generic arg is not provided".into(), )); @@ -798,9 +782,7 @@ impl<'db> Evaluator<'db> { // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89 // (https://github.com/rust-lang/rust/pull/142410) "min_align_of_val" | "align_of_val" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of_val generic arg is not provided".into(), )); @@ -819,9 +801,7 @@ impl<'db> Evaluator<'db> { } } "type_name" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "type_name generic arg is not provided".into(), )); @@ -848,18 +828,12 @@ impl<'db> Evaluator<'db> { .write_from_bytes(self, &len.to_le_bytes()) } "needs_drop" => { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "size_of generic arg is not provided".into(), )); }; - let result = match has_drop_glue( - &self.infcx, - ty.to_nextsolver(self.interner), - self.trait_env.clone(), - ) { + let result = match has_drop_glue(&self.infcx, ty, self.trait_env.clone()) { DropGlue::HasDropGlue => true, DropGlue::None => false, DropGlue::DependOnParams => { @@ -922,9 +896,7 @@ impl<'db> Evaluator<'db> { let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false)); let ans = lhs.wrapping_sub(rhs); - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "ptr_offset_from generic arg is not provided".into(), )); @@ -1013,13 +985,11 @@ impl<'db> Evaluator<'db> { "const_eval_select args are not provided".into(), )); }; - let result_ty = TyKind::Tuple( - 2, - Substitution::from_iter(Interner, [lhs.ty.clone(), TyBuilder::bool()]), - ) - .intern(Interner); - let op_size = - self.size_of_sized(&lhs.ty, locals, "operand of add_with_overflow")?; + let result_ty = Ty::new_tup_from_iter( + self.interner(), + [lhs.ty, Ty::new_bool(self.interner())].into_iter(), + ); + let op_size = self.size_of_sized(lhs.ty, locals, "operand of add_with_overflow")?; let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); let (ans, u128overflow) = match name { @@ -1031,7 +1001,7 @@ impl<'db> Evaluator<'db> { 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.to_nextsolver(interner))?; + let layout = self.layout(result_ty)?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, @@ -1048,9 +1018,7 @@ impl<'db> Evaluator<'db> { "copy_nonoverlapping args are not provided".into(), )); }; - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "copy_nonoverlapping generic arg is not provided".into(), )); @@ -1069,43 +1037,35 @@ impl<'db> Evaluator<'db> { return Err(MirEvalError::InternalError("offset args are not provided".into())); }; let ty = if name == "offset" { - let Some(ty0) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty0) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "offset generic arg is not provided".into(), )); }; - let Some(ty1) = - generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner)) - else { + let Some(ty1) = generic_args.as_slice().get(1).and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "offset generic arg is not provided".into(), )); }; if !matches!( - ty1.as_builtin(), - Some( - BuiltinType::Int(BuiltinInt::Isize) - | BuiltinType::Uint(BuiltinUint::Usize) - ) + ty1.kind(), + TyKind::Int(rustc_type_ir::IntTy::Isize) + | TyKind::Uint(rustc_type_ir::UintTy::Usize) ) { return Err(MirEvalError::InternalError( "offset generic arg is not usize or isize".into(), )); } - match ty0.as_raw_ptr() { - Some((ty, _)) => ty, - None => { + match ty0.kind() { + TyKind::RawPtr(ty, _) => ty, + _ => { return Err(MirEvalError::InternalError( "offset generic arg is not a raw pointer".into(), )); } } } else { - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "arith_offset generic arg is not provided".into(), )); @@ -1230,9 +1190,7 @@ impl<'db> Evaluator<'db> { "discriminant_value arg is not provided".into(), )); }; - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "discriminant_value generic arg is not provided".into(), )); @@ -1240,7 +1198,7 @@ impl<'db> Evaluator<'db> { let addr = Address::from_bytes(arg.get(self)?)?; let size = self.size_of_sized(ty, locals, "discriminant_value ptr type")?; let interval = Interval { addr, size }; - let r = self.compute_discriminant(ty.clone(), interval.get(self)?)?; + let r = self.compute_discriminant(ty, interval.get(self)?)?; destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size]) } "const_eval_select" => { @@ -1250,14 +1208,13 @@ impl<'db> Evaluator<'db> { )); }; let mut args = vec![const_fn.clone()]; - let TyKind::Tuple(_, fields) = tuple.ty.kind(Interner) else { + let TyKind::Tuple(fields) = tuple.ty.kind() else { return Err(MirEvalError::InternalError( "const_eval_select arg[0] is not a tuple".into(), )); }; - 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 layout = self.layout(tuple.ty)?; + for (i, field) in fields.iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let addr = tuple.interval.addr.offset(offset); args.push(IntervalAndTy::new(addr, field, self, locals)?); @@ -1271,7 +1228,7 @@ impl<'db> Evaluator<'db> { def, &args, // FIXME: wrong for manual impls of `FnOnce` - Substitution::empty(Interner), + GenericArgs::new_from_iter(self.interner(), []), locals, destination, None, @@ -1297,9 +1254,7 @@ impl<'db> Evaluator<'db> { )); }; let dst = Address::from_bytes(ptr.get(self)?)?; - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "write_via_copy generic arg is not provided".into(), )); @@ -1316,9 +1271,7 @@ impl<'db> Evaluator<'db> { }; let count = from_bytes!(usize, count.get(self)?); let val = from_bytes!(u8, val.get(self)?); - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "write_bytes generic arg is not provided".into(), )); @@ -1346,16 +1299,14 @@ impl<'db> Evaluator<'db> { "three_way_compare args are not provided".into(), )); }; - let Some(ty) = - generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "three_way_compare generic arg is not provided".into(), )); }; - let signed = match ty.as_builtin().unwrap() { - BuiltinType::Int(_) => true, - BuiltinType::Uint(_) => false, + let signed = match ty.kind() { + TyKind::Int(_) => true, + TyKind::Uint(_) => false, _ => { return Err(MirEvalError::InternalError( "three_way_compare expects an integral type".into(), @@ -1379,8 +1330,8 @@ impl<'db> Evaluator<'db> { result = (l as i8).cmp(&(r as i8)); } if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { - let ty = self.db.ty(e.into()).skip_binder().to_chalk(interner); - let r = self.compute_discriminant(ty.clone(), &[result as i8 as u8])?; + let ty = self.db.ty(e.into()).skip_binder(); + let r = self.compute_discriminant(ty, &[result as i8 as u8])?; destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?; Ok(()) } else { @@ -1409,38 +1360,37 @@ impl<'db> Evaluator<'db> { fn size_align_of_unsized( &mut self, - ty: &Ty, + ty: Ty<'db>, metadata: Interval, - locals: &Locals, + locals: &Locals<'db>, ) -> Result<'db, (usize, usize)> { - let interner = DbInterner::new_with(self.db, None, None); - Ok(match ty.kind(Interner) { + Ok(match ty.kind() { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), TyKind::Slice(inner) => { let len = from_bytes!(usize, metadata.get(self)?); let (size, align) = self.size_align_of_sized(inner, locals, "slice inner type")?; (size * len, align) } - TyKind::Dyn(_) => self.size_align_of_sized( - &convert_ty_for_result(interner, self.vtable_map.ty_of_bytes(metadata.get(self)?)?), + TyKind::Dynamic(..) => self.size_align_of_sized( + self.vtable_map.ty_of_bytes(metadata.get(self)?)?, locals, "dyn concrete type", )?, - TyKind::Adt(id, subst) => { - let id = id.0; - let layout = self.layout_adt(id, subst.clone())?; + TyKind::Adt(adt_def, subst) => { + let id = adt_def.def_id().0; + let layout = self.layout_adt(id, subst)?; let id = match id { AdtId::StructId(s) => s, _ => not_supported!("unsized enum or union"), }; - let field_types = &self.db.field_types(id.into()); + let field_types = self.db.field_types_ns(id.into()); let last_field_ty = - field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst); + field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst); let sized_part_size = layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); let sized_part_align = layout.align.bytes() as usize; let (unsized_part_size, unsized_part_align) = - self.size_align_of_unsized(&last_field_ty, metadata, locals)?; + self.size_align_of_unsized(last_field_ty, metadata, locals)?; let align = sized_part_align.max(unsized_part_align) as isize; let size = (sized_part_size + unsized_part_size) as isize; // Must add any necessary padding to `size` @@ -1463,13 +1413,12 @@ impl<'db> Evaluator<'db> { fn exec_atomic_intrinsic( &mut self, name: &str, - args: &[IntervalAndTy], - generic_args: &Substitution, + args: &[IntervalAndTy<'db>], + generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals, + locals: &Locals<'db>, _span: MirSpan, ) -> Result<'db, ()> { - 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. @@ -1479,8 +1428,7 @@ impl<'db> Evaluator<'db> { // The rest of atomic intrinsics have exactly one generic arg - let Some(ty) = generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "atomic intrinsic generic arg is not provided".into(), )); @@ -1562,12 +1510,11 @@ impl<'db> Evaluator<'db> { } else { (arg0_interval, false) }; - let result_ty = TyKind::Tuple( - 2, - Substitution::from_iter(Interner, [ty.clone(), TyBuilder::bool()]), - ) - .intern(Interner); - let layout = self.layout(result_ty.to_nextsolver(interner))?; + let result_ty = Ty::new_tup_from_iter( + self.interner(), + [ty, Ty::new_bool(self.interner())].into_iter(), + ); + let layout = self.layout(result_ty)?; let result = self.construct_with_layout( layout.size.bytes_usize(), &layout, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index 8e62c764b99bc..ade94b94c0ee5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; -use crate::TyKind; use crate::consteval::try_const_usize; use super::*; @@ -23,22 +22,20 @@ macro_rules! not_supported { } impl<'db> Evaluator<'db> { - fn detect_simd_ty(&self, ty: &Ty) -> Result<'db, (usize, Ty)> { - match ty.kind(Interner) { - TyKind::Adt(id, subst) => { - let len = match subst.as_slice(Interner).get(1).and_then(|it| it.constant(Interner)) - { + fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> { + match ty.kind() { + TyKind::Adt(adt_def, subst) => { + let len = match subst.as_slice().get(1).and_then(|it| it.konst()) { Some(len) => len, _ => { - if let AdtId::StructId(id) = id.0 { + if let AdtId::StructId(id) = adt_def.def_id().0 { let struct_data = id.fields(self.db); let fields = struct_data.fields(); let Some((first_field, _)) = fields.iter().next() else { not_supported!("simd type with no field"); }; - let field_ty = self.db.field_types(id.into())[first_field] - .clone() - .substitute(Interner, subst); + let field_ty = self.db.field_types_ns(id.into())[first_field] + .instantiate(self.interner(), subst); return Ok((fields.len(), field_ty)); } return Err(MirEvalError::InternalError( @@ -48,14 +45,12 @@ impl<'db> Evaluator<'db> { }; match try_const_usize(self.db, len) { Some(len) => { - let Some(ty) = - subst.as_slice(Interner).first().and_then(|it| it.ty(Interner)) - else { + let Some(ty) = subst.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "simd type with no ty param".into(), )); }; - Ok((len as usize, ty.clone())) + Ok((len as usize, ty)) } None => Err(MirEvalError::InternalError( "simd type with unevaluatable len param".into(), @@ -69,10 +64,10 @@ impl<'db> Evaluator<'db> { pub(super) fn exec_simd_intrinsic( &mut self, name: &str, - args: &[IntervalAndTy], - _generic_args: &Substitution, + args: &[IntervalAndTy<'db>], + _generic_args: GenericArgs<'db>, destination: Interval, - _locals: &Locals, + _locals: &Locals<'db>, _span: MirSpan, ) -> Result<'db, ()> { match name { @@ -99,8 +94,8 @@ impl<'db> Evaluator<'db> { let [left, right] = args else { return Err(MirEvalError::InternalError("simd args are not provided".into())); }; - let (len, ty) = self.detect_simd_ty(&left.ty)?; - let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); + let (len, ty) = self.detect_simd_ty(left.ty)?; + let is_signed = matches!(ty.kind(), TyKind::Int(_)); let size = left.interval.size / len; let dest_size = destination.size / len; let mut destination_bytes = vec![]; @@ -137,7 +132,7 @@ impl<'db> Evaluator<'db> { "simd_bitmask args are not provided".into(), )); }; - let (op_len, _) = self.detect_simd_ty(&op.ty)?; + let (op_len, _) = self.detect_simd_ty(op.ty)?; let op_count = op.interval.size / op_len; let mut result: u64 = 0; for (i, val) in op.get(self)?.chunks(op_count).enumerate() { @@ -153,7 +148,7 @@ impl<'db> Evaluator<'db> { "simd_shuffle args are not provided".into(), )); }; - let TyKind::Array(_, index_len) = index.ty.kind(Interner) else { + let TyKind::Array(_, index_len) = index.ty.kind() else { return Err(MirEvalError::InternalError( "simd_shuffle index argument has non-array type".into(), )); @@ -166,7 +161,7 @@ impl<'db> Evaluator<'db> { )); } }; - let (left_len, _) = self.detect_simd_ty(&left.ty)?; + let (left_len, _) = self.detect_simd_ty(left.ty)?; let left_size = left.interval.size / left_len; let vector = left.get(self)?.chunks(left_size).chain(right.get(self)?.chunks(left_size)); 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 82c0a8070c41a..4eb4aa91598e3 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 @@ -4,15 +4,20 @@ use span::Edition; use syntax::{TextRange, TextSize}; use test_fixture::WithFixture; -use crate::display::DisplayTarget; use crate::{ - Interner, Substitution, db::HirDatabase, mir::MirLowerError, setup_tracing, test_db::TestDB, + db::HirDatabase, + display::DisplayTarget, + mir::MirLowerError, + next_solver::{DbInterner, GenericArgs}, + setup_tracing, + test_db::TestDB, }; use super::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { + let interner = DbInterner::new_with(db, None, None); 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; @@ -34,7 +39,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), let body = db .monomorphized_mir_body( func_id.into(), - Substitution::empty(Interner), + GenericArgs::new_from_iter(interner, []), db.trait_environment(func_id.into()), ) .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; @@ -631,11 +636,16 @@ fn main() { ); } +#[ignore = " +FIXME(next-solver): +This does not work currently because I replaced homemade selection with selection by the trait solver; +This will work once we implement `Interner::impl_specializes()` properly. +"] #[test] fn specialization_array_clone() { check_pass( r#" -//- minicore: copy, derive, slice, index, coerce_unsized +//- minicore: copy, derive, slice, index, coerce_unsized, panic impl Clone for [T; N] { #[inline] fn clone(&self) -> Self { @@ -650,8 +660,7 @@ trait SpecArrayClone: Clone { impl SpecArrayClone for T { #[inline] default fn clone(array: &[T; N]) -> [T; N] { - // FIXME: panic here when we actually implement specialization. - from_slice(array) + panic!("should go to the specialized impl") } } 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 ec7bff708297d..92f9cd42615ec 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 @@ -3,10 +3,9 @@ use std::{fmt::Write, iter, mem}; use base_db::Crate; -use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, - Lookup, TraitId, TupleId, TypeOrConstParamId, + AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, GenericParamId, HasModule, + ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, @@ -20,37 +19,33 @@ use hir_expand::name::Name; use la_arena::ArenaMap; use rustc_apfloat::Float; use rustc_hash::FxHashMap; -use rustc_type_ir::inherent::IntoKind; +use rustc_type_ir::inherent::{Const as _, IntoKind, SliceLike, Ty as _}; use span::{Edition, FileId}; use syntax::TextRange; use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, TyBuilder, TyExt, + Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, consteval::ConstEvalError, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{DisplayTarget, HirDisplay, hir_display_with_store}, - error_lifetime, generics::generics, infer::{CaptureKind, CapturedItem, TypeMismatch, cast::CastTy}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, - mapping::ToChalk, mir::{ - AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, BorrowKind, CastKind, ConstScalar, - Either, Expr, FieldId, Idx, InferenceResult, Interner, Local, LocalId, MemoryMap, MirBody, - MirSpan, Mutability, Operand, Place, PlaceElem, PointerCast, ProjectionElem, - ProjectionStore, RawIdx, Rvalue, Statement, StatementKind, Substitution, SwitchTargets, - Terminator, TerminatorKind, TupleFieldId, Ty, UnOp, VariantId, intern_const_scalar, - return_slot, + AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp, BorrowKind, CastKind, Either, Expr, + FieldId, GenericArgs, Idx, InferenceResult, Local, LocalId, MemoryMap, MirBody, MirSpan, + Mutability, Operand, Place, PlaceElem, PointerCast, ProjectionElem, ProjectionStore, + RawIdx, Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, + TupleFieldId, Ty, UnOp, VariantId, return_slot, }, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst, + infer::{DbInternerInferExt, InferCtxt}, + mapping::NextSolverToChalk, }, - static_lifetime, traits::FnTrait, - utils::ClosureSubst, }; use super::OperandKind; @@ -61,33 +56,33 @@ mod pattern_matching; mod tests; #[derive(Debug, Clone)] -struct LoopBlocks { - begin: BasicBlockId, +struct LoopBlocks<'db> { + begin: BasicBlockId<'db>, /// `None` for loops that are not terminating - end: Option, - place: Place, + end: Option>, + place: Place<'db>, drop_scope_index: usize, } #[derive(Debug, Clone, Default)] -struct DropScope { +struct DropScope<'db> { /// locals, in order of definition (so we should run drop glues in reverse order) - locals: Vec, + locals: Vec>, } struct MirLowerCtx<'a, 'db> { - result: MirBody, + result: MirBody<'db>, owner: DefWithBodyId, - current_loop_blocks: Option, - labeled_loop_blocks: FxHashMap, - discr_temp: Option, + current_loop_blocks: Option>, + labeled_loop_blocks: FxHashMap>, + discr_temp: Option>, db: &'db dyn HirDatabase, body: &'a Body, infer: &'a InferenceResult<'db>, resolver: Resolver<'db>, - drop_scopes: Vec, + drop_scopes: Vec>, env: Arc>, - interner: DbInterner<'db>, + infcx: InferCtxt<'db>, } // FIXME: Make this smaller, its stored in database queries @@ -103,7 +98,7 @@ pub enum MirLowerError<'db> { RecordLiteralWithoutPath, UnresolvedMethod(String), UnresolvedField, - UnsizedTemporary(Ty), + UnsizedTemporary(Ty<'db>), MissingFunctionDefinition(DefWithBodyId, ExprId), TypeMismatch(TypeMismatch<'db>), HasErrors, @@ -118,22 +113,22 @@ pub enum MirLowerError<'db> { LangItemNotFound(LangItem), MutatingRvalue, UnresolvedLabel, - UnresolvedUpvar(Place), + UnresolvedUpvar(Place<'db>), InaccessibleLocal, // monomorphization errors: - GenericArgNotProvided(TypeOrConstParamId, Substitution), + GenericArgNotProvided(GenericParamId, GenericArgs<'db>), } /// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves. struct DropScopeToken; impl DropScopeToken { - fn pop_and_drop( + fn pop_and_drop<'db>( self, - ctx: &mut MirLowerCtx<'_, '_>, - current: BasicBlockId, + ctx: &mut MirLowerCtx<'_, 'db>, + current: BasicBlockId<'db>, span: MirSpan, - ) -> BasicBlockId { + ) -> BasicBlockId<'db> { std::mem::forget(self); ctx.pop_drop_scope_internal(current, span) } @@ -199,15 +194,24 @@ impl MirLowerError<'_> { e.actual.display(db, display_target), )?, MirLowerError::GenericArgNotProvided(id, subst) => { - let parent = id.parent; - let param = &db.generic_params(parent)[id.local_id]; + let param_name = match *id { + GenericParamId::TypeParamId(id) => { + db.generic_params(id.parent())[id.local_id()].name().cloned() + } + GenericParamId::ConstParamId(id) => { + db.generic_params(id.parent())[id.local_id()].name().cloned() + } + GenericParamId::LifetimeParamId(id) => { + Some(db.generic_params(id.parent)[id.local_id].name.clone()) + } + }; writeln!( f, "Generic arg not provided for {}", - param.name().unwrap_or(&Name::missing()).display(db, display_target.edition) + param_name.unwrap_or(Name::missing()).display(db, display_target.edition) )?; writeln!(f, "Provided args: [")?; - for g in subst.iter(Interner) { + for g in subst.iter() { write!(f, " {},", g.display(db, display_target))?; } writeln!(f, "]")?; @@ -285,7 +289,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { is_cleanup: false, }); let locals = Arena::new(); - let binding_locals: ArenaMap = ArenaMap::new(); + let binding_locals: ArenaMap> = ArenaMap::new(); let mir = MirBody { projection_store: ProjectionStore::default(), basic_blocks, @@ -299,6 +303,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let resolver = owner.resolver(db); let env = db.trait_environment_for_body(owner); let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); MirLowerCtx { result: mir, @@ -312,12 +317,22 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { discr_temp: None, drop_scopes: vec![DropScope::default()], env, - interner, + infcx, } } - fn temp(&mut self, ty: Ty, current: BasicBlockId, span: MirSpan) -> Result<'db, LocalId> { - if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { + #[inline] + fn interner(&self) -> DbInterner<'db> { + self.infcx.interner + } + + fn temp( + &mut self, + ty: Ty<'db>, + current: BasicBlockId<'db>, + span: MirSpan, + ) -> Result<'db, LocalId<'db>> { + if matches!(ty.kind(), TyKind::Slice(_) | TyKind::Dynamic(..)) { return Err(MirLowerError::UnsizedTemporary(ty)); } let l = self.result.locals.alloc(Local { ty }); @@ -328,8 +343,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_some_operand( &mut self, expr_id: ExprId, - current: BasicBlockId, - ) -> Result<'db, Option<(Operand, BasicBlockId)>> { + current: BasicBlockId<'db>, + ) -> Result<'db, Option<(Operand<'db>, BasicBlockId<'db>)>> { if !self.has_adjustments(expr_id) && let Expr::Literal(l) = &self.body[expr_id] { @@ -345,15 +360,18 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_place_with_adjust( &mut self, expr_id: ExprId, - place: Place, - current: BasicBlockId, + place: Place<'db>, + current: BasicBlockId<'db>, adjustments: &[Adjustment<'db>], - ) -> Result<'db, Option> { + ) -> Result<'db, Option>> { match adjustments.split_last() { Some((last, rest)) => match &last.kind { Adjust::NeverToAny => { - let temp = - self.temp(TyKind::Never.intern(Interner), current, MirSpan::Unknown)?; + let temp = self.temp( + Ty::new(self.interner(), TyKind::Never), + current, + MirSpan::Unknown, + )?; self.lower_expr_to_place_with_adjust(expr_id, temp.into(), current, rest) } Adjust::Deref(_) => { @@ -392,7 +410,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Rvalue::Cast( CastKind::PointerCoercion(*cast), Operand { kind: OperandKind::Copy(p), span: None }, - last.target.to_chalk(self.interner), + last.target, ), expr_id.into(), ); @@ -406,9 +424,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_place( &mut self, expr_id: ExprId, - place: Place, - prev_block: BasicBlockId, - ) -> Result<'db, Option> { + place: Place<'db>, + prev_block: BasicBlockId<'db>, + ) -> Result<'db, Option>> { if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) { return self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments); } @@ -418,9 +436,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_expr_to_place_without_adjust( &mut self, expr_id: ExprId, - place: Place, - mut current: BasicBlockId, - ) -> Result<'db, Option> { + place: Place<'db>, + mut current: BasicBlockId<'db>, + ) -> Result<'db, Option>> { match &self.body[expr_id] { Expr::OffsetOf(_) => { not_supported!("builtin#offset_of") @@ -443,14 +461,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) { match assoc { hir_def::AssocItemId::ConstId(c) => { - self.lower_const( - c.into(), - current, - place, - subst.to_chalk(self.interner), - expr_id.into(), - self.expr_ty_without_adjust(expr_id), - )?; + self.lower_const(c.into(), current, place, subst, expr_id.into())?; return Ok(Some(current)); } hir_def::AssocItemId::FunctionId(_) => { @@ -506,9 +517,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { const_id.into(), current, place, - Substitution::empty(Interner), + GenericArgs::new_from_iter(self.interner(), []), expr_id.into(), - self.expr_ty_without_adjust(expr_id), )?; Ok(Some(current)) } @@ -520,7 +530,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { variant_id, current, place, - ty.to_chalk(self.interner), + ty, Box::new([]), expr_id.into(), )?; @@ -533,25 +543,21 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { not_supported!("owner without generic def id"); }; let generics = generics(self.db, def); - let ty = self.expr_ty_without_adjust(expr_id); + let index = generics + .type_or_const_param_idx(p.into()) + .ok_or(MirLowerError::TypeError("fail to lower const generic param"))? + as u32; self.push_assignment( current, place, Rvalue::from(Operand { - kind: OperandKind::Constant( - ConstData { - ty, - value: chalk_ir::ConstValue::BoundVar(BoundVar::new( - DebruijnIndex::INNERMOST, - generics.type_or_const_param_idx(p.into()).ok_or( - MirLowerError::TypeError( - "fail to lower const generic param", - ), - )?, - )), - } - .intern(Interner), - ), + kind: OperandKind::Constant { + konst: Const::new_param( + self.interner(), + ParamConst { id: p, index }, + ), + ty: self.db.const_param_ty_ns(p), + }, span: None, }), expr_id.into(), @@ -603,7 +609,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { then_target, place, Box::new([1]), - TyBuilder::bool(), + Ty::new_bool(self.interner()), MirSpan::Unknown, )?; if let Some(else_target) = else_target { @@ -611,7 +617,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { else_target, place, Box::new([0]), - TyBuilder::bool(), + Ty::new_bool(self.interner()), MirSpan::Unknown, )?; } @@ -653,11 +659,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } Expr::Call { callee, args, .. } => { if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { - let ty = chalk_ir::TyKind::FnDef( - CallableDefId::FunctionId(func_id).to_chalk(self.db), - generic_args.to_chalk(self.interner), - ) - .intern(Interner); + let ty = Ty::new_fn_def( + self.interner(), + CallableDefId::FunctionId(func_id).into(), + generic_args, + ); let func = Operand::from_bytes(Box::default(), ty); return self.lower_call_and_args( func, @@ -669,9 +675,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { ); } let callee_ty = self.expr_ty_after_adjustments(*callee); - match &callee_ty.kind(Interner) { - chalk_ir::TyKind::FnDef(..) => { - let func = Operand::from_bytes(Box::default(), callee_ty.clone()); + match callee_ty.kind() { + TyKind::FnDef(..) => { + let func = Operand::from_bytes(Box::default(), callee_ty); self.lower_call_and_args( func, args.iter().copied(), @@ -681,7 +687,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { expr_id.into(), ) } - chalk_ir::TyKind::Function(_) => { + TyKind::FnPtr(..) => { let Some((func, current)) = self.lower_expr_to_some_operand(*callee, current)? else { @@ -701,7 +707,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { "method resolution not emitted for closure (Are Fn traits available?)" ); } - TyKind::Error => { + TyKind::Error(_) => { Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)) } _ => Err(MirLowerError::TypeError("function call on bad type")), @@ -714,7 +720,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { method_name.display(self.db, self.edition()).to_string(), ) })?; - let func = Operand::from_fn(self.db, func_id, generic_args.to_chalk(self.interner)); + let func = Operand::from_fn(self.db, func_id, generic_args); self.lower_call_and_args( func, iter::once(*receiver).chain(args.iter().copied()), @@ -862,8 +868,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { ), None => MirLowerError::RecordLiteralWithoutPath, })?; - let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) { - TyKind::Adt(_, s) => s.clone(), + let subst = match self.expr_ty_without_adjust(expr_id).kind() { + TyKind::Adt(_, s) => s, _ => not_supported!("Non ADT record literal"), }; let variant_fields = variant_id.fields(self.db); @@ -952,12 +958,12 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let rvalue = if self.infer.coercion_casts.contains(expr) { Rvalue::Use(it) } else { - let source_ty = self.infer[*expr].to_chalk(self.interner); - let target_ty = self.infer[expr_id].to_chalk(self.interner); + let source_ty = self.infer[*expr]; + let target_ty = self.infer[expr_id]; let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { - cast_kind(self.db, &source_ty, &target_ty)? + cast_kind(self.db, source_ty, target_ty)? }; Rvalue::Cast(cast_kind, it, target_ty) @@ -1034,8 +1040,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let lhs_ty = self.expr_ty_without_adjust(*lhs); let rhs_ty = self.expr_ty_without_adjust(*rhs); if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) - && lhs_ty.as_raw_ptr().is_some() - && rhs_ty.as_raw_ptr().is_some() + && matches!(lhs_ty.kind(), TyKind::RawPtr(..)) + && matches!(rhs_ty.kind(), TyKind::RawPtr(..)) { break 'b true; } @@ -1044,15 +1050,26 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) } ); - lhs_ty.is_scalar() - && rhs_ty.is_scalar() - && (lhs_ty == rhs_ty || builtin_inequal_impls) + matches!( + lhs_ty.kind(), + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + ) && matches!( + rhs_ty.kind(), + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + ) && (lhs_ty == rhs_ty || builtin_inequal_impls) }; if !is_builtin && let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { - let func = - Operand::from_fn(self.db, func_id, generic_args.to_chalk(self.interner)); + let func = Operand::from_fn(self.db, func_id, generic_args); return self.lower_call_and_args( func, [*lhs, *rhs].into_iter(), @@ -1185,7 +1202,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { current, place, Rvalue::Aggregate( - AggregateKind::Adt(st.into(), subst.clone()), + AggregateKind::Adt(st.into(), subst), st.fields(self.db) .fields() .iter() @@ -1193,9 +1210,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let o = match it.1.name.as_str() { "start" => lp.take(), "end" => rp.take(), - "exhausted" => { - Some(Operand::from_bytes(Box::new([0]), TyBuilder::bool())) - } + "exhausted" => Some(Operand::from_bytes( + Box::new([0]), + Ty::new_bool(self.interner()), + )), _ => None, }; o.ok_or(MirLowerError::UnresolvedField) @@ -1208,11 +1226,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } Expr::Closure { .. } => { let ty = self.expr_ty_without_adjust(expr_id); - let TyKind::Closure(id, _) = ty.kind(Interner) else { + let TyKind::Closure(id, _) = ty.kind() else { not_supported!("closure with non closure type"); }; - self.result.closures.push(*id); - let (captures, _) = self.infer.closure_info((*id).into()); + self.result.closures.push(id.0); + let (captures, _) = self.infer.closure_info(id.0); let mut operands = vec![]; for capture in captures.iter() { let p = Place { @@ -1236,7 +1254,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { ProjectionElem::Subslice { from, to } } ProjectionElem::OpaqueCast(it) => { - ProjectionElem::OpaqueCast(it.to_chalk(self.interner)) + ProjectionElem::OpaqueCast(it) } #[allow(unreachable_patterns)] ProjectionElem::Index(it) => match it {}, @@ -1246,15 +1264,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; match &capture.kind { CaptureKind::ByRef(bk) => { - let placeholder_subst: crate::next_solver::GenericArgs<'db> = - self.placeholder_subst().to_nextsolver(self.interner); - let tmp_ty = capture - .ty - .instantiate(self.interner, placeholder_subst) - .to_chalk(self.interner); + let tmp_ty = capture.ty.instantiate_identity(); // FIXME: Handle more than one span. let capture_spans = capture.spans(); - let tmp: Place = self.temp(tmp_ty, current, capture_spans[0])?.into(); + let tmp: Place<'db> = + self.temp(tmp_ty, current, capture_spans[0])?.into(); self.push_assignment( current, tmp, @@ -1299,8 +1313,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } Expr::Array(l) => match l { Array::ElementList { elements, .. } => { - let elem_ty = match &self.expr_ty_without_adjust(expr_id).kind(Interner) { - TyKind::Array(ty, _) => ty.clone(), + let elem_ty = match self.expr_ty_without_adjust(expr_id).kind() { + TyKind::Array(ty, _) => ty, _ => { return Err(MirLowerError::TypeError( "Array expression with non array type", @@ -1331,8 +1345,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { else { return Ok(None); }; - let len = match &self.expr_ty_without_adjust(expr_id).kind(Interner) { - TyKind::Array(_, len) => len.clone(), + let len = match self.expr_ty_without_adjust(expr_id).kind() { + TyKind::Array(_, len) => len, _ => { return Err(MirLowerError::TypeError( "Array repeat expression with non array type", @@ -1354,16 +1368,13 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } } - fn placeholder_subst(&mut self) -> Substitution { - match self.owner.as_generic_def_id(self.db) { - Some(it) => TyBuilder::placeholder_subst(self.db, it), - None => Substitution::empty(Interner), - } - } - - fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<'db, ()> { + fn push_field_projection( + &mut self, + place: &mut Place<'db>, + expr_id: ExprId, + ) -> Result<'db, ()> { if let Expr::Field { expr, name } = &self.body[expr_id] { - if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) { + if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind() { let index = name.as_tuple_index().ok_or(MirLowerError::TypeError("named field on tuple"))? as u32; @@ -1386,7 +1397,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(()) } - fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result<'db, Operand> { + fn lower_literal_or_const_to_operand( + &mut self, + ty: Ty<'db>, + loc: &ExprId, + ) -> Result<'db, Operand<'db>> { match &self.body[*loc] { Expr::Literal(l) => self.lower_literal_to_operand(ty, l), Expr::Path(c) => { @@ -1407,7 +1422,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { match pr { ResolveValueResult::ValueNs(v, _) => { if let ValueNs::ConstId(c) = v { - self.lower_const_to_operand(Substitution::empty(Interner), c.into(), ty) + self.lower_const_to_operand( + GenericArgs::new_from_iter(self.interner(), []), + c.into(), + ) } else { not_supported!("bad path in range pattern"); } @@ -1423,13 +1441,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } } - fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<'db, Operand> { - 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()) - }; + fn lower_literal_to_operand(&mut self, ty: Ty<'db>, l: &Literal) -> Result<'db, Operand<'db>> { + let size = || self.db.layout_of_ty(ty, 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) => { @@ -1475,48 +1488,57 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(Operand::from_concrete_const(bytes, MemoryMap::default(), ty)) } - fn new_basic_block(&mut self) -> BasicBlockId { + fn new_basic_block(&mut self) -> BasicBlockId<'db> { self.result.basic_blocks.alloc(BasicBlock::default()) } fn lower_const( &mut self, const_id: GeneralConstId, - prev_block: BasicBlockId, - place: Place, - subst: Substitution, + prev_block: BasicBlockId<'db>, + place: Place<'db>, + subst: GenericArgs<'db>, span: MirSpan, - ty: Ty, ) -> Result<'db, ()> { - let c = self.lower_const_to_operand(subst, const_id, ty)?; + let c = self.lower_const_to_operand(subst, const_id)?; self.push_assignment(prev_block, place, c.into(), span); Ok(()) } fn lower_const_to_operand( &mut self, - subst: Substitution, + subst: GenericArgs<'db>, const_id: GeneralConstId, - ty: Ty, - ) -> Result<'db, Operand> { - let c = if subst.len(Interner) != 0 { + ) -> Result<'db, Operand<'db>> { + let konst = if subst.len() != 0 { // We can't evaluate constant with substitution now, as generics are not monomorphized in lowering. - intern_const_scalar(ConstScalar::UnevaluatedConst(const_id, subst), ty) + Const::new_unevaluated( + self.interner(), + UnevaluatedConst { def: const_id.into(), args: subst }, + ) } else { let name = const_id.name(self.db); self.db .const_eval(const_id, subst, None) .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))? }; - Ok(Operand { kind: OperandKind::Constant(c), span: None }) + let ty = self + .db + .value_ty(match const_id { + GeneralConstId::ConstId(id) => id.into(), + GeneralConstId::StaticId(id) => id.into(), + }) + .unwrap() + .instantiate(self.interner(), subst); + Ok(Operand { kind: OperandKind::Constant { konst, ty }, span: None }) } fn write_bytes_to_place( &mut self, - prev_block: BasicBlockId, - place: Place, + prev_block: BasicBlockId<'db>, + place: Place<'db>, cv: Box<[u8]>, - ty: Ty, + ty: Ty<'db>, span: MirSpan, ) -> Result<'db, ()> { self.push_assignment(prev_block, place, Operand::from_bytes(cv, ty).into(), span); @@ -1526,14 +1548,14 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_enum_variant( &mut self, variant_id: EnumVariantId, - prev_block: BasicBlockId, - place: Place, - ty: Ty, - fields: Box<[Operand]>, + prev_block: BasicBlockId<'db>, + place: Place<'db>, + ty: Ty<'db>, + fields: Box<[Operand<'db>]>, span: MirSpan, - ) -> Result<'db, BasicBlockId> { - let subst = match ty.kind(Interner) { - TyKind::Adt(_, subst) => subst.clone(), + ) -> Result<'db, BasicBlockId<'db>> { + let subst = match ty.kind() { + TyKind::Adt(_, subst) => subst, _ => implementation_error!("Non ADT enum"), }; self.push_assignment( @@ -1547,13 +1569,13 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_call_and_args( &mut self, - func: Operand, + func: Operand<'db>, args: impl Iterator, - place: Place, - mut current: BasicBlockId, + place: Place<'db>, + mut current: BasicBlockId<'db>, is_uninhabited: bool, span: MirSpan, - ) -> Result<'db, Option> { + ) -> Result<'db, Option>> { let Some(args) = args .map(|arg| { if let Some((temp, c)) = self.lower_expr_to_some_operand(arg, current)? { @@ -1572,13 +1594,13 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_call( &mut self, - func: Operand, - args: Box<[Operand]>, - place: Place, - current: BasicBlockId, + func: Operand<'db>, + args: Box<[Operand<'db>]>, + place: Place<'db>, + current: BasicBlockId<'db>, is_uninhabited: bool, span: MirSpan, - ) -> Result<'db, Option> { + ) -> Result<'db, Option>> { let b = if is_uninhabited { None } else { Some(self.new_basic_block()) }; self.set_terminator( current, @@ -1595,56 +1617,63 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(b) } - fn is_unterminated(&mut self, source: BasicBlockId) -> bool { + fn is_unterminated(&mut self, source: BasicBlockId<'db>) -> bool { self.result.basic_blocks[source].terminator.is_none() } - fn set_terminator(&mut self, source: BasicBlockId, terminator: TerminatorKind, span: MirSpan) { + fn set_terminator( + &mut self, + source: BasicBlockId<'db>, + terminator: TerminatorKind<'db>, + span: MirSpan, + ) { self.result.basic_blocks[source].terminator = Some(Terminator { span, kind: terminator }); } - fn set_goto(&mut self, source: BasicBlockId, target: BasicBlockId, span: MirSpan) { + fn set_goto(&mut self, source: BasicBlockId<'db>, target: BasicBlockId<'db>, span: MirSpan) { self.set_terminator(source, TerminatorKind::Goto { target }, span); } - fn expr_ty_without_adjust(&self, e: ExprId) -> Ty { - self.infer[e].to_chalk(self.interner) + fn expr_ty_without_adjust(&self, e: ExprId) -> Ty<'db> { + self.infer[e] } - fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { + fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty<'db> { let mut ty = None; if let Some(it) = self.infer.expr_adjustments.get(&e) && let Some(it) = it.last() { - ty = Some(it.target.to_chalk(self.interner)); + ty = Some(it.target); } ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } - fn push_statement(&mut self, block: BasicBlockId, statement: Statement) { + fn push_statement(&mut self, block: BasicBlockId<'db>, statement: Statement<'db>) { self.result.basic_blocks[block].statements.push(statement); } - fn push_fake_read(&mut self, block: BasicBlockId, p: Place, span: MirSpan) { + fn push_fake_read(&mut self, block: BasicBlockId<'db>, p: Place<'db>, span: MirSpan) { self.push_statement(block, StatementKind::FakeRead(p).with_span(span)); } fn push_assignment( &mut self, - block: BasicBlockId, - place: Place, - rvalue: Rvalue, + block: BasicBlockId<'db>, + place: Place<'db>, + rvalue: Rvalue<'db>, span: MirSpan, ) { self.push_statement(block, StatementKind::Assign(place, rvalue).with_span(span)); } - fn discr_temp_place(&mut self, current: BasicBlockId) -> Place { + fn discr_temp_place(&mut self, current: BasicBlockId<'db>) -> Place<'db> { match &self.discr_temp { Some(it) => *it, None => { - let tmp: Place = self - .temp(TyBuilder::discr_ty(), current, MirSpan::Unknown) + // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well + let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128); + let tmp: Place<'db> = self + .temp(discr_ty, current, MirSpan::Unknown) .expect("discr_ty is never unsized") .into(); self.discr_temp = Some(tmp); @@ -1655,12 +1684,12 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_loop( &mut self, - prev_block: BasicBlockId, - place: Place, + prev_block: BasicBlockId<'db>, + place: Place<'db>, label: Option, span: MirSpan, - f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId) -> Result<'db, ()>, - ) -> Result<'db, Option> { + f: impl FnOnce(&mut MirLowerCtx<'_, 'db>, BasicBlockId<'db>) -> Result<'db, ()>, + ) -> Result<'db, Option>> { let begin = self.new_basic_block(); let prev = self.current_loop_blocks.replace(LoopBlocks { begin, @@ -1695,10 +1724,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn merge_blocks( &mut self, - b1: Option, - b2: Option, + b1: Option>, + b2: Option>, span: MirSpan, - ) -> Option { + ) -> Option> { match (b1, b2) { (None, None) => None, (None, Some(b)) | (Some(b), None) => Some(b), @@ -1711,7 +1740,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } } - fn current_loop_end(&mut self) -> Result<'db, BasicBlockId> { + fn current_loop_end(&mut self) -> Result<'db, BasicBlockId<'db>> { let r = match self .current_loop_blocks .as_mut() @@ -1738,7 +1767,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn is_uninhabited(&self, expr_id: ExprId) -> bool { is_ty_uninhabited_from( self.db, - &self.infer[expr_id].to_chalk(self.interner), + &self.infer[expr_id].to_chalk(self.interner()), self.owner.module(self.db), self.env.clone(), ) @@ -1746,15 +1775,15 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and /// `Drop` in the appropriated places. - fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<'db, ()> { + fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId<'db>) -> Result<'db, ()> { let l = self.binding_local(b)?; self.push_storage_live_for_local(l, current, MirSpan::BindingId(b)) } fn push_storage_live_for_local( &mut self, - l: LocalId, - current: BasicBlockId, + l: LocalId<'db>, + current: BasicBlockId<'db>, span: MirSpan, ) -> Result<'db, ()> { self.drop_scopes.last_mut().unwrap().locals.push(l); @@ -1770,11 +1799,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_block_to_place( &mut self, statements: &[hir_def::hir::Statement], - mut current: BasicBlockId, + mut current: BasicBlockId<'db>, tail: Option, - place: Place, + place: Place<'db>, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>>> { let scope = self.push_drop_scope(); for statement in statements.iter() { match statement { @@ -1847,10 +1876,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_params_and_bindings( &mut self, - params: impl Iterator + Clone, - self_binding: Option<(BindingId, Ty)>, + params: impl Iterator)> + Clone, + self_binding: Option<(BindingId, Ty<'db>)>, pick_binding: impl Fn(BindingId) -> bool, - ) -> Result<'db, BasicBlockId> { + ) -> Result<'db, BasicBlockId<'db>> { let base_param_count = self.result.param_locals.len(); let self_binding = match self_binding { Some((self_binding, ty)) => { @@ -1881,10 +1910,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { continue; } if !self.result.binding_locals.contains_idx(id) { - self.result.binding_locals.insert( - id, - self.result.locals.alloc(Local { ty: self.infer[id].to_chalk(self.interner) }), - ); + self.result + .binding_locals + .insert(id, self.result.locals.alloc(Local { ty: self.infer[id] })); } } let mut current = self.result.start_block; @@ -1919,7 +1947,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(current) } - fn binding_local(&self, b: BindingId) -> Result<'db, LocalId> { + fn binding_local(&self, b: BindingId) -> Result<'db, LocalId<'db>> { match self.result.binding_locals.get(b) { Some(it) => Ok(*it), None => { @@ -1968,9 +1996,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn drop_until_scope( &mut self, scope_index: usize, - mut current: BasicBlockId, + mut current: BasicBlockId<'db>, span: MirSpan, - ) -> BasicBlockId { + ) -> BasicBlockId<'db> { for scope in self.drop_scopes[scope_index..].to_vec().iter().rev() { self.emit_drop_and_storage_dead_for_scope(scope, &mut current, span); } @@ -1990,9 +2018,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { /// Don't call directly fn pop_drop_scope_internal( &mut self, - mut current: BasicBlockId, + mut current: BasicBlockId<'db>, span: MirSpan, - ) -> BasicBlockId { + ) -> BasicBlockId<'db> { let scope = self.drop_scopes.pop().unwrap(); self.emit_drop_and_storage_dead_for_scope(&scope, &mut current, span); current @@ -2000,9 +2028,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn pop_drop_scope_assert_finished( &mut self, - mut current: BasicBlockId, + mut current: BasicBlockId<'db>, span: MirSpan, - ) -> Result<'db, BasicBlockId> { + ) -> Result<'db, BasicBlockId<'db>> { current = self.pop_drop_scope_internal(current, span); if !self.drop_scopes.is_empty() { implementation_error!("Mismatched count between drop scope push and pops"); @@ -2012,12 +2040,12 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn emit_drop_and_storage_dead_for_scope( &mut self, - scope: &DropScope, - current: &mut Idx, + scope: &DropScope<'db>, + current: &mut Idx>, span: MirSpan, ) { for &l in scope.locals.iter().rev() { - if !self.result.locals[l].ty.clone().is_copy(self.db, self.owner) { + if !self.infcx.type_is_copy_modulo_regions(self.env.env, self.result.locals[l].ty) { let prev = std::mem::replace(current, self.new_basic_block()); self.set_terminator( prev, @@ -2032,12 +2060,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn cast_kind<'db>( db: &'db dyn HirDatabase, - source_ty: &Ty, - target_ty: &Ty, + source_ty: Ty<'db>, + target_ty: Ty<'db>, ) -> Result<'db, CastKind> { - let interner = DbInterner::new_with(db, None, None); - let from = CastTy::from_ty(db, source_ty.to_nextsolver(interner)); - let cast = CastTy::from_ty(db, target_ty.to_nextsolver(interner)); + 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 @@ -2056,7 +2083,7 @@ fn cast_kind<'db>( pub fn mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId, -) -> Result<'db, Arc> { +) -> Result<'db, Arc>> { let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); let body = db.body(owner); let infer = db.infer(owner); @@ -2068,29 +2095,34 @@ pub fn mir_body_for_closure_query<'db>( }; let (captures, kind) = infer.closure_info(closure); let mut ctx = MirLowerCtx::new(db, owner, &body, &infer); - let substs: &Substitution = &substs.to_chalk(ctx.interner); // 0 is return local - ctx.result.locals.alloc(Local { ty: infer[*root].to_chalk(ctx.interner) }); + ctx.result.locals.alloc(Local { ty: infer[*root] }); let closure_local = ctx.result.locals.alloc(Local { ty: match kind { - FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].to_chalk(ctx.interner), - FnTrait::FnMut | FnTrait::AsyncFnMut => { - TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].to_chalk(ctx.interner)) - .intern(Interner) - } - FnTrait::Fn | FnTrait::AsyncFn => { - TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].to_chalk(ctx.interner)) - .intern(Interner) - } + FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr], + FnTrait::FnMut | FnTrait::AsyncFnMut => Ty::new_ref( + ctx.interner(), + Region::error(ctx.interner()), + infer[expr], + Mutability::Mut, + ), + FnTrait::Fn | FnTrait::AsyncFn => Ty::new_ref( + ctx.interner(), + Region::error(ctx.interner()), + infer[expr], + Mutability::Not, + ), }, }); ctx.result.param_locals.push(closure_local); - let Some(sig) = ClosureSubst(substs).sig_ty(db).callable_sig(db) else { + let Some(sig) = + substs.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.callable_sig(ctx.interner()) + else { implementation_error!("closure has not callable sig"); }; let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr); let current = ctx.lower_params_and_bindings( - args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())), + args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, y)), None, |_| true, )?; @@ -2099,7 +2131,8 @@ pub fn mir_body_for_closure_query<'db>( let current = ctx.pop_drop_scope_assert_finished(current, root.into())?; ctx.set_terminator(current, TerminatorKind::Return, (*root).into()); } - let mut upvar_map: FxHashMap, usize)>> = FxHashMap::default(); + let mut upvar_map: FxHashMap, Vec<(&CapturedItem<'_>, usize)>> = + FxHashMap::default(); for (i, capture) in captures.iter().enumerate() { let local = ctx.binding_local(capture.place.local)?; upvar_map.entry(local).or_default().push((capture, i)); @@ -2164,7 +2197,7 @@ pub fn mir_body_for_closure_query<'db>( pub fn mir_body_query<'db>( db: &'db dyn HirDatabase, def: DefWithBodyId, -) -> Result<'db, Arc> { +) -> Result<'db, Arc>> { let krate = def.krate(db); let edition = krate.data(db).edition; let detail = match def { @@ -2200,7 +2233,7 @@ pub fn mir_body_query<'db>( pub(crate) fn mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _def: DefWithBodyId, -) -> Result<'db, Arc> { +) -> Result<'db, Arc>> { Err(MirLowerError::Loop) } @@ -2212,7 +2245,7 @@ pub fn lower_to_mir<'db>( // FIXME: root_expr should always be the body.body_expr, but since `X` in `[(); X]` doesn't have its own specific body yet, we // need to take this input explicitly. root_expr: ExprId, -) -> Result<'db, MirBody> { +) -> Result<'db, MirBody<'db>> { if infer.type_mismatches().next().is_some() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } @@ -2229,18 +2262,12 @@ pub fn lower_to_mir<'db>( if body.body_expr == root_expr { // otherwise it's an inline const, and has no parameter if let DefWithBodyId::FunctionId(fid) = owner { - let substs = TyBuilder::placeholder_subst(db, fid); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(fid.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); - let mut params = callable_sig.params().iter(); - let self_param = body.self_param.and_then(|id| Some((id, params.next()?.clone()))); + let callable_sig = + db.callable_item_signature(fid.into()).instantiate_identity().skip_binder(); + let mut params = callable_sig.inputs().iter(); + let self_param = body.self_param.and_then(|id| Some((id, params.next()?))); break 'b ctx.lower_params_and_bindings( - body.params.iter().zip(params).map(|(it, y)| (*it, y.clone())), + body.params.iter().zip(params).map(|(it, y)| (*it, y)), self_param, binding_picker, )?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index bd7b644618e7a..52f1412a06bf4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,10 +1,14 @@ //! MIR lowering for places -use crate::mir::{MutBorrowKind, Operand, OperandKind}; - -use super::*; use hir_def::FunctionId; use intern::sym; +use rustc_type_ir::inherent::{AdtDef, Region as _, Ty as _}; + +use super::*; +use crate::{ + mir::{MutBorrowKind, Operand, OperandKind}, + next_solver::Region, +}; macro_rules! not_supported { ($it: expr) => { @@ -16,8 +20,8 @@ impl<'db> MirLowerCtx<'_, 'db> { fn lower_expr_to_some_place_without_adjust( &mut self, expr_id: ExprId, - prev_block: BasicBlockId, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + prev_block: BasicBlockId<'db>, + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { let ty = self.expr_ty_without_adjust(expr_id); let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = @@ -31,12 +35,12 @@ impl<'db> MirLowerCtx<'_, 'db> { fn lower_expr_to_some_place_with_adjust( &mut self, expr_id: ExprId, - prev_block: BasicBlockId, + prev_block: BasicBlockId<'db>, adjustments: &[Adjustment<'db>], - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { let ty = adjustments .last() - .map(|it| it.target.to_chalk(self.interner)) + .map(|it| it.target) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = @@ -49,11 +53,11 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn lower_expr_as_place_with_adjust( &mut self, - current: BasicBlockId, + current: BasicBlockId<'db>, expr_id: ExprId, upgrade_rvalue: bool, adjustments: &[Adjustment<'db>], - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); @@ -89,11 +93,11 @@ impl<'db> MirLowerCtx<'_, 'db> { current, r, rest.last() - .map(|it| it.target.to_chalk(self.interner)) + .map(|it| it.target) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)), - last.target.to_chalk(self.interner), + last.target, expr_id.into(), - match od.0.to_chalk(self.interner) { + match od.0 { Some(Mutability::Mut) => true, Some(Mutability::Not) => false, None => { @@ -111,10 +115,10 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn lower_expr_as_place( &mut self, - current: BasicBlockId, + current: BasicBlockId<'db>, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { match self.infer.expr_adjustments.get(&expr_id) { Some(a) => self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a), None => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue), @@ -123,10 +127,10 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn lower_expr_as_place_without_adjust( &mut self, - current: BasicBlockId, + current: BasicBlockId<'db>, expr_id: ExprId, upgrade_rvalue: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| { if !upgrade_rvalue { return Err(MirLowerError::MutatingRvalue); @@ -149,9 +153,13 @@ impl<'db> MirLowerCtx<'_, 'db> { } ValueNs::StaticId(s) => { let ty = self.expr_ty_without_adjust(expr_id); - let ref_ty = - TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner); - let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); + let ref_ty = Ty::new_ref( + self.interner(), + Region::new_static(self.interner()), + ty, + Mutability::Not, + ); + let temp: Place<'db> = self.temp(ref_ty, current, expr_id.into())?.into(); self.push_assignment( current, temp, @@ -167,10 +175,10 @@ impl<'db> MirLowerCtx<'_, 'db> { } } Expr::UnaryOp { expr, op: hir_def::hir::UnaryOp::Deref } => { - let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { - TyKind::Ref(..) | TyKind::Raw(..) => true, + let is_builtin = match self.expr_ty_without_adjust(*expr).kind() { + TyKind::Ref(..) | TyKind::RawPtr(..) => true, TyKind::Adt(id, _) => { - if let Some(lang_item) = self.db.lang_attr(id.0.into()) { + if let Some(lang_item) = self.db.lang_attr(id.def_id().0.into()) { lang_item == LangItem::OwnedBox } else { false @@ -219,9 +227,9 @@ impl<'db> MirLowerCtx<'_, 'db> { Expr::Index { base, index } => { let base_ty = self.expr_ty_after_adjustments(*base); let index_ty = self.expr_ty_after_adjustments(*index); - if index_ty != TyBuilder::usize() + if !matches!(index_ty.kind(), TyKind::Uint(rustc_ast_ir::UintTy::Usize)) || !matches!( - base_ty.strip_reference().kind(Interner), + base_ty.strip_reference().kind(), TyKind::Array(..) | TyKind::Slice(..) ) { @@ -230,7 +238,6 @@ impl<'db> MirLowerCtx<'_, 'db> { "[overloaded index]".to_owned(), )); }; - let index_fn = (index_fn.0, index_fn.1.to_chalk(self.interner)); let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else { @@ -279,24 +286,26 @@ impl<'db> MirLowerCtx<'_, 'db> { fn lower_overloaded_index( &mut self, - current: BasicBlockId, - place: Place, - base_ty: Ty, - result_ty: Ty, - index_operand: Operand, + current: BasicBlockId<'db>, + place: Place<'db>, + base_ty: Ty<'db>, + result_ty: Ty<'db>, + index_operand: Operand<'db>, span: MirSpan, - index_fn: (FunctionId, Substitution), - ) -> Result<'db, Option<(Place, BasicBlockId)>> { + index_fn: (FunctionId, GenericArgs<'db>), + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { let mutability = match base_ty.as_reference() { Some((_, _, mutability)) => mutability, None => Mutability::Not, }; - let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner); - let mut result: Place = self.temp(result_ref, current, span)?.into(); - let index_fn_op = Operand::const_zst( - TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1) - .intern(Interner), - ); + let result_ref = + Ty::new_ref(self.interner(), Region::error(self.interner()), result_ty, mutability); + let mut result: Place<'db> = self.temp(result_ref, current, span)?.into(); + let index_fn_op = Operand::const_zst(Ty::new_fn_def( + self.interner(), + CallableDefId::FunctionId(index_fn.0).into(), + index_fn.1, + )); let Some(current) = self.lower_call( index_fn_op, Box::new([Operand { kind: OperandKind::Copy(place), span: None }, index_operand]), @@ -314,14 +323,14 @@ impl<'db> MirLowerCtx<'_, 'db> { fn lower_overloaded_deref( &mut self, - current: BasicBlockId, - place: Place, - source_ty: Ty, - target_ty: Ty, + current: BasicBlockId<'db>, + place: Place<'db>, + source_ty: Ty<'db>, + target_ty: Ty<'db>, span: MirSpan, mutability: bool, - ) -> Result<'db, Option<(Place, BasicBlockId)>> { - let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability { + ) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> { + let (mutability, trait_lang_item, trait_method_name, borrow_kind) = if !mutability { ( Mutability::Not, LangItem::Deref, @@ -336,9 +345,10 @@ impl<'db> MirLowerCtx<'_, 'db> { BorrowKind::Mut { kind: MutBorrowKind::Default }, ) }; - let ty_ref = TyKind::Ref(chalk_mut, error_lifetime(), source_ty.clone()).intern(Interner); - let target_ty_ref = TyKind::Ref(chalk_mut, error_lifetime(), target_ty).intern(Interner); - let ref_place: Place = self.temp(ty_ref, current, span)?.into(); + let error_region = Region::error(self.interner()); + let ty_ref = Ty::new_ref(self.interner(), error_region, source_ty, mutability); + let target_ty_ref = Ty::new_ref(self.interner(), error_region, target_ty, mutability); + let ref_place: Place<'db> = self.temp(ty_ref, current, span)?.into(); self.push_assignment(current, ref_place, Rvalue::Ref(borrow_kind, place), span); let deref_trait = self .resolve_lang_item(trait_lang_item)? @@ -348,14 +358,12 @@ impl<'db> MirLowerCtx<'_, 'db> { .trait_items(self.db) .method_by_name(&trait_method_name) .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?; - let deref_fn_op = Operand::const_zst( - TyKind::FnDef( - CallableDefId::FunctionId(deref_fn).to_chalk(self.db), - Substitution::from1(Interner, source_ty), - ) - .intern(Interner), - ); - let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); + let deref_fn_op = Operand::const_zst(Ty::new_fn_def( + self.interner(), + CallableDefId::FunctionId(deref_fn).into(), + GenericArgs::new_from_iter(self.interner(), [source_ty.into()]), + )); + let mut result: Place<'db> = self.temp(target_ty_ref, current, span)?.into(); let Some(current) = self.lower_call( deref_fn_op, Box::new([Operand { kind: OperandKind::Copy(ref_place), span: None }]), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 359c4fbb2e052..b1b86ab2c61b1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -1,18 +1,18 @@ //! MIR lowering for patterns use hir_def::{AssocItemId, hir::ExprId, signatures::VariantFields}; +use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _}; -use crate::next_solver::mapping::NextSolverToChalk; +use crate::next_solver::GenericArgs; use crate::{ BindingMode, mir::{ LocalId, MutBorrowKind, Operand, OperandKind, lower::{ - BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner, - MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem, - ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, Substitution, - SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs, - VariantId, + BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, MemoryMap, + MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem, ProjectionElem, + RecordFieldPat, ResolveValueResult, Result, Rvalue, SwitchTargets, TerminatorKind, + TupleFieldId, TupleId, Ty, TyKind, ValueNs, VariantId, }, }, }; @@ -63,11 +63,11 @@ impl<'db> MirLowerCtx<'_, 'db> { /// so it should be an empty block. pub(super) fn pattern_match( &mut self, - current: BasicBlockId, - current_else: Option, - cond_place: Place, + current: BasicBlockId<'db>, + current_else: Option>, + cond_place: Place<'db>, pattern: PatId, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { let (current, current_else) = self.pattern_match_inner( current, current_else, @@ -87,10 +87,10 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn pattern_match_assignment( &mut self, - current: BasicBlockId, - value: Place, + current: BasicBlockId<'db>, + value: Place<'db>, pattern: PatId, - ) -> Result<'db, BasicBlockId> { + ) -> Result<'db, BasicBlockId<'db>> { let (current, _) = self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?; Ok(current) @@ -99,9 +99,9 @@ impl<'db> MirLowerCtx<'_, 'db> { pub(super) fn match_self_param( &mut self, id: BindingId, - current: BasicBlockId, - local: LocalId, - ) -> Result<'db, (BasicBlockId, Option)> { + current: BasicBlockId<'db>, + local: LocalId<'db>, + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { self.pattern_match_binding( id, BindingMode::Move, @@ -114,12 +114,12 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_match_inner( &mut self, - mut current: BasicBlockId, - mut current_else: Option, - mut cond_place: Place, + mut current: BasicBlockId<'db>, + mut current_else: Option>, + mut cond_place: Place<'db>, pattern: PatId, mode: MatchingMode, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); cond_place.projection = self.result.projection_store.intern( cond_place @@ -135,8 +135,8 @@ impl<'db> MirLowerCtx<'_, 'db> { Pat::Missing => return Err(MirLowerError::IncompletePattern), Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { - let subst = match self.infer[pattern].to_chalk(self.interner).kind(Interner) { - TyKind::Tuple(_, s) => s.clone(), + let subst = match self.infer[pattern].kind() { + TyKind::Tuple(s) => s, _ => { return Err(MirLowerError::TypeError( "non tuple type matched with tuple pattern", @@ -148,7 +148,7 @@ impl<'db> MirLowerCtx<'_, 'db> { current_else, args, *ellipsis, - (0..subst.len(Interner)).map(|i| { + (0..subst.len()).map(|i| { PlaceElem::Field(Either::Right(TupleFieldId { tuple: TupleId(!0), // Dummy as it is unused index: i as u32, @@ -209,14 +209,11 @@ impl<'db> MirLowerCtx<'_, 'db> { } Pat::Range { start, end } => { let mut add_check = |l: &ExprId, binop| -> Result<'db, ()> { - let lv = self.lower_literal_or_const_to_operand( - self.infer[pattern].to_chalk(self.interner), - l, - )?; + let lv = self.lower_literal_or_const_to_operand(self.infer[pattern], l)?; let else_target = *current_else.get_or_insert_with(|| self.new_basic_block()); let next = self.new_basic_block(); - let discr: Place = - self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + let discr: Place<'db> = + self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, discr, @@ -252,12 +249,11 @@ impl<'db> MirLowerCtx<'_, 'db> { Pat::Slice { prefix, slice, suffix } => { if mode == MatchingMode::Check { // emit runtime length check for slice - if let TyKind::Slice(_) = - self.infer[pattern].to_chalk(self.interner).kind(Interner) - { + if let TyKind::Slice(_) = self.infer[pattern].kind() { let pattern_len = prefix.len() + suffix.len(); - let place_len: Place = - self.temp(TyBuilder::usize(), current, pattern.into())?.into(); + let place_len: Place<'db> = self + .temp(Ty::new_usize(self.interner()), current, pattern.into())? + .into(); self.push_assignment( current, place_len, @@ -287,10 +283,11 @@ impl<'db> MirLowerCtx<'_, 'db> { let c = Operand::from_concrete_const( pattern_len.to_le_bytes().into(), MemoryMap::default(), - TyBuilder::usize(), + Ty::new_usize(self.interner()), ); - let discr: Place = - self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + let discr: Place<'db> = self + .temp(Ty::new_bool(self.interner()), current, pattern.into())? + .into(); self.push_assignment( current, discr, @@ -398,26 +395,19 @@ impl<'db> MirLowerCtx<'_, 'db> { if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) && let AssocItemId::ConstId(c) = x.0 { - break 'b (c, x.1.to_chalk(self.interner)); + break 'b (c, x.1); } if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr { - break 'b (c, Substitution::empty(Interner)); + break 'b (c, GenericArgs::new_from_iter(self.interner(), [])); } not_supported!("path in pattern position that is not const or variant") }; - let tmp: Place = self - .temp(self.infer[pattern].to_chalk(self.interner), current, pattern.into())? - .into(); + let tmp: Place<'db> = + self.temp(self.infer[pattern], current, pattern.into())?.into(); let span = pattern.into(); - self.lower_const( - c.into(), - current, - tmp, - subst, - span, - self.infer[pattern].to_chalk(self.interner), - )?; - let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + self.lower_const(c.into(), current, tmp, subst, span)?; + let tmp2: Place<'db> = + self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, tmp2, @@ -444,10 +434,7 @@ impl<'db> MirLowerCtx<'_, 'db> { Pat::Lit(l) => match &self.body[*l] { Expr::Literal(l) => { if mode == MatchingMode::Check { - let c = self.lower_literal_to_operand( - self.infer[pattern].to_chalk(self.interner), - l, - )?; + let c = self.lower_literal_to_operand(self.infer[pattern], l)?; self.pattern_match_const(current_else, current, c, cond_place, pattern)? } else { (current, current_else) @@ -519,11 +506,11 @@ impl<'db> MirLowerCtx<'_, 'db> { &mut self, id: BindingId, mode: BindingMode, - cond_place: Place, + cond_place: Place<'db>, span: MirSpan, - current: BasicBlockId, - current_else: Option, - ) -> Result<'db, (BasicBlockId, Option)> { + current: BasicBlockId<'db>, + current_else: Option>, + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { let target_place = self.binding_local(id)?; self.push_storage_live(id, current)?; self.push_match_assignment(current, target_place, mode, cond_place, span); @@ -532,10 +519,10 @@ impl<'db> MirLowerCtx<'_, 'db> { fn push_match_assignment( &mut self, - current: BasicBlockId, - target_place: LocalId, + current: BasicBlockId<'db>, + target_place: LocalId<'db>, mode: BindingMode, - cond_place: Place, + cond_place: Place<'db>, span: MirSpan, ) { self.push_assignment( @@ -558,15 +545,16 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_match_const( &mut self, - current_else: Option, - current: BasicBlockId, - c: Operand, - cond_place: Place, + current_else: Option>, + current: BasicBlockId<'db>, + c: Operand<'db>, + cond_place: Place<'db>, pattern: Idx, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { let then_target = self.new_basic_block(); let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - let discr: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into(); + let discr: Place<'db> = + self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into(); self.push_assignment( current, discr, @@ -591,14 +579,14 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_matching_variant( &mut self, - cond_place: Place, + cond_place: Place<'db>, variant: VariantId, - mut current: BasicBlockId, + mut current: BasicBlockId<'db>, span: MirSpan, - mut current_else: Option, + mut current_else: Option>, shape: AdtPatternShape<'_>, mode: MatchingMode, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { Ok(match variant { VariantId::EnumVariantId(v) => { if mode == MatchingMode::Check { @@ -647,11 +635,11 @@ impl<'db> MirLowerCtx<'_, 'db> { shape: AdtPatternShape<'_>, variant_data: &VariantFields, v: VariantId, - current: BasicBlockId, - current_else: Option, - cond_place: &Place, + current: BasicBlockId<'db>, + current_else: Option>, + cond_place: &Place<'db>, mode: MatchingMode, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { Ok(match shape { AdtPatternShape::Record { args } => { let it = args @@ -690,12 +678,12 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_match_adt( &mut self, - mut current: BasicBlockId, - mut current_else: Option, - args: impl Iterator, - cond_place: &Place, + mut current: BasicBlockId<'db>, + mut current_else: Option>, + args: impl Iterator, PatId)>, + cond_place: &Place<'db>, mode: MatchingMode, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { for (proj, arg) in args { let cond_place = cond_place.project(proj, &mut self.result.projection_store); (current, current_else) = @@ -706,14 +694,14 @@ impl<'db> MirLowerCtx<'_, 'db> { fn pattern_match_tuple_like( &mut self, - current: BasicBlockId, - current_else: Option, + current: BasicBlockId<'db>, + current_else: Option>, args: &[PatId], ellipsis: Option, - fields: impl DoubleEndedIterator + Clone, - cond_place: &Place, + fields: impl DoubleEndedIterator> + Clone, + cond_place: &Place<'db>, mode: MatchingMode, - ) -> Result<'db, (BasicBlockId, Option)> { + ) -> Result<'db, (BasicBlockId<'db>, Option>)> { let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); let it = al .iter() 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 index ee088bd06ca6b..38fc7ad78a287 100644 --- 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 @@ -1,14 +1,8 @@ -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, setup_tracing, test_db::TestDB}; +use crate::{db::HirDatabase, setup_tracing, test_db::TestDB}; -fn lower_mir( - #[rust_analyzer::rust_fixture] ra_fixture: &str, -) -> FxHashMap, ()>> { +fn lower_mir(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); crate::attach_db(&db, || { @@ -20,14 +14,9 @@ fn lower_mir( 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.map_err(drop)) - }) - .collect() + for func in funcs { + _ = db.mir_body(func.into()); + } }) } 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 4bc81a4806ec6..745f73948d08c 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 @@ -7,232 +7,129 @@ //! //! So the monomorphization should be called even if the substitution is empty. -use std::mem; - -use chalk_ir::{ - ConstData, DebruijnIndex, - fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}, -}; use hir_def::DefWithBodyId; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; +use rustc_type_ir::{ + FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt, +}; use triomphe::Arc; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; +use crate::next_solver::{Const, ConstKind, Region, RegionKind}; use crate::{ - Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, - consteval::{intern_const_scalar, unknown_const}, - db::{HirDatabase, InternedClosure, InternedClosureId}, - from_placeholder_idx, - generics::{Generics, generics}, - infer::normalize, + TraitEnvironment, + db::{HirDatabase, InternedClosureId}, + next_solver::{ + DbInterner, GenericArgs, Ty, TyKind, TypingMode, + infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + references_non_lt_error, + }, }; use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind}; -macro_rules! not_supported { - ($it: expr) => { - return Err(MirLowerError::NotSupported(format!($it))) - }; -} - -struct Filler<'a, 'db> { - db: &'db dyn HirDatabase, +struct Filler<'db> { + infcx: InferCtxt<'db>, trait_env: Arc>, - subst: &'a Substitution, - generics: Option, - interner: DbInterner<'db>, + subst: GenericArgs<'db>, } -impl<'a, 'db> FallibleTypeFolder for Filler<'a, 'db> { + +impl<'db> FallibleTypeFolder> for Filler<'db> { type Error = MirLowerError<'db>; - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { - self + fn cx(&self) -> DbInterner<'db> { + self.infcx.interner } - fn interner(&self) -> Interner { - Interner - } + fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result, Self::Error> { + if !ty.has_type_flags(TypeFlags::HAS_ALIAS | TypeFlags::HAS_PARAM) { + return Ok(ty); + } - fn try_fold_ty( - &mut self, - ty: Ty, - outer_binder: DebruijnIndex, - ) -> std::result::Result { - match ty.kind(Interner) { - TyKind::AssociatedType(id, subst) => { - // I don't know exactly if and why this is needed, but it looks like `normalize_ty` likes - // this kind of associated types. - Ok(TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { - associated_ty_id: *id, - substitution: subst.clone().try_fold_with(self, outer_binder)?, - })) - .intern(Interner)) - } - 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 { - crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { - let infer = self.db.infer(func.into()); - let filler = &mut Filler { - db: self.db, - trait_env: self.trait_env.clone(), - subst: &subst, - generics: Some(generics(self.db, func.into())), - interner: self.interner, - }; - filler.try_fold_ty( - infer.type_of_rpit[idx.to_nextsolver(self.interner)] - .to_chalk(self.interner), - outer_binder, - ) - } - crate::ImplTraitId::TypeAliasImplTrait(..) => { - not_supported!("type alias impl trait"); - } - crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { - not_supported!("async block impl trait"); - } - } + match ty.kind() { + TyKind::Alias(..) => { + // First instantiate params. + let ty = ty.try_super_fold_with(self)?; + + let mut ocx = ObligationCtxt::new(&self.infcx); + let ty = ocx + .structurally_normalize_ty(&ObligationCause::dummy(), self.trait_env.env, ty) + .map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?; + ty.try_super_fold_with(self) } - _ => ty.try_super_fold_with(self.as_dyn(), outer_binder), + TyKind::Param(param) => Ok(self + .subst + .as_slice() + .get(param.index as usize) + .and_then(|arg| arg.ty()) + .ok_or_else(|| { + MirLowerError::GenericArgNotProvided(param.id.into(), self.subst) + })?), + _ => ty.try_super_fold_with(self), } } - fn try_fold_free_placeholder_const( - &mut self, - _ty: chalk_ir::Ty, - idx: chalk_ir::PlaceholderIndex, - _outer_binder: DebruijnIndex, - ) -> std::result::Result, Self::Error> { - 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"); + fn try_fold_const(&mut self, ct: Const<'db>) -> Result, Self::Error> { + let ConstKind::Param(param) = ct.kind() else { + return ct.try_super_fold_with(self); }; - Ok(self - .subst - .as_slice(Interner) - .get(idx) - .and_then(|it| it.constant(Interner)) - .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))? - .clone()) + self.subst + .as_slice() + .get(param.index as usize) + .and_then(|arg| arg.konst()) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst)) } - fn try_fold_free_placeholder_ty( - &mut self, - idx: chalk_ir::PlaceholderIndex, - _outer_binder: DebruijnIndex, - ) -> std::result::Result { - 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"); + fn try_fold_region(&mut self, region: Region<'db>) -> Result, Self::Error> { + let RegionKind::ReEarlyParam(param) = region.kind() else { + return Ok(region); }; - Ok(self - .subst - .as_slice(Interner) - .get(idx) - .and_then(|it| it.ty(Interner)) - .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))? - .clone()) - } - - fn try_fold_const( - &mut self, - constant: chalk_ir::Const, - outer_binder: DebruijnIndex, - ) -> Result, Self::Error> { - let next_ty = normalize( - self.db, - self.trait_env.clone(), - constant.data(Interner).ty.clone().try_fold_with(self, outer_binder)?, - ); - ConstData { ty: next_ty, value: constant.data(Interner).value.clone() } - .intern(Interner) - .try_super_fold_with(self, outer_binder) + self.subst + .as_slice() + .get(param.index as usize) + .and_then(|arg| arg.region()) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst)) } } -impl<'a, 'db> Filler<'a, 'db> { - fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError<'db>> { - let tmp = mem::replace(ty, TyKind::Error.intern(Interner)); - *ty = normalize( - self.db, - self.trait_env.clone(), - tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?, - ); - Ok(()) - } - - fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError<'db>> { - let tmp = mem::replace(c, unknown_const(c.data(Interner).ty.clone())); - *c = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; - Ok(()) +impl<'db> Filler<'db> { + fn new( + db: &'db dyn HirDatabase, + env: Arc>, + subst: GenericArgs<'db>, + ) -> Self { + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + Self { infcx, trait_env: env, subst } } - fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError<'db>> { - let tmp = mem::replace(ty, Substitution::empty(Interner)); - *ty = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?; - Ok(()) + fn fill> + Copy>( + &mut self, + t: &mut T, + ) -> Result<(), MirLowerError<'db>> { + // Can't deep normalized as that'll try to normalize consts and fail. + *t = t.try_fold_with(self)?; + if references_non_lt_error(t) { + Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned())) + } else { + Ok(()) + } } - fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> { + fn fill_operand(&mut self, op: &mut Operand<'db>) -> Result<(), MirLowerError<'db>> { match &mut op.kind { - OperandKind::Constant(c) => { - match &c.data(Interner).value { - chalk_ir::ConstValue::BoundVar(b) => { - let resolved = self - .subst - .as_slice(Interner) - .get(b.index) - .ok_or_else(|| { - MirLowerError::GenericArgNotProvided( - self.generics - .as_ref() - .and_then(|it| it.iter().nth(b.index)) - .and_then(|(id, _)| match id { - hir_def::GenericParamId::ConstParamId(id) => { - Some(hir_def::TypeOrConstParamId::from(id)) - } - hir_def::GenericParamId::TypeParamId(id) => { - Some(hir_def::TypeOrConstParamId::from(id)) - } - _ => None, - }) - .unwrap(), - self.subst.clone(), - ) - })? - .assert_const_ref(Interner); - *c = resolved.clone(); - } - chalk_ir::ConstValue::InferenceVar(_) - | chalk_ir::ConstValue::Placeholder(_) => {} - chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { - crate::ConstScalar::UnevaluatedConst(const_id, subst) => { - let mut subst = subst.clone(); - self.fill_subst(&mut subst)?; - *c = intern_const_scalar( - crate::ConstScalar::UnevaluatedConst(*const_id, subst), - c.data(Interner).ty.clone(), - ); - } - crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (), - }, - } - self.fill_const(c)?; + OperandKind::Constant { konst, ty } => { + self.fill(konst)?; + self.fill(ty)?; } OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (), } Ok(()) } - fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError<'db>> { + fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> { for (_, l) in body.locals.iter_mut() { - self.fill_ty(&mut l.ty)?; + self.fill(&mut l.ty)?; } for (_, bb) in body.basic_blocks.iter_mut() { for statement in &mut bb.statements { @@ -245,20 +142,20 @@ impl<'a, 'db> Filler<'a, 'db> { match ak { super::AggregateKind::Array(ty) | super::AggregateKind::Tuple(ty) - | super::AggregateKind::Closure(ty) => self.fill_ty(ty)?, - super::AggregateKind::Adt(_, subst) => self.fill_subst(subst)?, + | super::AggregateKind::Closure(ty) => self.fill(ty)?, + super::AggregateKind::Adt(_, subst) => self.fill(subst)?, super::AggregateKind::Union(_, _) => (), } } Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => { - self.fill_ty(ty)?; + self.fill(ty)?; } Rvalue::Use(op) => { self.fill_operand(op)?; } Rvalue::Repeat(op, len) => { self.fill_operand(op)?; - self.fill_const(len)?; + self.fill(len)?; } Rvalue::Ref(_, _) | Rvalue::Len(_) @@ -312,12 +209,10 @@ impl<'a, 'db> Filler<'a, 'db> { pub fn monomorphized_mir_body_query<'db>( db: &'db dyn HirDatabase, owner: DefWithBodyId, - subst: Substitution, + subst: GenericArgs<'db>, trait_env: Arc>, -) -> Result, MirLowerError<'db>> { - let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); - let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); - let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner }; +) -> Result>, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env, subst); let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; @@ -327,22 +222,19 @@ pub fn monomorphized_mir_body_query<'db>( pub(crate) fn monomorphized_mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _: DefWithBodyId, - _: Substitution, + _: GenericArgs<'db>, _: Arc>, -) -> Result, MirLowerError<'db>> { +) -> Result>, MirLowerError<'db>> { Err(MirLowerError::Loop) } pub fn monomorphized_mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId, - subst: Substitution, + subst: GenericArgs<'db>, trait_env: Arc>, -) -> Result, MirLowerError<'db>> { - let InternedClosure(owner, _) = db.lookup_intern_closure(closure); - let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); - let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); - let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner }; +) -> Result>, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env, subst); let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index aad54f884385e..e46edb8159189 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -11,8 +11,7 @@ use hir_expand::{Lookup, name::Name}; use la_arena::ArenaMap; use crate::{ - ClosureId, - db::HirDatabase, + db::{HirDatabase, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind}, }; @@ -37,8 +36,8 @@ macro_rules! wln { }; } -impl MirBody { - pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { +impl<'db> MirBody<'db> { + pub fn pretty_print(&self, db: &'db dyn HirDatabase, display_target: DisplayTarget) -> String { let hir_body = db.body(self.owner); let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target); ctx.for_body(|this| match ctx.body.owner { @@ -81,7 +80,7 @@ impl MirBody { // String with lines is rendered poorly in `dbg` macros, which I use very much, so this // function exists to solve that. - pub fn dbg(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> impl Debug { + pub fn dbg(&self, db: &'db dyn HirDatabase, display_target: DisplayTarget) -> impl Debug { struct StringDbg(String); impl Debug for StringDbg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -92,17 +91,17 @@ impl MirBody { } } -struct MirPrettyCtx<'a> { - body: &'a MirBody, +struct MirPrettyCtx<'a, 'db> { + body: &'a MirBody<'db>, hir_body: &'a Body, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, result: String, indent: String, - local_to_binding: ArenaMap, + local_to_binding: ArenaMap, BindingId>, display_target: DisplayTarget, } -impl Write for MirPrettyCtx<'_> { +impl Write for MirPrettyCtx<'_, '_> { fn write_str(&mut self, s: &str) -> std::fmt::Result { let mut it = s.split('\n'); // note: `.lines()` is wrong here self.write(it.next().unwrap_or_default()); @@ -114,12 +113,12 @@ impl Write for MirPrettyCtx<'_> { } } -enum LocalName { - Unknown(LocalId), - Binding(Name, LocalId), +enum LocalName<'db> { + Unknown(LocalId<'db>), + Binding(Name, LocalId<'db>), } -impl HirDisplay for LocalName { +impl<'db> HirDisplay for LocalName<'db> { fn hir_fmt( &self, f: &mut crate::display::HirFormatter<'_>, @@ -133,8 +132,8 @@ impl HirDisplay for LocalName { } } -impl<'a> MirPrettyCtx<'a> { - fn for_body(&mut self, name: impl FnOnce(&mut MirPrettyCtx<'_>)) { +impl<'a, 'db> MirPrettyCtx<'a, 'db> { + fn for_body(&mut self, name: impl FnOnce(&mut MirPrettyCtx<'_, 'db>)) { name(self); self.with_block(|this| { this.locals(); @@ -146,8 +145,8 @@ impl<'a> MirPrettyCtx<'a> { } } - fn for_closure(&mut self, closure: ClosureId) { - let body = match self.db.mir_body_for_closure(closure.into()) { + fn for_closure(&mut self, closure: InternedClosureId) { + let body = match self.db.mir_body_for_closure(closure) { Ok(it) => it, Err(e) => { wln!(self, "// error in {closure:?}: {e:?}"); @@ -168,7 +167,7 @@ impl<'a> MirPrettyCtx<'a> { self.indent = ctx.indent; } - fn with_block(&mut self, f: impl FnOnce(&mut MirPrettyCtx<'_>)) { + fn with_block(&mut self, f: impl FnOnce(&mut MirPrettyCtx<'_, 'db>)) { self.indent += " "; wln!(self, "{{"); f(self); @@ -180,9 +179,9 @@ impl<'a> MirPrettyCtx<'a> { } fn new( - body: &'a MirBody, + body: &'a MirBody<'db>, hir_body: &'a Body, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> Self { let local_to_binding = body.local_to_binding_map(); @@ -217,14 +216,14 @@ impl<'a> MirPrettyCtx<'a> { } } - fn local_name(&self, local: LocalId) -> LocalName { + fn local_name(&self, local: LocalId<'db>) -> LocalName<'db> { match self.local_to_binding.get(local) { Some(b) => LocalName::Binding(self.hir_body[*b].name.clone(), local), None => LocalName::Unknown(local), } } - fn basic_block_id(&self, basic_block_id: BasicBlockId) -> String { + fn basic_block_id(&self, basic_block_id: BasicBlockId<'db>) -> String { format!("'bb{}", u32::from(basic_block_id.into_raw())) } @@ -312,8 +311,12 @@ impl<'a> MirPrettyCtx<'a> { } } - fn place(&mut self, p: &Place) { - fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) { + fn place(&mut self, p: &Place<'db>) { + fn f<'db>( + this: &mut MirPrettyCtx<'_, 'db>, + local: LocalId<'db>, + projections: &[PlaceElem<'db>], + ) { let Some((last, head)) = projections.split_last() else { // no projection w!(this, "{}", this.local_name(local).display_test(this.db, this.display_target)); @@ -373,19 +376,19 @@ impl<'a> MirPrettyCtx<'a> { f(self, p.local, p.projection.lookup(&self.body.projection_store)); } - fn operand(&mut self, r: &Operand) { + fn operand(&mut self, r: &Operand<'db>) { match &r.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { // MIR at the time of writing doesn't have difference between move and copy, so we show them // equally. Feel free to change it. self.place(p); } - OperandKind::Constant(c) => w!(self, "Const({})", self.hir_display(c)), + OperandKind::Constant { konst, .. } => w!(self, "Const({})", self.hir_display(konst)), OperandKind::Static(s) => w!(self, "Static({:?})", s), } } - fn rvalue(&mut self, r: &Rvalue) { + fn rvalue(&mut self, r: &Rvalue<'db>) { match r { Rvalue::Use(op) => self.operand(op), Rvalue::Ref(r, p) => { @@ -475,7 +478,7 @@ impl<'a> MirPrettyCtx<'a> { } } - fn operand_list(&mut self, it: &[Operand]) { + fn operand_list(&mut self, it: &[Operand<'db>]) { let mut it = it.iter(); if let Some(first) = it.next() { self.operand(first); @@ -486,7 +489,10 @@ impl<'a> MirPrettyCtx<'a> { } } - fn hir_display(&self, ty: &'a T) -> impl Display + 'a { + fn hir_display<'b, T: HirDisplay>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T> + where + 'db: 'b, + { ty.display_test(self.db, self.display_target) .with_closure_style(ClosureStyle::ClosureWithSubst) } 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 aae48eeaf9346..da86fa3ae53c0 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,6 +4,7 @@ use std::hash::Hash; use hir_def::{ConstParamId, TypeOrConstParamId}; use intern::{Interned, Symbol}; +use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::{try_visit, visit::VisitorResult}; use rustc_type_ir::{ BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, @@ -23,7 +24,7 @@ use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, pub type ConstKind<'db> = rustc_type_ir::ConstKind>; pub type UnevaluatedConst<'db> = rustc_type_ir::UnevaluatedConst>; -#[salsa::interned(constructor = new_, debug)] +#[salsa::interned(constructor = new_)] pub struct Const<'db> { #[returns(ref)] kind_: InternedWrapperNoDebug>>, @@ -61,6 +62,21 @@ impl<'db> Const<'db> { Const::new(interner, ConstKind::Placeholder(placeholder)) } + pub fn new_valtree( + interner: DbInterner<'db>, + ty: Ty<'db>, + memory: Box<[u8]>, + memory_map: MemoryMap<'db>, + ) -> Self { + Const::new( + interner, + ConstKind::Value(ValueConst { + ty, + value: Valtree::new(ConstBytes { memory, memory_map }), + }), + ) + } + pub fn is_ct_infer(&self) -> bool { matches!(&self.inner().internee, ConstKind::Infer(_)) } @@ -77,6 +93,12 @@ impl<'db> Const<'db> { } } +impl<'db> std::fmt::Debug for Const<'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) @@ -135,9 +157,12 @@ impl ParamConst { /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TypeFoldable, TypeVisitable)] pub struct ValueConst<'db> { pub(crate) ty: Ty<'db>, + // FIXME: Should we ignore this for TypeVisitable, TypeFoldable? + #[type_visitable(ignore)] + #[type_foldable(identity)] pub(crate) value: Valtree<'db>, } @@ -158,33 +183,15 @@ impl<'db> rustc_type_ir::inherent::ValueConst> for ValueConst<'d } } -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<'db>(pub Box<[u8]>, pub MemoryMap<'db>); +pub struct ConstBytes<'db> { + pub memory: Box<[u8]>, + pub memory_map: MemoryMap<'db>, +} impl Hash for ConstBytes<'_> { fn hash(&self, state: &mut H) { - self.0.hash(state) + self.memory.hash(state) } } @@ -212,7 +219,7 @@ impl<'db> Valtree<'db> { } } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable)] pub struct ExprConst; impl rustc_type_ir::inherent::ParamLike for ParamConst { @@ -412,29 +419,6 @@ impl<'db> PlaceholderLike> for PlaceholderConst { } } -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, 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 918a311ea9ccc..3e4c4171bedde 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, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, - StaticId, StructId, TraitId, TypeAliasId, UnionId, + AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, + ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -119,6 +119,16 @@ impl From for SolverDefId { } } +impl From for SolverDefId { + #[inline] + fn from(value: GeneralConstId) -> Self { + match value { + GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), + GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), + } + } +} + impl TryFrom for GenericDefId { type Error = SolverDefId; 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 89a4d9202a75d..79527dac2fef3 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 @@ -2,6 +2,7 @@ use hir_def::{GenericDefId, GenericParamId}; use intern::{Interned, Symbol}; +use macros::{TypeFoldable, TypeVisitable}; use rustc_type_ir::inherent::Const as _; use rustc_type_ir::{ ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, @@ -23,7 +24,7 @@ use super::{ interned_vec_db, }; -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub enum GenericArg<'db> { Ty(Ty<'db>), Lifetime(Region<'db>), @@ -55,6 +56,13 @@ impl<'db> GenericArg<'db> { } } + pub fn konst(self) -> Option> { + match self.kind() { + GenericArgKind::Const(konst) => Some(konst), + _ => None, + } + } + pub fn region(self) -> Option> { match self.kind() { GenericArgKind::Lifetime(r) => Some(r), @@ -72,7 +80,7 @@ impl<'db> From> for GenericArg<'db> { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub enum Term<'db> { Ty(Ty<'db>), Const(Const<'db>), @@ -130,39 +138,6 @@ impl<'db> IntoKind for GenericArg<'db> { } } -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, @@ -553,36 +528,6 @@ impl<'db> From> for Term<'db> { } } -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, 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 392e2b9329a04..79b0a2933236b 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 @@ -1,6 +1,7 @@ use std::ops::ControlFlow; use hir_def::{ImplId, TraitId}; +use macros::{TypeFoldable, TypeVisitable}; use rustc_type_ir::{ Interner, solve::{BuiltinImplSource, CandidateSource, Certainty, inspect::ProbeKind}, @@ -177,7 +178,7 @@ pub type SelectionResult<'db, T> = Result, SelectionError<'db>>; /// ### The type parameter `N` /// /// See explanation on `ImplSourceUserDefinedData`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub enum ImplSource<'db, N> { /// ImplSource identifying a particular impl. UserDefined(ImplSourceUserDefinedData<'db, N>), @@ -242,8 +243,10 @@ impl<'db, N> ImplSource<'db, N> { /// 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)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] pub struct ImplSourceUserDefinedData<'db, N> { + #[type_visitable(ignore)] + #[type_foldable(identity)] pub impl_def_id: ImplId, pub args: GenericArgs<'db>, pub nested: Vec, 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 9fa1fa7fb4404..bc905c2e0b958 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 @@ -8,6 +8,7 @@ use std::{ }; use hir_def::TraitId; +use macros::{TypeFoldable, TypeVisitable}; use rustc_type_ir::elaborate::Elaboratable; use rustc_type_ir::{ PredicatePolarity, Upcast, @@ -65,8 +66,10 @@ impl ObligationCause { /// 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)] +#[derive(Clone, Debug, TypeVisitable, TypeFoldable)] pub struct Obligation<'db, T> { + #[type_foldable(identity)] + #[type_visitable(ignore)] /// The reason we have to prove this thing. pub cause: ObligationCause, @@ -117,39 +120,6 @@ impl<'db> Elaboratable> for PredicateObligation<'db> { } } -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 } 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 4a0ede35ac752..cd1667527ba65 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 @@ -1,77 +1,81 @@ //! Things related to the Interner in the next-trait-solver. -#![allow(unused)] +#![allow(unused)] // FIXME(next-solver): Remove this. + +use std::{fmt, ops::ControlFlow}; pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; 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, GenericDefId, TypeAliasId, VariantId}; -use hir_def::{AttrDefId, Lookup}; -use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId}; +use hir_def::{ + AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup, + StructId, TypeAliasId, UnionId, VariantId, + lang_item::LangItem, + signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, +}; use intern::sym::non_exhaustive; use intern::{Interned, impl_internable, sym}; use la_arena::Idx; use rustc_abi::{Align, ReprFlags, ReprOptions}; +use rustc_ast_ir::visit::VisitorResult; 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::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; -use rustc_type_ir::solve::SizedTraitKind; +use rustc_index::{IndexVec, bit_set::DenseBitSet}; use rustc_type_ir::{ - AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, - ImplPolarity, InferTy, ProjectionPredicate, TraitPredicate, TraitRef, Upcast, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex, + EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, + ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt, + UniverseIndex, Upcast, Variance, WithCachedTypeInfo, + elaborate::{self, elaborate}, + error::TypeError, + inherent::{ + self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _, + Region as _, SliceLike as _, Span as _, Ty as _, + }, + ir_print, + lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}, + relate, + solve::SizedTraitKind, }; use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; -use std::fmt; -use std::ops::ControlFlow; use syntax::ast::SelfParamKind; +use tracing::debug; 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::infer::InferCtxt; -use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; -use crate::next_solver::{ - AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, - CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, - RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, +use crate::{ + ConstScalar, FnAbi, Interner, + db::HirDatabase, + lower_nextsolver::{self, TyLoweringContext}, + method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}, + next_solver::{ + AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, + CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, + RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, + TypingMode, + infer::{ + DbInternerInferExt, InferCtxt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, + util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}, + }, }; -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, + ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints, ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv, ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate, - PredicateKind, Term, Ty, TyKind, Tys, ValueConst, + PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst, abi::Safety, fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate}, - generics::Generics, + generics::{Generics, generics}, mapping::ChalkToNextSolver, region::{ BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region, }, + util::sizedness_constraint_for_ty, }; -use super::{ClauseKind, SolverDefId, Valtree}; #[macro_export] #[doc(hidden)] @@ -1102,7 +1106,15 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> AliasTyKind { match alias.def_id { SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, - SolverDefId::TypeAliasId(_) => AliasTyKind::Projection, + SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { + ItemContainerId::ImplId(impl_) + if self.db.impl_signature(impl_).target_trait.is_none() => + { + AliasTyKind::Inherent + } + ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => AliasTyKind::Projection, + _ => AliasTyKind::Free, + }, _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1113,7 +1125,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ) -> rustc_type_ir::AliasTermKind { match alias.def_id { SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, - SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, + SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { + ItemContainerId::ImplId(impl_) + if self.db.impl_signature(impl_).target_trait.is_none() => + { + AliasTermKind::InherentTy + } + ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => { + AliasTermKind::ProjectionTy + } + _ => AliasTermKind::FreeTy, + }, + // rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections + // via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it. SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } @@ -1676,8 +1700,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { - // FIXME - false + self.db.impl_signature(impl_def_id.0).is_default() } #[tracing::instrument(skip(self), ret)] @@ -1731,7 +1754,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed { - panic!("Bug encountered in next-trait-solver.") + panic!("Bug encountered in next-trait-solver: {}", msg.to_string()) } fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool { @@ -1929,7 +1952,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { false } - fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool { + // FIXME(next-solver): Make this a query? Can this make cycles? + fn impl_specializes( + self, + specializing_impl_def_id: Self::ImplId, + parent_impl_def_id: Self::ImplId, + ) -> bool { false } 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 b32a5ec2928bf..1a5982cc00d36 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 @@ -539,7 +539,7 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { ConstScalar::Bytes(bytes, memory) => { rustc_type_ir::ConstKind::Value(ValueConst::new( data.ty.to_nextsolver(interner), - ConstBytes(bytes.clone(), memory.clone()), + ConstBytes { memory: bytes.clone(), memory_map: memory.clone() }, )) } ConstScalar::UnevaluatedConst(c, subst) => { @@ -1710,8 +1710,10 @@ pub fn convert_const_for_result<'db>( let bytes = value_const.value.inner(); let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { // 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()) + interned: ConstScalar::Bytes(bytes.memory.clone(), unsafe { + std::mem::transmute::, MemoryMap<'static>>( + bytes.memory_map.clone(), + ) }), }); return chalk_ir::ConstData { 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 1623fa342a736..9dda9d06da276 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 @@ -3,6 +3,7 @@ use std::cmp::Ordering; use intern::Interned; +use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::try_visit; use rustc_type_ir::{ self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags, @@ -424,7 +425,7 @@ impl<'db> rustc_type_ir::TypeSuperVisitable> for Clauses<'db> { 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)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable)] pub struct ParamEnv<'db> { pub(crate) clauses: Clauses<'db>, } @@ -435,28 +436,6 @@ impl<'db> ParamEnv<'db> { } } -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 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 a161423da4d76..2457447ee39ba 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 @@ -149,13 +149,9 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn fetch_eligible_assoc_item( &self, goal_trait_ref: rustc_type_ir::TraitRef, - trait_assoc_def_id: ::DefId, + trait_assoc_def_id: SolverDefId, impl_id: ImplIdWrapper, - ) -> Result::DefId>, ErrorGuaranteed> { - let trait_assoc_id = match trait_assoc_def_id { - SolverDefId::TypeAliasId(id) => id, - _ => panic!("Unexpected SolverDefId"), - }; + ) -> Result, ErrorGuaranteed> { let trait_ = self .0 .interner @@ -167,18 +163,47 @@ impl<'db> SolverDelegate for SolverContext<'db> { .def_id .0; let trait_data = trait_.trait_items(self.0.interner.db()); - let id = - 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; - 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)) + let impl_items = impl_id.0.impl_items(self.0.interner.db()); + let id = match trait_assoc_def_id { + SolverDefId::TypeAliasId(trait_assoc_id) => { + let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id + && *impl_assoc_name == trait_assoc_data.name + { + Some(impl_assoc_id) + } else { + None + } + }) + .map(SolverDefId::TypeAliasId) + } + SolverDefId::ConstId(trait_assoc_id) => { + let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id); + let trait_assoc_name = trait_assoc_data + .name + .as_ref() + .expect("unnamed consts should not get passed to the solver"); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id + && impl_assoc_name == trait_assoc_name + { + Some(impl_assoc_id) + } else { + None + } + }) + .map(SolverDefId::ConstId) + } + _ => panic!("Unexpected SolverDefId"), + }; + Ok(id) } fn is_transmutable( @@ -200,9 +225,9 @@ impl<'db> SolverDelegate for SolverContext<'db> { SolverDefId::StaticId(c) => GeneralConstId::StaticId(c), _ => unreachable!(), }; - let subst = uv.args.to_chalk(self.interner); + let subst = uv.args; let ec = self.cx().db.const_eval(c, subst, None).ok()?; - Some(ec.to_nextsolver(self.interner)) + Some(ec) } fn compute_goal_fast_path( 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 11ca0b03eb3dc..c5969120c9665 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 @@ -8,11 +8,10 @@ use hir_def::{AdtId, 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::TyVid; use rustc_type_ir::{ BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy, - IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo, + IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo, inherent::{ Abi, AdtDef as _, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _, @@ -24,14 +23,13 @@ use rustc_type_ir::{ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; -use crate::next_solver::{AdtDef, Binder}; use crate::{ FnAbi, db::HirDatabase, interner::InternedWrapperNoDebug, next_solver::{ - CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg, - PolyFnSig, TypeAliasIdWrapper, + AdtDef, Binder, CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, + GenericArg, PolyFnSig, Region, TypeAliasIdWrapper, abi::Safety, util::{CoroutineArgsExt, IntegerTypeExt}, }, @@ -392,7 +390,7 @@ impl<'db> Ty<'db> { /// 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() + references_non_lt_error(&self) } pub fn callable_sig(self, interner: DbInterner<'db>) -> Option>> { @@ -409,6 +407,13 @@ impl<'db> Ty<'db> { } } + pub fn as_reference(self) -> Option<(Ty<'db>, Region<'db>, Mutability)> { + match self.kind() { + TyKind::Ref(lifetime, ty, mutability) => Some((ty, lifetime, mutability)), + _ => None, + } + } + pub fn as_reference_or_ptr(self) -> Option<(Ty<'db>, Rawness, Mutability)> { match self.kind() { TyKind::Ref(_, ty, mutability) => Some((ty, Rawness::Ref, mutability)), @@ -417,6 +422,18 @@ impl<'db> Ty<'db> { } } + pub fn strip_references(self) -> Ty<'db> { + let mut t = self; + while let TyKind::Ref(_lifetime, ty, _mutability) = t.kind() { + t = ty; + } + t + } + + pub fn strip_reference(self) -> Ty<'db> { + self.as_reference().map_or(self, |(ty, _, _)| ty) + } + /// Replace infer vars with errors. /// /// This needs to be called for every type that may contain infer vars and is yielded to outside inference, @@ -428,6 +445,10 @@ impl<'db> Ty<'db> { } } +pub fn references_non_lt_error<'db, T: TypeVisitableExt>>(t: &T) -> bool { + t.references_error() && t.visit_with(&mut ReferencesNonLifetimeError).is_break() +} + struct ReferencesNonLifetimeError; impl<'db> TypeVisitor> for ReferencesNonLifetimeError { 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 427c4bb68423d..e989e4c006fff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -20,11 +20,10 @@ use hir_expand::name::Name; use intern::sym; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; -use rustc_type_ir::inherent::{GenericArgs, IntoKind, SliceLike}; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use span::Edition; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef, TraitRefExt, Ty, @@ -34,7 +33,7 @@ use crate::{ mir::pad16, next_solver::{ DbInterner, - mapping::{ChalkToNextSolver, convert_args_for_result}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_args_for_result}, }, to_chalk_trait_id, }; @@ -196,15 +195,6 @@ pub(super) fn associated_type_by_name_including_super_traits( pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution); impl<'a> ClosureSubst<'a> { - 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, db: &dyn HirDatabase) -> Ty { let interner = DbInterner::new_with(db, None, None); let subst = @@ -310,10 +300,12 @@ impl FallibleTypeFolder for UnevaluatedConstEvaluatorFolder<'_> { if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned { - if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) { - return Ok(eval); + let interner = DbInterner::conjure(); + if let Ok(eval) = self.db.const_eval(*id, subst.to_nextsolver(interner), None) { + return Ok(eval.to_chalk(interner)); } else { - return Ok(unknown_const(constant.data(Interner).ty.clone())); + return Ok(unknown_const(constant.data(Interner).ty.to_nextsolver(interner)) + .to_chalk(interner)); } } Ok(constant) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index cce2564a9e6dd..59038c2656c9d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -75,7 +75,7 @@ use hir_ty::{ 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}, + consteval_chalk::{ConstExt, try_const_usize, unknown_const_as_generic}, diagnostics::BodyValidationDiagnostic, direct_super_traits, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -2153,8 +2153,11 @@ impl DefWithBody { mir::MirSpan::Unknown => continue, }; acc.push( - MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span } - .into(), + MovedOutOfRef { + ty: Type::new_for_crate(krate, moof.ty.to_chalk(interner)), + span, + } + .into(), ) } let mol = &borrowck_result.mutability_of_locals; @@ -2649,9 +2652,10 @@ impl Function { db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, ) -> Result> { + let interner = DbInterner::new_with(db, None, None); let body = db.monomorphized_mir_body( self.id.into(), - Substitution::empty(Interner), + GenericArgs::new_from_iter(interner, []), db.trait_environment(self.id.into()), )?; let (result, output) = interpret_mir(db, body, false, None)?; @@ -2933,8 +2937,10 @@ impl Const { /// Evaluate the constant. pub fn eval(self, db: &dyn HirDatabase) -> Result> { - db.const_eval(self.id.into(), Substitution::empty(Interner), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) + let interner = DbInterner::new_with(db, None, None); + let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner); + db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) + .map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty }) } } @@ -2947,6 +2953,7 @@ impl HasVisibility for Const { pub struct EvaluatedConst { def: DefWithBodyId, const_: hir_ty::Const, + ty: hir_ty::Ty, } impl EvaluatedConst { @@ -2955,6 +2962,7 @@ impl EvaluatedConst { } pub fn render_debug<'db>(&self, db: &'db dyn HirDatabase) -> Result> { + let interner = DbInterner::new_with(db, None, None); let data = self.const_.data(Interner); if let TyKind::Scalar(s) = data.ty.kind(Interner) && matches!(s, Scalar::Int(_) | Scalar::Uint(_)) @@ -2972,7 +2980,12 @@ impl EvaluatedConst { return Ok(result); } } - mir::render_const_using_debug_impl(db, self.def, &self.const_) + mir::render_const_using_debug_impl( + db, + self.def, + self.const_.to_nextsolver(interner), + self.ty.to_nextsolver(interner), + ) } } @@ -3011,8 +3024,10 @@ impl Static { /// Evaluate the static initializer. pub fn eval(self, db: &dyn HirDatabase) -> Result> { - db.const_eval(self.id.into(), Substitution::empty(Interner), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) + let interner = DbInterner::new_with(db, None, None); + let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner); + db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) + .map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty }) } } 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 1faa3c4165fdd..a4bc3e8f1a13a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -35,7 +35,6 @@ use hir_expand::{ mod_path::{ModPath, PathKind, path}, name::{AsName, Name}, }; -use hir_ty::next_solver::GenericArgs; use hir_ty::{ Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy, Substitution, ToChalk, TraitEnvironment, Ty, TyKind, TyLoweringContext, @@ -47,7 +46,8 @@ use hir_ty::{ lang_items::lang_items_for_bin_op, method_resolution, next_solver::{ - DbInterner, + DbInterner, GenericArgs, TypingMode, + infer::DbInternerInferExt, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, }; @@ -1439,12 +1439,9 @@ impl<'db> SourceAnalyzer<'db> { None => return (const_id, subs), }; let env = db.trait_environment_for_body(owner); - method_resolution::lookup_impl_const( - DbInterner::new_with(db, None, None), - env, - const_id, - subs, - ) + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + method_resolution::lookup_impl_const(&infcx, env, const_id, subs) } fn lang_trait_fn( 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 8bc0b3f6ab3b9..df1800616803e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -6306,6 +6306,8 @@ const FOO$0: (&str, &str) = { ); } +// FIXME(next-solver): this fails to normalize the const, probably due to the solver +// refusing to give the impl because of the error type. #[test] fn hover_const_eval_in_generic_trait() { // Doesn't compile, but we shouldn't crash. @@ -6327,12 +6329,16 @@ fn test() { *FOO* ```rust - ra_test_fixture::S + ra_test_fixture::Trait ``` ```rust - const FOO: bool = true + const FOO: bool = false ``` + + --- + + `Self` = `S<{unknown}>` "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index d0539abe28281..1e272fe3ba827 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -6,7 +6,7 @@ //! } //! ``` use hir::{ - ChalkTyInterner, DefWithBody, + DefWithBody, db::{DefDatabase as _, HirDatabase as _}, mir::{MirSpan, TerminatorKind}, }; @@ -46,7 +46,7 @@ pub(super) fn hints( if !place.projection.is_empty() { continue; // Ignore complex cases for now } - if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() { + if mir.locals[place.local].ty.as_adt().is_none() { continue; // Arguably only ADTs have significant drop impls } let Some(&binding_idx) = local_to_binding.get(place.local) else { diff --git a/src/tools/rust-analyzer/crates/macros/Cargo.toml b/src/tools/rust-analyzer/crates/macros/Cargo.toml new file mode 100644 index 0000000000000..8184cc6d1c03d --- /dev/null +++ b/src/tools/rust-analyzer/crates/macros/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "macros" +version = "0.0.0" +repository.workspace = true +description = "Proc macros for rust-analyzer." + +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1" +quote = "1" +syn = "2.0.9" +synstructure = "0.13.0" diff --git a/src/tools/rust-analyzer/crates/macros/src/lib.rs b/src/tools/rust-analyzer/crates/macros/src/lib.rs new file mode 100644 index 0000000000000..8bafcf498c510 --- /dev/null +++ b/src/tools/rust-analyzer/crates/macros/src/lib.rs @@ -0,0 +1,164 @@ +//! Proc macros for rust-analyzer. + +use quote::{ToTokens, quote}; +use syn::parse_quote; +use synstructure::decl_derive; + +decl_derive!( + [TypeFoldable, attributes(type_foldable)] => + /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). + /// + /// The fold will produce a value of the same struct or enum variant as the input, with + /// each field respectively folded using the `TypeFoldable` implementation for its type. + /// However, if a field of a struct or an enum variant is annotated with + /// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its + /// type is not required to implement `TypeFoldable`). + type_foldable_derive +); +decl_derive!( + [TypeVisitable, attributes(type_visitable)] => + /// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported). + /// + /// Each field of the struct or enum variant will be visited in definition order, using the + /// `TypeVisitable` implementation for its type. However, if a field of a struct or an enum + /// variant is annotated with `#[type_visitable(ignore)]` then that field will not be + /// visited (and its type is not required to implement `TypeVisitable`). + type_visitable_derive +); + +fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + // ignore fields with #[type_visitable(ignore)] + s.filter(|bi| { + let mut ignored = false; + + bi.ast().attrs.iter().for_each(|attr| { + if !attr.path().is_ident("type_visitable") { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident("ignore") { + ignored = true; + } + Ok(()) + }); + }); + + !ignored + }); + + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "db") { + s.add_impl_generic(parse_quote! { 'db }); + } + + s.add_bounds(synstructure::AddBounds::Generics); + let body_visit = s.each(|bind| { + quote! { + match ::rustc_type_ir::VisitorResult::branch( + ::rustc_type_ir::TypeVisitable::visit_with(#bind, __visitor) + ) { + ::core::ops::ControlFlow::Continue(()) => {}, + ::core::ops::ControlFlow::Break(r) => { + return ::rustc_type_ir::VisitorResult::from_residual(r); + }, + } + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); + + s.bound_impl( + quote!(::rustc_type_ir::TypeVisitable<::hir_ty::next_solver::DbInterner<'db>>), + quote! { + fn visit_with<__V: ::rustc_type_ir::TypeVisitor<::hir_ty::next_solver::DbInterner<'db>>>( + &self, + __visitor: &mut __V + ) -> __V::Result { + match *self { #body_visit } + <__V::Result as ::rustc_type_ir::VisitorResult>::output() + } + }, + ) +} + +fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "db") { + s.add_impl_generic(parse_quote! { 'db }); + } + + s.add_bounds(synstructure::AddBounds::Generics); + s.bind_with(|_| synstructure::BindStyle::Move); + let try_body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::TypeFoldable::try_fold_with(#bind, __folder)? + } + } + }) + }); + + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::TypeFoldable::fold_with(#bind, __folder) + } + } + }) + }); + + s.bound_impl( + quote!(::rustc_type_ir::TypeFoldable<::hir_ty::next_solver::DbInterner<'db>>), + quote! { + fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<::hir_ty::next_solver::DbInterner<'db>>>( + self, + __folder: &mut __F + ) -> Result { + Ok(match self { #try_body_fold }) + } + + fn fold_with<__F: ::rustc_type_ir::TypeFolder<::hir_ty::next_solver::DbInterner<'db>>>( + self, + __folder: &mut __F + ) -> Self { + match self { #body_fold } + } + }, + ) +} + +fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool { + let mut ignored = false; + attrs.iter().for_each(|attr| { + if !attr.path().is_ident(name) { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident(meta) { + ignored = true; + } + Ok(()) + }); + }); + + ignored +} From 9170a7dffc05ab9f6ff389cf3605197eba93d3fd Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 12 Oct 2025 09:45:18 +0300 Subject: [PATCH 53/59] Migrate `hir` types to next solver --- .../crates/hir-ty/src/autoderef.rs | 23 +- .../crates/hir-ty/src/chalk_ext.rs | 327 +--- .../crates/hir-ty/src/consteval_chalk.rs | 91 +- .../crates/hir-ty/src/infer/coerce.rs | 19 +- .../crates/hir-ty/src/infer/path.rs | 16 +- .../crates/hir-ty/src/infer/unify.rs | 71 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 398 ++--- .../rust-analyzer/crates/hir-ty/src/lower.rs | 44 +- .../crates/hir-ty/src/lower/path.rs | 30 +- .../crates/hir-ty/src/lower_nextsolver.rs | 23 +- .../hir-ty/src/lower_nextsolver/path.rs | 43 +- .../crates/hir-ty/src/method_resolution.rs | 54 +- .../crates/hir-ty/src/next_solver/consts.rs | 12 +- .../crates/hir-ty/src/next_solver/def_id.rs | 9 + .../hir-ty/src/next_solver/generic_arg.rs | 15 + .../crates/hir-ty/src/next_solver/interner.rs | 2 +- .../crates/hir-ty/src/next_solver/region.rs | 11 +- .../crates/hir-ty/src/next_solver/ty.rs | 209 ++- .../rust-analyzer/crates/hir-ty/src/traits.rs | 64 +- .../rust-analyzer/crates/hir/src/attrs.rs | 14 +- .../crates/hir/src/diagnostics.rs | 24 +- .../rust-analyzer/crates/hir/src/display.rs | 6 +- .../crates/hir/src/has_source.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 1411 +++++++---------- .../rust-analyzer/crates/hir/src/semantics.rs | 18 +- .../crates/hir/src/source_analyzer.rs | 227 ++- .../crates/hir/src/term_search/tactics.rs | 22 +- .../crates/ide/src/hover/render.rs | 8 +- 28 files changed, 1272 insertions(+), 1921 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 0be00afe7bf45..abd1b8b155d2a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -5,23 +5,21 @@ use std::fmt; -use hir_def::TraitId; -use hir_def::{TypeAliasId, lang_item::LangItem}; +use hir_def::{TraitId, TypeAliasId, lang_item::LangItem}; use rustc_type_ir::inherent::{IntoKind, Ty as _}; use tracing::debug; use triomphe::Arc; -use crate::next_solver::TraitRef; -use crate::next_solver::infer::InferOk; -use crate::next_solver::infer::traits::Obligation; use crate::{ TraitEnvironment, db::HirDatabase, infer::unify::InferenceTable, next_solver::{ - Ty, TyKind, - infer::traits::{ObligationCause, PredicateObligations}, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + Canonical, TraitRef, Ty, TyKind, + infer::{ + InferOk, + traits::{Obligation, ObligationCause, PredicateObligations}, + }, obligation_ctxt::ObligationCtxt, }, }; @@ -38,17 +36,16 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20; pub fn autoderef<'db>( db: &'db dyn HirDatabase, env: Arc>, - ty: crate::Canonical, -) -> impl Iterator + use<> { + ty: Canonical<'db, Ty<'db>>, +) -> impl Iterator> + use<'db> { let mut table = InferenceTable::new(db, env); - let interner = table.interner(); - let ty = table.instantiate_canonical(ty.to_nextsolver(interner)); + let ty = table.instantiate_canonical(ty); let mut autoderef = Autoderef::new_no_tracking(&mut table, ty); 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).to_chalk(interner); + let resolved = autoderef.table.resolve_completely(ty); // 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. 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 6956a0a123283..e9960374c6f5f 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 @@ -1,66 +1,32 @@ //! Various extensions traits for Chalk types. -use chalk_ir::{ - FloatTy, IntTy, Mutability, Scalar, TyVariableKind, TypeOutlives, UintTy, cast::Cast, -}; -use hir_def::{ - DefWithBodyId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId, - builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint}, - hir::generics::{TypeOrConstParamData, TypeParamProvenance}, - lang_item::LangItem, - type_ref::Rawness, -}; +use chalk_ir::Mutability; +use hir_def::{FunctionId, ItemContainerId, Lookup, TraitId}; use crate::{ - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, - ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, - 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, - next_solver::{DbInterner, mapping::NextSolverToChalk}, - to_chalk_trait_id, + AdtId, Binders, CallableDefId, CallableSig, DynTy, Interner, Lifetime, ProjectionTy, + Substitution, ToChalk, TraitRef, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id, utils::ClosureSubst, }; -pub trait TyExt { +pub(crate) trait TyExt { fn is_unit(&self) -> bool; - fn is_integral(&self) -> bool; - fn is_scalar(&self) -> bool; - fn is_floating_point(&self) -> bool; - fn is_never(&self) -> bool; - fn is_str(&self) -> bool; fn is_unknown(&self) -> bool; fn contains_unknown(&self) -> bool; - fn is_ty_var(&self) -> bool; - fn is_union(&self) -> bool; fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; - fn as_builtin(&self) -> Option; fn as_tuple(&self) -> Option<&Substitution>; - fn as_closure(&self) -> Option; fn as_fn_def(&self, db: &dyn HirDatabase) -> Option; fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; - fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)>; - fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>; - fn as_generic_def(&self, db: &dyn HirDatabase) -> Option; fn callable_def(&self, db: &dyn HirDatabase) -> Option; fn callable_sig(&self, db: &dyn HirDatabase) -> Option; fn strip_references(&self) -> &Ty; - fn strip_reference(&self) -> &Ty; /// If this is a `dyn Trait`, returns that trait. fn dyn_trait(&self) -> Option; - - fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option>; - fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option; - fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool; - - /// FIXME: Get rid of this, it's not a good abstraction - fn equals_ctor(&self, other: &Ty) -> bool; } impl TyExt for Ty { @@ -68,33 +34,6 @@ impl TyExt for Ty { matches!(self.kind(Interner), TyKind::Tuple(0, _)) } - fn is_integral(&self) -> bool { - matches!( - self.kind(Interner), - TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) - | TyKind::InferenceVar(_, TyVariableKind::Integer) - ) - } - - fn is_scalar(&self) -> bool { - matches!(self.kind(Interner), TyKind::Scalar(_)) - } - - fn is_floating_point(&self) -> bool { - matches!( - self.kind(Interner), - TyKind::Scalar(Scalar::Float(_)) | TyKind::InferenceVar(_, TyVariableKind::Float) - ) - } - - fn is_never(&self) -> bool { - matches!(self.kind(Interner), TyKind::Never) - } - - fn is_str(&self) -> bool { - matches!(self.kind(Interner), TyKind::Str) - } - fn is_unknown(&self) -> bool { matches!(self.kind(Interner), TyKind::Error) } @@ -103,14 +42,6 @@ impl TyExt for Ty { self.data(Interner).flags.contains(TypeFlags::HAS_ERROR) } - fn is_ty_var(&self) -> bool { - matches!(self.kind(Interner), TyKind::InferenceVar(_, _)) - } - - fn is_union(&self) -> bool { - matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_)))) - } - fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { match self.kind(Interner) { TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), @@ -118,37 +49,6 @@ impl TyExt for Ty { } } - fn as_builtin(&self) -> Option { - match self.kind(Interner) { - TyKind::Str => Some(BuiltinType::Str), - TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool), - TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char), - TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty { - FloatTy::F128 => BuiltinFloat::F128, - FloatTy::F64 => BuiltinFloat::F64, - FloatTy::F32 => BuiltinFloat::F32, - FloatTy::F16 => BuiltinFloat::F16, - })), - TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity { - IntTy::Isize => BuiltinInt::Isize, - IntTy::I8 => BuiltinInt::I8, - IntTy::I16 => BuiltinInt::I16, - IntTy::I32 => BuiltinInt::I32, - IntTy::I64 => BuiltinInt::I64, - IntTy::I128 => BuiltinInt::I128, - })), - TyKind::Scalar(Scalar::Uint(ity)) => Some(BuiltinType::Uint(match ity { - UintTy::Usize => BuiltinUint::Usize, - UintTy::U8 => BuiltinUint::U8, - UintTy::U16 => BuiltinUint::U16, - UintTy::U32 => BuiltinUint::U32, - UintTy::U64 => BuiltinUint::U64, - UintTy::U128 => BuiltinUint::U128, - })), - _ => None, - } - } - fn as_tuple(&self) -> Option<&Substitution> { match self.kind(Interner) { TyKind::Tuple(_, substs) => Some(substs), @@ -156,13 +56,6 @@ impl TyExt for Ty { } } - fn as_closure(&self) -> Option { - match self.kind(Interner) { - TyKind::Closure(id, _) => Some(*id), - _ => None, - } - } - fn as_fn_def(&self, db: &dyn HirDatabase) -> Option { match self.callable_def(db) { Some(CallableDefId::FunctionId(func)) => Some(func), @@ -177,33 +70,6 @@ impl TyExt for Ty { } } - fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)> { - match self.kind(Interner) { - TyKind::Raw(mutability, ty) => Some((ty, *mutability)), - _ => None, - } - } - - fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { - match self.kind(Interner) { - TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)), - TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)), - _ => None, - } - } - - fn as_generic_def(&self, db: &dyn HirDatabase) -> Option { - match *self.kind(Interner) { - TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), - TyKind::FnDef(callable, ..) => { - Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable))) - } - TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), - TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), - _ => None, - } - } - fn callable_def(&self, db: &dyn HirDatabase) -> Option { match self.kind(Interner) { &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)), @@ -244,177 +110,6 @@ impl TyExt for Ty { } t } - - fn strip_reference(&self) -> &Ty { - self.as_reference().map_or(self, |(ty, _, _)| 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) => { - handle_async_block_type_impl_trait(def) - } - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - db.return_type_impl_traits(func).map(|it| { - let data = - (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - data.substitute(Interner, &subst).into_value_and_skipped_binders().0 - }) - } - ImplTraitId::TypeAliasImplTrait(alias, idx) => { - db.type_alias_impl_traits(alias).map(|it| { - let data = - (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - data.substitute(Interner, &subst).into_value_and_skipped_binders().0 - }) - } - } - } - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()) - { - ImplTraitId::ReturnTypeImplTrait(func, idx) => { - db.return_type_impl_traits(func).map(|it| { - let data = - (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - data.substitute(Interner, &opaque_ty.substitution) - }) - } - ImplTraitId::TypeAliasImplTrait(alias, idx) => { - db.type_alias_impl_traits(alias).map(|it| { - let data = - (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - data.substitute(Interner, &opaque_ty.substitution) - }) - } - ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { - return handle_async_block_type_impl_trait(def); - } - }; - - predicates.map(|it| it.into_value_and_skipped_binders().0) - } - TyKind::Placeholder(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 { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::ArgumentImplTrait => { - let substs = TyBuilder::placeholder_subst(db, id.parent); - let predicates = db - .generic_predicates(id.parent) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match wc.skip_binders() { - WhereClause::Implemented(tr) => { - &tr.self_type_parameter(Interner) == self - } - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(proj), - ty: _, - }) => &proj.self_type_parameter(db) == self, - WhereClause::TypeOutlives(TypeOutlives { ty, lifetime: _ }) => { - ty == self - } - _ => false, - }) - .collect::>(); - - Some(predicates) - } - _ => None, - }, - _ => None, - } - } - _ => None, - } - } - - fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - TyKind::AssociatedType(id, ..) => match from_assoc_type_id(*id).lookup(db).container { - ItemContainerId::TraitId(trait_id) => Some(trait_id), - _ => None, - }, - TyKind::Alias(AliasTy::Projection(projection_ty)) => { - match from_assoc_type_id(projection_ty.associated_ty_id).lookup(db).container { - ItemContainerId::TraitId(trait_id) => Some(trait_id), - _ => None, - } - } - _ => None, - } - } - - fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool { - let crate_id = owner.module(db).krate(); - let Some(copy_trait) = LangItem::Copy.resolve_trait(db, crate_id) else { - return false; - }; - let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); - let env = db.trait_environment_for_body(owner); - let goal = Canonical { - value: InEnvironment::new( - &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), - trait_ref.cast(Interner), - ), - binders: CanonicalVarKinds::empty(Interner), - }; - !db.trait_solve(crate_id, None, goal).no_solution() - } - - fn equals_ctor(&self, other: &Ty) -> bool { - match (self.kind(Interner), other.kind(Interner)) { - (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, - (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => { - true - } - (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2, - (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2, - (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => { - ty_id == ty_id2 - } - (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2, - (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2, - (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..)) - | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => { - mutability == mutability2 - } - ( - TyKind::Function(FnPointer { num_binders, sig, .. }), - TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }), - ) => num_binders == num_binders2 && sig == sig2, - (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => { - cardinality == cardinality2 - } - (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true, - (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2, - _ => false, - } - } } pub trait ProjectionTyExt { @@ -445,9 +140,8 @@ impl ProjectionTyExt for ProjectionTy { } } -pub trait DynTyExt { +pub(crate) trait DynTyExt { fn principal(&self) -> Option>>; - fn principal_id(&self) -> Option>; } impl DynTyExt for DynTy { @@ -461,13 +155,6 @@ impl DynTyExt for DynTy { }) }) } - - fn principal_id(&self) -> Option> { - self.bounds.skip_binders().interned().first().and_then(|b| match b.skip_binders() { - crate::WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id), - _ => None, - }) - } } pub trait TraitRefExt { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs index 458974384dca3..07b783ea92925 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs @@ -11,48 +11,15 @@ use stdx::never; use crate::{ Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, + TraitEnvironment, Ty, db::HirDatabase, generics::Generics, lower::ParamLoweringMode, - next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, - }, + next_solver::{DbInterner, mapping::ChalkToNextSolver}, to_placeholder_idx, }; -use super::mir::pad16; - -/// Extension trait for [`Const`] -pub trait ConstExt { - /// Is a [`Const`] unknown? - fn is_unknown(&self) -> bool; -} - -impl ConstExt for Const { - fn is_unknown(&self) -> bool { - match self.data(Interner).value { - // interned Unknown - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Unknown, - }) => true, - - // interned concrete anything else - chalk_ir::ConstValue::Concrete(..) => false, - - _ => { - tracing::error!( - "is_unknown was called on a non-concrete constant value! {:?}", - self - ); - true - } - } - } -} - -pub fn path_to_const<'g>( +pub(crate) fn path_to_const<'g>( db: &dyn HirDatabase, resolver: &Resolver<'_>, path: &Path, @@ -94,7 +61,7 @@ pub fn path_to_const<'g>( } } -pub fn unknown_const(ty: Ty) -> Const { +pub(crate) fn unknown_const(ty: Ty) -> Const { ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }), @@ -102,18 +69,18 @@ pub fn unknown_const(ty: Ty) -> Const { .intern(Interner) } -pub fn unknown_const_as_generic(ty: Ty) -> GenericArg { +pub(crate) fn unknown_const_as_generic(ty: Ty) -> GenericArg { unknown_const(ty).cast(Interner) } /// Interns a constant scalar with the given type -pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { +pub(crate) fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) } .intern(Interner) } /// Interns a constant scalar with the given type -pub fn intern_const_ref( +pub(crate) fn intern_const_ref( db: &dyn HirDatabase, value: &LiteralConstRef, ty: Ty, @@ -139,47 +106,3 @@ pub fn intern_const_ref( }; intern_const_scalar(bytes, ty) } - -/// Interns a possibly-unknown target usize -pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: Crate) -> Const { - intern_const_ref( - db, - &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), - TyBuilder::usize(), - krate, - ) -} - -pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { - let interner = DbInterner::new_with(db, None, None); - match &c.data(Interner).value { - chalk_ir::ConstValue::BoundVar(_) => None, - chalk_ir::ConstValue::InferenceVar(_) => None, - chalk_ir::ConstValue::Placeholder(_) => None, - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(it, false))), - ConstScalar::UnevaluatedConst(c, subst) => { - let ec = db.const_eval(*c, subst.to_nextsolver(interner), None).ok()?; - try_const_usize(db, &ec.to_chalk(interner)) - } - _ => None, - }, - } -} - -pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option { - let interner = DbInterner::new_with(db, None, None); - match &c.data(Interner).value { - chalk_ir::ConstValue::BoundVar(_) => None, - chalk_ir::ConstValue::InferenceVar(_) => None, - chalk_ir::ConstValue::Placeholder(_) => None, - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))), - ConstScalar::UnevaluatedConst(c, subst) => { - let ec = db.const_eval(*c, subst.to_nextsolver(interner), None).ok()?; - try_const_isize(db, &ec.to_chalk(interner)) - } - _ => None, - }, - } -} 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 10c1f9c980917..ce5c98979d4d9 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 @@ -46,7 +46,7 @@ use rustc_ast_ir::Mutability; use rustc_type_ir::{ BoundVar, TypeAndMut, error::TypeError, - inherent::{Const as _, GenericArg as _, IntoKind, Region as _, Safety, SliceLike, Ty as _}, + inherent::{Const as _, GenericArg as _, IntoKind, Safety, SliceLike, Ty as _}, }; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -59,15 +59,15 @@ use crate::{ infer::{AllowTwoPhase, InferenceContext, TypeMismatch, unify::InferenceTable}, next_solver::{ Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper, - ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, - PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty, TyKind, + Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed, + GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, 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, }, utils::TargetFeatureIsSafeInTarget, @@ -1525,7 +1525,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { pub fn could_coerce<'db>( db: &'db dyn HirDatabase, env: Arc>, - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, + tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { coerce(db, env, tys).is_ok() } @@ -1533,12 +1533,11 @@ pub fn could_coerce<'db>( fn coerce<'db>( db: &'db dyn HirDatabase, env: Arc>, - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, -) -> Result<(Vec>, crate::Ty), TypeError>> { + tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, +) -> Result<(Vec>, Ty<'db>), TypeError>> { let mut table = InferenceTable::new(db, env); let interner = table.interner(); - let tys = tys.to_nextsolver(interner); - let ((ty1_with_vars, ty2_with_vars), vars) = table.infer_ctxt.instantiate_canonical(&tys); + let ((ty1_with_vars, ty2_with_vars), vars) = table.infer_ctxt.instantiate_canonical(tys); let cause = ObligationCause::new(); // FIXME: Target features. @@ -1614,5 +1613,5 @@ fn coerce<'db>( &mut fallback_const, &mut fallback_region, ); - Ok((adjustments, ty.to_chalk(interner))) + Ok((adjustments, ty)) } 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 110f767967c10..f70ed90b953a0 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 @@ -1,7 +1,7 @@ //! Path expression resolution. use hir_def::{ - AdtId, AssocItemId, GenericDefId, GenericParamId, ItemContainerId, Lookup, + AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, }; @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::{SliceLike, Ty as _}; use stdx::never; use crate::{ - InferenceDiagnostic, ValueTyDefId, consteval, + InferenceDiagnostic, ValueTyDefId, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, lower_nextsolver::LifetimeElisionKind, @@ -118,22 +118,12 @@ impl<'db> InferenceContext<'_, 'db> { self.interner(), generic_def.into(), self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)), - |_, _, id, _| self.error_param(id), + |_, _, id, _| GenericArg::error_from_id(self.interner(), id), ); Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)) } - fn error_param(&mut self, id: GenericParamId) -> GenericArg<'db> { - match id { - GenericParamId::TypeParamId(_) => self.types.error.into(), - GenericParamId::ConstParamId(id) => { - consteval::unknown_const_as_generic(self.db.const_param_ty_ns(id)) - } - GenericParamId::LifetimeParamId(_) => self.types.re_error.into(), - } - } - pub(super) fn resolve_value_path_inner( &mut self, path: &Path, 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 89bab4e59c94c..114c90c7becfa 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 @@ -2,29 +2,27 @@ use std::fmt; -use chalk_ir::cast::Cast; -use hir_def::GenericParamId; -use hir_def::{AdtId, lang_item::LangItem}; +use hir_def::{AdtId, GenericParamId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::{DebruijnIndex, InferConst, InferTy, RegionVid}; use rustc_type_ir::{ - TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UpcastFrom, + DebruijnIndex, InferConst, InferTy, RegionVid, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, UpcastFrom, inherent::{Const as _, IntoKind, Ty as _}, solve::{Certainty, GoalSource}, }; use smallvec::SmallVec; use triomphe::Arc; -use crate::next_solver::{Binder, ConstKind, GenericArgs, RegionKind, SolverDefId}; use crate::{ - Interner, TraitEnvironment, + TraitEnvironment, db::{HirDatabase, InternedOpaqueTyId}, infer::InferenceContext, next_solver::{ - self, AliasTy, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, Predicate, - PredicateKind, Region, SolverDefIds, TraitRef, Ty, TyKind, TypingMode, + self, AliasTy, Binder, Canonical, ClauseKind, Const, ConstKind, DbInterner, + ErrorGuaranteed, GenericArg, GenericArgs, Predicate, PredicateKind, Region, RegionKind, + SolverDefId, SolverDefIds, TraitRef, Ty, TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ DbInternerInferExt, DefineOpaqueTypes, InferCtxt, InferOk, InferResult, @@ -33,7 +31,6 @@ use crate::{ traits::{Obligation, ObligationCause, PredicateObligation}, }, inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, - mapping::{ChalkToNextSolver, NextSolverToChalk}, obligation_ctxt::ObligationCtxt, }, traits::{ @@ -115,10 +112,10 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { /// This means that there may be some unresolved goals that actually set bounds for the placeholder /// type for the types to unify. For example `Option` and `Option` unify although there is /// unresolved goal `T = U`. -pub fn could_unify( - db: &dyn HirDatabase, - env: Arc>, - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, +pub fn could_unify<'db>( + db: &'db dyn HirDatabase, + env: Arc>, + tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { could_unify_impl(db, env, tys, |ctxt| ctxt.select_where_possible()) } @@ -127,32 +124,28 @@ pub fn could_unify( /// /// This means that placeholder types are not considered to unify if there are any bounds set on /// them. For example `Option` and `Option` do not unify as we cannot show that `T = U` -pub fn could_unify_deeply( - db: &dyn HirDatabase, - env: Arc>, - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, +pub fn could_unify_deeply<'db>( + db: &'db dyn HirDatabase, + env: Arc>, + tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, ) -> bool { could_unify_impl(db, env, tys, |ctxt| ctxt.select_all_or_error()) } -fn could_unify_impl( - db: &dyn HirDatabase, - env: Arc>, - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, - select: for<'a, 'db> fn(&mut ObligationCtxt<'a, 'db>) -> Vec>, +fn could_unify_impl<'db>( + db: &'db dyn HirDatabase, + env: Arc>, + tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>, + select: for<'a> fn(&mut ObligationCtxt<'a, 'db>) -> Vec>, ) -> bool { let interner = DbInterner::new_with(db, Some(env.krate), env.block); // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things), // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT // and async blocks. - let infcx = interner.infer_ctxt().build(TypingMode::Analysis { - defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), - }); + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::dummy(); let at = infcx.at(&cause, env.env); - let vars = make_substitutions(tys, &infcx); - let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner).to_nextsolver(interner); - let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner).to_nextsolver(interner); + let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys); let mut ctxt = ObligationCtxt::new(&infcx); let can_unify = at .eq(DefineOpaqueTypes::No, ty1_with_vars, ty2_with_vars) @@ -161,26 +154,6 @@ fn could_unify_impl( can_unify && select(&mut ctxt).is_empty() } -fn make_substitutions( - tys: &crate::Canonical<(crate::Ty, crate::Ty)>, - infcx: &InferCtxt<'_>, -) -> crate::Substitution { - let interner = infcx.interner; - crate::Substitution::from_iter( - Interner, - tys.binders.iter(Interner).map(|it| match &it.kind { - chalk_ir::VariableKind::Ty(_) => infcx.next_ty_var().to_chalk(interner).cast(Interner), - // FIXME: maybe wrong? - chalk_ir::VariableKind::Lifetime => { - infcx.next_ty_var().to_chalk(interner).cast(Interner) - } - chalk_ir::VariableKind::Const(_ty) => { - infcx.next_const_var().to_chalk(interner).cast(Interner) - } - }), - ) -} - #[derive(Clone)] pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, 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 76cc65277cd3d..734483a823e45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -39,7 +39,7 @@ mod utils; pub mod autoderef; pub mod consteval; -pub mod consteval_chalk; +mod consteval_chalk; pub mod db; pub mod diagnostics; pub mod display; @@ -62,7 +62,7 @@ mod variance; use std::hash::Hash; use chalk_ir::{ - NoSolution, VariableKinds, + VariableKinds, fold::{Shift, TypeFoldable}, interner::HasInterner, }; @@ -74,15 +74,16 @@ use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use rustc_type_ir::{ - UpcastFrom, - inherent::{SliceLike, Ty as _}, + TypeSuperVisitable, TypeVisitableExt, UpcastFrom, + inherent::{IntoKind, SliceLike, Ty as _}, }; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; +#[cfg(not(debug_assertions))] +use crate::next_solver::ErrorGuaranteed; use crate::{ - consteval::unknown_const, db::HirDatabase, display::{DisplayTarget, HirDisplay}, generics::Generics, @@ -104,11 +105,10 @@ pub use infer::{ could_coerce, could_unify, could_unify_deeply, }; pub use interner::Interner; -pub use lower::{ - ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext, - ValueTyDefId, diagnostics::*, +pub use lower::{ImplTraitLoweringMode, ParamLoweringMode, TyDefId, ValueTyDefId, diagnostics::*}; +pub use lower_nextsolver::{ + LifetimeElisionKind, TyLoweringContext, associated_type_shorthand_candidates, }; -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, @@ -124,20 +124,16 @@ pub use utils::{ }; pub use variance::Variance; -pub use chalk_ir::{ - AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, - cast::Cast, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; +use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Safety, Scalar}; -pub type ForeignDefId = chalk_ir::ForeignDefId; -pub type AssocTypeId = chalk_ir::AssocTypeId; -pub type FnDefId = chalk_ir::FnDefId; -pub type ClosureId = chalk_ir::ClosureId; -pub type OpaqueTyId = chalk_ir::OpaqueTyId; -pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; +pub(crate) type ForeignDefId = chalk_ir::ForeignDefId; +pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; +pub(crate) type FnDefId = chalk_ir::FnDefId; +pub(crate) type ClosureId = chalk_ir::ClosureId; +pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId; +pub(crate) type PlaceholderIndex = chalk_ir::PlaceholderIndex; -pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds; +pub(crate) 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 @@ -148,49 +144,48 @@ pub(crate) type VariableKind = chalk_ir::VariableKind; /// parameters/arguments for an item MUST come before those for its parent. This is to facilitate /// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its /// motivation in detail. -pub type Binders = chalk_ir::Binders; +pub(crate) type Binders = chalk_ir::Binders; /// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for /// it contains generic arguments for both its parent and itself. See chalk's documentation for /// details. /// /// See `Binders` for the constraint on the ordering. -pub type Substitution = chalk_ir::Substitution; -pub type GenericArg = chalk_ir::GenericArg; -pub type GenericArgData = chalk_ir::GenericArgData; +pub(crate) type Substitution = chalk_ir::Substitution; +pub(crate) type GenericArg = chalk_ir::GenericArg; +pub(crate) type GenericArgData = chalk_ir::GenericArgData; -pub type Ty = chalk_ir::Ty; +pub(crate) type Ty = chalk_ir::Ty; pub type TyKind = chalk_ir::TyKind; -pub type TypeFlags = chalk_ir::TypeFlags; +pub(crate) type TypeFlags = chalk_ir::TypeFlags; pub(crate) type DynTy = chalk_ir::DynTy; -pub type FnPointer = chalk_ir::FnPointer; +pub(crate) type FnPointer = chalk_ir::FnPointer; 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 ProjectionTy = chalk_ir::ProjectionTy; +pub(crate) 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 ConstValue = chalk_ir::ConstValue; +pub(crate) type ConstValue = chalk_ir::ConstValue; -pub type Const = chalk_ir::Const; +pub(crate) 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 Canonical = chalk_ir::Canonical; +pub(crate) type TraitRef = chalk_ir::TraitRef; +pub(crate) type QuantifiedWhereClause = Binders; +pub(crate) type Canonical = chalk_ir::Canonical; 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(crate) type InEnvironment = chalk_ir::InEnvironment; pub type AliasEq = chalk_ir::AliasEq; pub type WhereClause = chalk_ir::WhereClause; @@ -717,130 +712,167 @@ pub(crate) fn fold_free_vars + TypeFoldable< /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also /// ensures there are no unbound variables or inference variables anywhere in /// the `t`. -pub fn replace_errors_with_variables(t: &T) -> Canonical +pub fn replace_errors_with_variables<'db, T>( + interner: DbInterner<'db>, + t: &T, +) -> crate::next_solver::Canonical<'db, T> where - T: HasInterner + TypeFoldable + Clone, + T: rustc_type_ir::TypeFoldable> + Clone, { - use chalk_ir::{ - Fallible, - fold::{FallibleTypeFolder, TypeSuperFoldable}, - }; - struct ErrorReplacer { - vars: usize, + use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable}; + struct ErrorReplacer<'db> { + interner: DbInterner<'db>, + vars: Vec>, + binder: rustc_type_ir::DebruijnIndex, } - impl FallibleTypeFolder for ErrorReplacer { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { - self + impl<'db> FallibleTypeFolder> for ErrorReplacer<'db> { + #[cfg(debug_assertions)] + type Error = (); + #[cfg(not(debug_assertions))] + type Error = std::convert::Infallible; + + fn cx(&self) -> DbInterner<'db> { + self.interner } - fn interner(&self) -> Interner { - Interner - } - - fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { - if let TyKind::Error = ty.kind(Interner) { - let index = self.vars; - self.vars += 1; - Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner)) - } else { - ty.try_super_fold_with(self.as_dyn(), outer_binder) - } - } - - fn try_fold_inference_ty( + fn try_fold_binder( &mut self, - _var: InferenceVar, - _kind: TyVariableKind, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) - } + t: crate::next_solver::Binder<'db, T>, + ) -> Result, Self::Error> + where + T: rustc_type_ir::TypeFoldable>, + { + self.binder.shift_in(1); + let result = t.try_super_fold_with(self); + self.binder.shift_out(1); + result } - fn try_fold_free_var_ty( + fn try_fold_ty( &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) + t: crate::next_solver::Ty<'db>, + ) -> Result, Self::Error> { + if !t.has_type_flags( + rustc_type_ir::TypeFlags::HAS_ERROR + | rustc_type_ir::TypeFlags::HAS_TY_INFER + | rustc_type_ir::TypeFlags::HAS_CT_INFER + | rustc_type_ir::TypeFlags::HAS_RE_INFER, + ) { + return Ok(t); } - } - fn try_fold_inference_const( - &mut self, - ty: Ty, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - let interner = DbInterner::conjure(); - Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner)) + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(crate::next_solver::Ty::new_error(self.interner, ErrorGuaranteed)); + + match t.kind() { + crate::next_solver::TyKind::Error(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(crate::next_solver::CanonicalVarKind::Ty { + ui: rustc_type_ir::UniverseIndex::ZERO, + sub_root: var, + }); + Ok(crate::next_solver::Ty::new_bound( + self.interner, + self.binder, + crate::next_solver::BoundTy { + var, + kind: crate::next_solver::BoundTyKind::Anon, + }, + )) + } + crate::next_solver::TyKind::Infer(_) => error(), + crate::next_solver::TyKind::Bound(index, _) if index > self.binder => error(), + _ => t.try_super_fold_with(self), } } - fn try_fold_free_var_const( + fn try_fold_const( &mut self, - ty: Ty, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { - Err(NoSolution) - } else { - let interner = DbInterner::conjure(); - Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner)) + ct: crate::next_solver::Const<'db>, + ) -> Result, Self::Error> { + if !ct.has_type_flags( + rustc_type_ir::TypeFlags::HAS_ERROR + | rustc_type_ir::TypeFlags::HAS_TY_INFER + | rustc_type_ir::TypeFlags::HAS_CT_INFER + | rustc_type_ir::TypeFlags::HAS_RE_INFER, + ) { + return Ok(ct); } - } - fn try_fold_inference_lifetime( - &mut self, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) } + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(crate::next_solver::Const::error(self.interner)); + + match ct.kind() { + crate::next_solver::ConstKind::Error(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(crate::next_solver::CanonicalVarKind::Const( + rustc_type_ir::UniverseIndex::ZERO, + )); + Ok(crate::next_solver::Const::new_bound( + self.interner, + self.binder, + crate::next_solver::BoundConst { var }, + )) + } + crate::next_solver::ConstKind::Infer(_) => error(), + crate::next_solver::ConstKind::Bound(index, _) if index > self.binder => error(), + _ => ct.try_super_fold_with(self), + } } - fn try_fold_free_var_lifetime( + fn try_fold_region( &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) } + region: crate::next_solver::Region<'db>, + ) -> Result, Self::Error> { + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(crate::next_solver::Region::error(self.interner)); + + match region.kind() { + crate::next_solver::RegionKind::ReError(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(crate::next_solver::CanonicalVarKind::Region( + rustc_type_ir::UniverseIndex::ZERO, + )); + Ok(crate::next_solver::Region::new_bound( + self.interner, + self.binder, + crate::next_solver::BoundRegion { + var, + kind: crate::next_solver::BoundRegionKind::Anon, + }, + )) + } + crate::next_solver::RegionKind::ReVar(_) => error(), + crate::next_solver::RegionKind::ReBound(index, _) if index > self.binder => error(), + _ => Ok(region), + } } } - let mut error_replacer = ErrorReplacer { vars: 0 }; - let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) { + + let mut error_replacer = + ErrorReplacer { vars: Vec::new(), binder: rustc_type_ir::DebruijnIndex::ZERO, interner }; + let value = match t.clone().try_fold_with(&mut error_replacer) { Ok(t) => t, Err(_) => panic!("Encountered unbound or inference vars in {t:?}"), }; - let kinds = (0..error_replacer.vars).map(|_| { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex::ROOT, - ) - }); - Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } + crate::next_solver::Canonical { + value, + max_universe: rustc_type_ir::UniverseIndex::ZERO, + variables: crate::next_solver::CanonicalVars::new_from_iter(interner, error_replacer.vars), + } } pub fn callable_sig_from_fn_trait<'db>( - self_ty: &Ty, + self_ty: crate::next_solver::Ty<'db>, trait_env: Arc>, db: &'db dyn HirDatabase, -) -> Option<(FnTrait, CallableSig)> { +) -> Option<(FnTrait, crate::next_solver::PolyFnSig<'db>)> { let krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = fn_once_trait @@ -857,7 +889,7 @@ pub fn callable_sig_from_fn_trait<'db>( // - Self: FnOnce // - >::Output == ?ret_ty let args_ty = table.next_ty_var(); - let args = [self_ty.to_nextsolver(table.interner()), args_ty]; + let args = [self_ty, args_ty]; let trait_ref = crate::next_solver::TraitRef::new(table.interner(), fn_once_trait.into(), args); let projection = crate::next_solver::Ty::new_alias( table.interner(), @@ -880,23 +912,24 @@ pub fn callable_sig_from_fn_trait<'db>( )) .no_solution() { - let ret_ty = table.resolve_completely(return_ty).to_chalk(table.interner()); - let args_ty = table.resolve_completely(args_ty).to_chalk(table.interner()); - let params = args_ty - .as_tuple()? - .iter(Interner) - .map(|it| it.assert_ty_ref(Interner)) - .cloned(); + let ret_ty = table.resolve_completely(return_ty); + let args_ty = table.resolve_completely(args_ty); + let crate::next_solver::TyKind::Tuple(params) = args_ty.kind() else { + return None; + }; + let inputs_and_output = crate::next_solver::Tys::new_from_iter( + table.interner(), + params.iter().chain(std::iter::once(ret_ty)), + ); return Some(( fn_x, - CallableSig::from_params_and_return( - params, - ret_ty, - false, - Safety::Safe, - FnAbi::RustCall, - ), + crate::next_solver::Binder::dummy(crate::next_solver::FnSig { + inputs_and_output, + c_variadic: false, + safety: crate::next_solver::abi::Safety::Safe, + abi: FnAbi::RustCall, + }), )); } } @@ -906,74 +939,43 @@ pub fn callable_sig_from_fn_trait<'db>( } } -struct PlaceholderCollector<'db> { - db: &'db dyn HirDatabase, - placeholders: FxHashSet, -} - -impl PlaceholderCollector<'_> { - fn collect(&mut self, idx: PlaceholderIndex) { - let id = from_placeholder_idx(self.db, idx).0; - self.placeholders.insert(id); - } +struct ParamCollector { + params: FxHashSet, } -impl TypeVisitor for PlaceholderCollector<'_> { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } - - fn interner(&self) -> Interner { - Interner - } +impl<'db> rustc_type_ir::TypeVisitor> for ParamCollector { + type Result = (); - fn visit_ty( - &mut self, - ty: &Ty, - outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow { - let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER; - let chalk_ir::TyData { kind, flags } = ty.data(Interner); - - if let TyKind::Placeholder(idx) = kind { - self.collect(*idx); - } else if flags.intersects(has_placeholder_bits) { - return ty.super_visit_with(self, outer_binder); - } else { - // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate - // that there are no placeholders. + fn visit_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> Self::Result { + if let crate::next_solver::TyKind::Param(param) = ty.kind() { + self.params.insert(param.id.into()); } - std::ops::ControlFlow::Continue(()) + ty.super_visit_with(self); } - fn visit_const( - &mut self, - constant: &chalk_ir::Const, - _outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow { - if let chalk_ir::ConstValue::Placeholder(idx) = constant.data(Interner).value { - self.collect(idx); + fn visit_const(&mut self, konst: crate::next_solver::Const<'db>) -> Self::Result { + if let crate::next_solver::ConstKind::Param(param) = konst.kind() { + self.params.insert(param.id.into()); } - std::ops::ControlFlow::Continue(()) + + konst.super_visit_with(self); } } -/// Returns unique placeholders for types and consts contained in `value`. -pub fn collect_placeholders(value: &T, db: &dyn HirDatabase) -> Vec +/// Returns unique params for types and consts contained in `value`. +pub fn collect_params<'db, T>(value: &T) -> Vec where - T: ?Sized + TypeVisitable, + T: ?Sized + rustc_type_ir::TypeVisitable>, { - let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() }; - _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST); - collector.placeholders.into_iter().collect() + let mut collector = ParamCollector { params: FxHashSet::default() }; + value.visit_with(&mut collector); + Vec::from_iter(collector.params) } -pub fn known_const_to_ast( - konst: &Const, - db: &dyn HirDatabase, +pub fn known_const_to_ast<'db>( + konst: crate::next_solver::Const<'db>, + db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> Option { Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str())) 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 ee7b0cdd1fe34..b18d713c411ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -86,7 +86,7 @@ impl ImplTraitLoweringState { pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); #[derive(Debug, Clone)] -pub enum LifetimeElisionKind { +pub(crate) enum LifetimeElisionKind { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: @@ -111,14 +111,6 @@ pub enum LifetimeElisionKind { /// 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, } @@ -132,7 +124,7 @@ impl LifetimeElisionKind { } #[derive(Debug)] -pub struct TyLoweringContext<'db> { +pub(crate) struct TyLoweringContext<'db> { pub db: &'db dyn HirDatabase, resolver: &'db Resolver<'db>, store: &'db ExpressionStore, @@ -152,7 +144,7 @@ pub struct TyLoweringContext<'db> { } impl<'db> TyLoweringContext<'db> { - pub fn new( + pub(crate) fn new( db: &'db dyn HirDatabase, resolver: &'db Resolver<'db>, store: &'db ExpressionStore, @@ -177,7 +169,7 @@ impl<'db> TyLoweringContext<'db> { } } - pub fn with_debruijn( + pub(crate) fn with_debruijn( &mut self, debruijn: DebruijnIndex, f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, @@ -188,7 +180,7 @@ impl<'db> TyLoweringContext<'db> { result } - pub fn with_shifted_in( + pub(crate) fn with_shifted_in( &mut self, debruijn: DebruijnIndex, f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, @@ -207,25 +199,15 @@ impl<'db> TyLoweringContext<'db> { result } - pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { + pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } } - pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { + pub(crate) fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { Self { type_param_mode, ..self } } - pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self { - self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode); - self - } - - pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self { - self.type_param_mode = type_param_mode; - self - } - - pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { + pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); } } @@ -249,11 +231,11 @@ pub enum ParamLoweringMode { } impl<'db> TyLoweringContext<'db> { - pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty { + pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty { self.lower_ty_ext(type_ref).0 } - pub fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const { + pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const { let const_ref = &self.store[const_ref.expr]; match const_ref { hir_def::hir::Expr::Path(path) => path_to_const( @@ -308,7 +290,7 @@ impl<'db> TyLoweringContext<'db> { } } - pub fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const { + pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const { path_to_const( self.db, self.resolver, @@ -325,7 +307,7 @@ impl<'db> TyLoweringContext<'db> { self.generics.get_or_init(|| generics(self.db, self.def)) } - pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option) { + pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option) { let mut res = None; let type_ref = &self.store[type_ref_id]; let ty = match type_ref { @@ -774,7 +756,7 @@ impl<'db> TyLoweringContext<'db> { ImplTrait { bounds: crate::make_single_type_binders(predicates) } } - pub fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime { + pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime { match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { LifetimeNs::Static => static_lifetime(), 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 f988b6160ba51..09a256a86dccf 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 @@ -21,18 +21,17 @@ use stdx::never; use crate::{ AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, IncorrectGenericsLenKind, Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy, - QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, - TyLoweringContext, WhereClause, + QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, WhereClause, consteval_chalk::{unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, generics::{Generics, generics}, - lower::{LifetimeElisionKind, named_associated_type_shorthand_candidates}, + lower::{LifetimeElisionKind, TyLoweringContext, named_associated_type_shorthand_candidates}, next_solver::{ DbInterner, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, - static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, + to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::associated_type_by_name_including_super_traits, }; @@ -650,14 +649,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { }); } - 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, @@ -810,8 +801,6 @@ pub(crate) trait GenericArgsLowerer { 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( @@ -884,13 +873,6 @@ fn check_generic_args_len( 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); } @@ -1099,15 +1081,11 @@ pub(crate) fn substs_from_args_and_bindings( // 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::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: _ } => { - static_lifetime().cast(Interner) - } LifetimeElisionKind::Elided(lifetime) => lifetime.clone().cast(Interner), LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false } | LifetimeElisionKind::Infer => { 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 5a0bccea5f9c1..abca6b6bb9e52 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 @@ -40,7 +40,7 @@ use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId}; use hir_expand::name::Name; use intern::{Symbol, sym}; use la_arena::{Arena, ArenaMap, Idx}; -use path::{PathDiagnosticCallback, PathLoweringContext, builtin}; +use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_pattern_analysis::Captures; @@ -105,7 +105,7 @@ impl<'db> ImplTraitLoweringState<'db> { } #[derive(Debug, Clone)] -pub(crate) enum LifetimeElisionKind<'db> { +pub 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: @@ -174,7 +174,7 @@ impl<'db> LifetimeElisionKind<'db> { } #[derive(Debug)] -pub(crate) struct TyLoweringContext<'db, 'a> { +pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, interner: DbInterner<'db>, resolver: &'a Resolver<'db>, @@ -192,7 +192,7 @@ pub(crate) struct TyLoweringContext<'db, 'a> { } impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub(crate) fn new( + pub fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, store: &'a ExpressionStore, @@ -271,7 +271,7 @@ pub(crate) enum ImplTraitLoweringMode { } impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { + pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.lower_ty_ext(type_ref).0 } @@ -361,7 +361,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } #[tracing::instrument(skip(self), ret)] - pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { + pub 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]; @@ -1013,7 +1013,7 @@ pub(crate) fn type_alias_impl_traits<'db>( 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::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)), TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( interner, it, @@ -1401,6 +1401,7 @@ pub(crate) fn generic_predicates_for_param_cycle_result( pub struct GenericPredicates<'db>(Option]>>); impl<'db> GenericPredicates<'db> { + #[inline] pub fn instantiate( &self, interner: DbInterner<'db>, @@ -1410,6 +1411,11 @@ impl<'db> GenericPredicates<'db> { .as_ref() .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) } + + #[inline] + pub fn instantiate_identity(&self) -> Option>> { + self.0.as_ref().map(|it| it.iter().copied()) + } } impl<'db> ops::Deref for GenericPredicates<'db> { @@ -1458,8 +1464,7 @@ pub(crate) fn trait_environment_query<'db>( for pred in maybe_parent_generics.where_predicates() { for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { - traits_in_scope - .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0)); + traits_in_scope.push((tr.self_ty(), tr.def_id().0)); } clauses.push(pred); } 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 b003cc574d5b5..ef2c392f08616 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 @@ -550,7 +550,9 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { 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::BuiltinType(builtinty) => { + return Ty::from_builtin_type(self.ctx.interner, builtinty); + } TyDefId::AdtId(it) => it.into(), TyDefId::TypeAliasId(it) => it.into(), }; @@ -1350,42 +1352,3 @@ fn unknown_subst<'db>( }), ) } - -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 110fee824cb2d..98c8f3e890160 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 @@ -5,7 +5,6 @@ use std::ops::ControlFlow; use base_db::Crate; -use chalk_ir::{UniverseIndex, WithKind, cast::Cast}; use hir_def::{ AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleId, TraitId, TypeAliasId, @@ -29,8 +28,7 @@ use triomphe::Arc; use crate::next_solver::infer::InferCtxt; use crate::next_solver::infer::select::ImplSource; use crate::{ - CanonicalVarKinds, DebruijnIndex, GenericArgData, InEnvironment, Interner, TraitEnvironment, - TyBuilder, VariableKind, + TraitEnvironment, TyBuilder, autoderef::{self, AutoderefKind}, db::HirDatabase, infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, @@ -42,7 +40,6 @@ use crate::{ DbInternerInferExt, DefineOpaqueTypes, traits::{Obligation, ObligationCause, PredicateObligation}, }, - mapping::NextSolverToChalk, obligation_ctxt::ObligationCtxt, }, traits::next_trait_solve_canonical_in_ctxt, @@ -1390,9 +1387,8 @@ fn iterate_inherent_methods<'db>( match self_ty.kind() { TyKind::Param(_) => { let env = table.trait_env.clone(); - let traits = env - .traits_in_scope_from_clauses(self_ty.to_chalk(table.interner())) - .flat_map(|t| all_super_traits(db, t)); + let traits = + env.traits_in_scope_from_clauses(self_ty).flat_map(|t| all_super_traits(db, t)); iterate_inherent_trait_methods( self_ty, table, @@ -1755,50 +1751,6 @@ fn is_valid_impl_fn_candidate<'db>( }) } -pub fn implements_trait_unique<'db>( - ty: &crate::Canonical, - db: &'db dyn HirDatabase, - env: &TraitEnvironment<'db>, - trait_: TraitId, -) -> bool { - let goal = generic_implements_goal(db, env, trait_, ty); - 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 -/// for all other parameters, to query next solver with it. -#[tracing::instrument(skip_all)] -fn generic_implements_goal<'db>( - db: &'db dyn HirDatabase, - env: &TraitEnvironment<'db>, - trait_: TraitId, - self_ty: &crate::Canonical, -) -> crate::Canonical> { - let binders = self_ty.binders.interned(); - let trait_ref = TyBuilder::trait_ref(db, trait_) - .push(self_ty.value.clone()) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, binders.len()) - .build(); - - 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.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), - obligation, - ); - crate::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)] 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 da86fa3ae53c0..2fc1fc4f45a5c 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 @@ -7,8 +7,8 @@ use intern::{Interned, Symbol}; use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::{try_visit, visit::VisitorResult}; use rustc_type_ir::{ - BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, WithCachedTypeInfo, + BoundVar, DebruijnIndex, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, WithCachedTypeInfo, inherent::{IntoKind, ParamEnv as _, PlaceholderLike, SliceLike}, relate::Relate, }; @@ -62,6 +62,10 @@ impl<'db> Const<'db> { Const::new(interner, ConstKind::Placeholder(placeholder)) } + pub fn new_bound(interner: DbInterner<'db>, index: DebruijnIndex, bound: BoundConst) -> Self { + Const::new(interner, ConstKind::Bound(index, bound)) + } + pub fn new_valtree( interner: DbInterner<'db>, ty: Ty<'db>, @@ -159,11 +163,11 @@ impl ParamConst { /// Represents a typed, fully evaluated constant. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TypeFoldable, TypeVisitable)] pub struct ValueConst<'db> { - pub(crate) ty: Ty<'db>, + pub ty: Ty<'db>, // FIXME: Should we ignore this for TypeVisitable, TypeFoldable? #[type_visitable(ignore)] #[type_foldable(identity)] - pub(crate) value: Valtree<'db>, + pub value: Valtree<'db>, } impl<'db> ValueConst<'db> { 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 3e4c4171bedde..789be3b731b13 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 @@ -158,6 +158,15 @@ impl SolverDefId { _ => panic!("expected opaque type, found {self:?}"), } } + + #[inline] + #[track_caller] + pub fn expect_type_alias(self) -> TypeAliasId { + match self { + SolverDefId::TypeAliasId(it) => it, + _ => panic!("expected type alias, found {self:?}"), + } + } } impl<'db> inherent::DefId> for SolverDefId { 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 79527dac2fef3..38293c45422c1 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 @@ -69,6 +69,14 @@ impl<'db> GenericArg<'db> { _ => None, } } + + pub fn error_from_id(interner: DbInterner<'db>, id: GenericParamId) -> GenericArg<'db> { + match id { + GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(), + GenericParamId::ConstParamId(_) => Const::error(interner).into(), + GenericParamId::LifetimeParamId(_) => Region::error(interner).into(), + } + } } impl<'db> From> for GenericArg<'db> { @@ -192,6 +200,13 @@ impl<'db> GenericArgs<'db> { interner.mk_args(&args) } + /// Creates an all-error `GenericArgs`. + pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> { + GenericArgs::for_item(interner, def_id, |_, _, id, _| { + GenericArg::error_from_id(interner, id) + }) + } + /// Like `for_item`, but prefers the default of a parameter if it has any. pub fn for_item_with_defaults( interner: DbInterner<'db>, 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 cd1667527ba65..3fd8e7b39dd7d 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 @@ -304,6 +304,7 @@ impl<'db> DbInterner<'db> { DbInterner { db, krate, block } } + #[inline] pub fn db(&self) -> &'db dyn HirDatabase { self.db } @@ -1952,7 +1953,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { false } - // FIXME(next-solver): Make this a query? Can this make cycles? fn impl_specializes( self, specializing_impl_def_id: Self::ImplId, 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 13c333b9d54d8..5e7eb7532bb09 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 @@ -3,7 +3,8 @@ use hir_def::LifetimeParamId; use intern::{Interned, Symbol}; use rustc_type_ir::{ - BoundVar, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable, VisitorResult, + BoundVar, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable, + VisitorResult, inherent::{IntoKind, PlaceholderLike, SliceLike}, relate::Relate, }; @@ -62,6 +63,14 @@ impl<'db> Region<'db> { Region::new(interner, RegionKind::ReErased) } + pub fn new_bound( + interner: DbInterner<'db>, + index: DebruijnIndex, + bound: BoundRegion, + ) -> Region<'db> { + Region::new(interner, RegionKind::ReBound(index, bound)) + } + pub fn is_placeholder(&self) -> bool { matches!(self.inner(), RegionKind::RePlaceholder(..)) } 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 c5969120c9665..44b85abba0ef3 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 @@ -3,18 +3,22 @@ use std::iter; use std::ops::ControlFlow; -use hir_def::type_ref::Rawness; -use hir_def::{AdtId, GenericDefId, TypeOrConstParamId, TypeParamId}; +use hir_def::{ + AdtId, DefWithBodyId, GenericDefId, HasModule, TypeOrConstParamId, TypeParamId, + hir::generics::{TypeOrConstParamData, TypeParamProvenance}, + lang_item::LangItem, +}; +use hir_def::{TraitId, type_ref::Rawness}; 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, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy, - IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo, + AliasTyKind, BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, + InferTy, IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo, inherent::{ - Abi, AdtDef as _, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, - PlaceholderLike, Safety as _, SliceLike, Ty as _, + Abi, AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _, + IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _, }, relate::Relate, solve::SizedTraitKind, @@ -24,13 +28,14 @@ use salsa::plumbing::{AsId, FromId}; use smallvec::SmallVec; use crate::{ - FnAbi, + FnAbi, ImplTraitId, db::HirDatabase, interner::InternedWrapperNoDebug, next_solver::{ - AdtDef, Binder, CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, - GenericArg, PolyFnSig, Region, TypeAliasIdWrapper, + AdtDef, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const, + CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper, abi::Safety, + mapping::ChalkToNextSolver, util::{CoroutineArgsExt, IntegerTypeExt}, }, }; @@ -409,7 +414,7 @@ impl<'db> Ty<'db> { pub fn as_reference(self) -> Option<(Ty<'db>, Region<'db>, Mutability)> { match self.kind() { - TyKind::Ref(lifetime, ty, mutability) => Some((ty, lifetime, mutability)), + TyKind::Ref(region, ty, mutability) => Some((ty, region, mutability)), _ => None, } } @@ -422,6 +427,18 @@ impl<'db> Ty<'db> { } } + pub fn as_tuple(self) -> Option> { + match self.kind() { + TyKind::Tuple(tys) => Some(tys), + _ => None, + } + } + + pub fn dyn_trait(self) -> Option { + let TyKind::Dynamic(bounds, _) = self.kind() else { return None }; + Some(bounds.principal_def_id()?.0) + } + pub fn strip_references(self) -> Ty<'db> { let mut t = self; while let TyKind::Ref(_lifetime, ty, _mutability) = t.kind() { @@ -443,6 +460,176 @@ impl<'db> Ty<'db> { interner, )) } + + pub fn from_builtin_type( + interner: DbInterner<'db>, + ty: hir_def::builtin_type::BuiltinType, + ) -> Ty<'db> { + let kind = match ty { + hir_def::builtin_type::BuiltinType::Char => TyKind::Char, + hir_def::builtin_type::BuiltinType::Bool => TyKind::Bool, + hir_def::builtin_type::BuiltinType::Str => TyKind::Str, + hir_def::builtin_type::BuiltinType::Int(int) => TyKind::Int(match int { + hir_def::builtin_type::BuiltinInt::Isize => rustc_type_ir::IntTy::Isize, + hir_def::builtin_type::BuiltinInt::I8 => rustc_type_ir::IntTy::I8, + hir_def::builtin_type::BuiltinInt::I16 => rustc_type_ir::IntTy::I16, + hir_def::builtin_type::BuiltinInt::I32 => rustc_type_ir::IntTy::I32, + hir_def::builtin_type::BuiltinInt::I64 => rustc_type_ir::IntTy::I64, + hir_def::builtin_type::BuiltinInt::I128 => rustc_type_ir::IntTy::I128, + }), + hir_def::builtin_type::BuiltinType::Uint(uint) => TyKind::Uint(match uint { + hir_def::builtin_type::BuiltinUint::Usize => rustc_type_ir::UintTy::Usize, + hir_def::builtin_type::BuiltinUint::U8 => rustc_type_ir::UintTy::U8, + hir_def::builtin_type::BuiltinUint::U16 => rustc_type_ir::UintTy::U16, + hir_def::builtin_type::BuiltinUint::U32 => rustc_type_ir::UintTy::U32, + hir_def::builtin_type::BuiltinUint::U64 => rustc_type_ir::UintTy::U64, + hir_def::builtin_type::BuiltinUint::U128 => rustc_type_ir::UintTy::U128, + }), + hir_def::builtin_type::BuiltinType::Float(float) => TyKind::Float(match float { + hir_def::builtin_type::BuiltinFloat::F16 => rustc_type_ir::FloatTy::F16, + hir_def::builtin_type::BuiltinFloat::F32 => rustc_type_ir::FloatTy::F32, + hir_def::builtin_type::BuiltinFloat::F64 => rustc_type_ir::FloatTy::F64, + hir_def::builtin_type::BuiltinFloat::F128 => rustc_type_ir::FloatTy::F128, + }), + }; + Ty::new(interner, kind) + } + + pub fn as_builtin(self) -> Option { + let builtin = match self.kind() { + TyKind::Char => hir_def::builtin_type::BuiltinType::Char, + TyKind::Bool => hir_def::builtin_type::BuiltinType::Bool, + TyKind::Str => hir_def::builtin_type::BuiltinType::Str, + TyKind::Int(int) => hir_def::builtin_type::BuiltinType::Int(match int { + rustc_type_ir::IntTy::Isize => hir_def::builtin_type::BuiltinInt::Isize, + rustc_type_ir::IntTy::I8 => hir_def::builtin_type::BuiltinInt::I8, + rustc_type_ir::IntTy::I16 => hir_def::builtin_type::BuiltinInt::I16, + rustc_type_ir::IntTy::I32 => hir_def::builtin_type::BuiltinInt::I32, + rustc_type_ir::IntTy::I64 => hir_def::builtin_type::BuiltinInt::I64, + rustc_type_ir::IntTy::I128 => hir_def::builtin_type::BuiltinInt::I128, + }), + TyKind::Uint(uint) => hir_def::builtin_type::BuiltinType::Uint(match uint { + rustc_type_ir::UintTy::Usize => hir_def::builtin_type::BuiltinUint::Usize, + rustc_type_ir::UintTy::U8 => hir_def::builtin_type::BuiltinUint::U8, + rustc_type_ir::UintTy::U16 => hir_def::builtin_type::BuiltinUint::U16, + rustc_type_ir::UintTy::U32 => hir_def::builtin_type::BuiltinUint::U32, + rustc_type_ir::UintTy::U64 => hir_def::builtin_type::BuiltinUint::U64, + rustc_type_ir::UintTy::U128 => hir_def::builtin_type::BuiltinUint::U128, + }), + TyKind::Float(float) => hir_def::builtin_type::BuiltinType::Float(match float { + rustc_type_ir::FloatTy::F16 => hir_def::builtin_type::BuiltinFloat::F16, + rustc_type_ir::FloatTy::F32 => hir_def::builtin_type::BuiltinFloat::F32, + rustc_type_ir::FloatTy::F64 => hir_def::builtin_type::BuiltinFloat::F64, + rustc_type_ir::FloatTy::F128 => hir_def::builtin_type::BuiltinFloat::F128, + }), + _ => return None, + }; + Some(builtin) + } + + // FIXME: Should this be here? + pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option>> { + let interner = DbInterner::new_with(db, None, None); + + match self.kind() { + TyKind::Alias(AliasTyKind::Opaque, opaque_ty) => { + match db.lookup_intern_impl_trait_id(opaque_ty.def_id.expect_opaque_ty()) { + ImplTraitId::ReturnTypeImplTrait(func, idx) => { + db.return_type_impl_traits_ns(func).map(|it| { + let data = (*it).as_ref().map_bound(|rpit| { + &rpit.impl_traits[idx.to_nextsolver(interner)].predicates + }); + data.iter_instantiated_copied(interner, opaque_ty.args.as_slice()) + .collect() + }) + } + ImplTraitId::TypeAliasImplTrait(alias, idx) => { + db.type_alias_impl_traits_ns(alias).map(|it| { + let data = (*it).as_ref().map_bound(|rpit| { + &rpit.impl_traits[idx.to_nextsolver(interner)].predicates + }); + data.iter_instantiated_copied(interner, opaque_ty.args.as_slice()) + .collect() + }) + } + ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { + 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 = TraitRef::new( + interner, + future_trait.into(), + GenericArgs::new_from_iter(interner, []), + ) + .upcast(interner); + Some(vec![impl_bound]) + } else { + None + } + } + } + } + TyKind::Param(param) => { + // FIXME: We shouldn't use `param.id` here. + let generic_params = db.generic_params(param.id.parent()); + let param_data = &generic_params[param.id.local_id()]; + match param_data { + TypeOrConstParamData::TypeParamData(p) => match p.provenance { + TypeParamProvenance::ArgumentImplTrait => { + let predicates = db + .generic_predicates_ns(param.id.parent()) + .instantiate_identity() + .into_iter() + .flatten() + .filter(|wc| match wc.kind().skip_binder() { + ClauseKind::Trait(tr) => tr.self_ty() == self, + ClauseKind::Projection(pred) => pred.self_ty() == self, + ClauseKind::TypeOutlives(pred) => pred.0 == self, + _ => false, + }) + .collect::>(); + + Some(predicates) + } + _ => None, + }, + _ => None, + } + } + _ => None, + } + } + + /// FIXME: Get rid of this, it's not a good abstraction + pub fn equals_ctor(self, other: Ty<'db>) -> bool { + match (self.kind(), other.kind()) { + (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt.def_id() == adt2.def_id(), + (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => { + true + } + (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2, + (TyKind::Alias(_, alias, ..), TyKind::Alias(_, alias2)) => { + alias.def_id == alias2.def_id + } + (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2, + (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2, + (TyKind::Ref(.., mutability), TyKind::Ref(.., mutability2)) + | (TyKind::RawPtr(.., mutability), TyKind::RawPtr(.., mutability2)) => { + mutability == mutability2 + } + (TyKind::FnPtr(sig, hdr), TyKind::FnPtr(sig2, hdr2)) => sig == sig2 && hdr == hdr2, + (TyKind::Tuple(tys), TyKind::Tuple(tys2)) => tys.len() == tys2.len(), + (TyKind::Str, TyKind::Str) + | (TyKind::Never, TyKind::Never) + | (TyKind::Char, TyKind::Char) + | (TyKind::Bool, TyKind::Bool) => true, + (TyKind::Int(int), TyKind::Int(int2)) => int == int2, + (TyKind::Float(float), TyKind::Float(float2)) => float == float2, + _ => false, + } + } } pub fn references_non_lt_error<'db, T: TypeVisitableExt>>(t: &T) -> bool { 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 16ad54a2f2c06..cd125f3af8645 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -12,7 +12,7 @@ use intern::sym; use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt}; use rustc_type_ir::{ InferCtxtLike, TypingMode, - inherent::{SliceLike, Span as _, Ty as _}, + inherent::{IntoKind, SliceLike, Span as _, Ty as _}, solve::Certainty, }; use span::Edition; @@ -28,6 +28,7 @@ use crate::{ DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span, infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result}, + obligation_ctxt::ObligationCtxt, util::mini_canonicalize, }, utils::UnevaluatedConstEvaluatorFolder, @@ -43,7 +44,7 @@ pub struct TraitEnvironment<'db> { pub krate: Crate, pub block: Option, // FIXME make this a BTreeMap - traits_from_clauses: Box<[(Ty, TraitId)]>, + traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>, pub env: ParamEnv<'db>, } @@ -60,7 +61,7 @@ impl<'db> TraitEnvironment<'db> { pub fn new( krate: Crate, block: Option, - traits_from_clauses: Box<[(Ty, TraitId)]>, + traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>, env: ParamEnv<'db>, ) -> Arc { Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) @@ -71,13 +72,28 @@ impl<'db> TraitEnvironment<'db> { Arc::make_mut(this).block = Some(block); } - pub fn traits_in_scope_from_clauses(&self, ty: Ty) -> impl Iterator + '_ { + pub fn traits_in_scope_from_clauses( + &self, + ty: crate::next_solver::Ty<'db>, + ) -> impl Iterator + '_ { self.traits_from_clauses .iter() .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id)) } } +/// This should be used in `hir` only. +pub fn structurally_normalize_ty<'db>( + infcx: &InferCtxt<'db>, + ty: crate::next_solver::Ty<'db>, + env: Arc>, +) -> crate::next_solver::Ty<'db> { + let crate::next_solver::TyKind::Alias(..) = ty.kind() else { return ty }; + let mut ocx = ObligationCtxt::new(infcx); + let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); + ty.replace_infer_with_error(infcx.interner) +} + pub(crate) fn normalize_projection_query<'db>( db: &'db dyn HirDatabase, projection: ProjectionTy, @@ -440,3 +456,43 @@ impl FnTrait { self.lang_item().resolve_trait(db, krate) } } + +/// This should not be used in `hir-ty`, only in `hir`. +pub fn implements_trait_unique<'db>( + ty: crate::next_solver::Ty<'db>, + db: &'db dyn HirDatabase, + env: Arc>, + trait_: TraitId, +) -> bool { + implements_trait_unique_impl(db, env, trait_, &mut |infcx| { + infcx.fill_rest_fresh_args(trait_.into(), [ty.into()]) + }) +} + +/// This should not be used in `hir-ty`, only in `hir`. +pub fn implements_trait_unique_with_args<'db>( + db: &'db dyn HirDatabase, + env: Arc>, + trait_: TraitId, + args: crate::next_solver::GenericArgs<'db>, +) -> bool { + implements_trait_unique_impl(db, env, trait_, &mut |_| args) +} + +fn implements_trait_unique_impl<'db>( + db: &'db dyn HirDatabase, + env: Arc>, + trait_: TraitId, + create_args: &mut dyn FnMut(&InferCtxt<'db>) -> crate::next_solver::GenericArgs<'db>, +) -> bool { + let interner = DbInterner::new_with(db, Some(env.krate), env.block); + // FIXME(next-solver): I believe this should be `PostAnalysis`. + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + + let args = create_args(&infcx); + let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); + let goal = crate::next_solver::Goal::new(interner, env.env, trait_ref); + + let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal); + matches!(result, Ok((_, Certainty::Yes))) +} diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index c230bbad0bc45..147f1b8653be8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -14,11 +14,7 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::Name, }; -use hir_ty::{ - db::HirDatabase, - method_resolution, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, -}; +use hir_ty::{db::HirDatabase, method_resolution}; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -261,7 +257,7 @@ fn resolve_impl_trait_item<'db>( name: &Name, ns: Option, ) -> Option { - let canonical = ty.canonical(); + let canonical = ty.canonical(db); let krate = ty.krate(db); let environment = resolver .generic_def() @@ -275,11 +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.to_nextsolver(DbInterner::new_with( - db, - Some(environment.krate), - environment.block, - )), + &canonical, db, environment, &traits_in_scope, diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index c094487a8709e..a6d67e8fb4fb5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -19,7 +19,6 @@ use hir_ty::{ PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind, db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, - next_solver::{DbInterner, mapping::NextSolverToChalk}, }; use syntax::{ AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange, @@ -641,7 +640,6 @@ impl<'db> AnyDiagnostic<'db> { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat), }; - let interner = DbInterner::new_with(db, None, None); Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { let expr_or_pat = match expr { @@ -668,11 +666,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::ExpectedFunction { call_expr, found } => { let call_expr = expr_syntax(*call_expr)?; - ExpectedFunction { - call: call_expr, - found: Type::new(db, def, found.to_chalk(interner)), - } - .into() + ExpectedFunction { call: call_expr, found: Type::new(db, def, *found) }.into() } InferenceDiagnostic::UnresolvedField { expr, @@ -684,7 +678,7 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedField { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.to_chalk(interner)), + receiver: Type::new(db, def, *receiver), method_with_same_name_exists: *method_with_same_name_exists, } .into() @@ -700,9 +694,8 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedMethodCall { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.to_chalk(interner)), - field_with_same_name: (*field_with_same_name) - .map(|ty| Type::new(db, def, ty.to_chalk(interner))), + receiver: Type::new(db, def, *receiver), + field_with_same_name: (*field_with_same_name).map(|ty| Type::new(db, def, ty)), assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into), } .into() @@ -729,7 +722,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::TypedHole { expr, expected } => { let expr = expr_syntax(*expr)?; - TypedHole { expr, expected: Type::new(db, def, expected.to_chalk(interner)) }.into() + TypedHole { expr, expected: Type::new(db, def, *expected) }.into() } &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => { let expr_or_pat = match pat { @@ -746,13 +739,12 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::CastToUnsized { expr, cast_ty } => { let expr = expr_syntax(*expr)?; - CastToUnsized { expr, cast_ty: Type::new(db, def, cast_ty.to_chalk(interner)) } - .into() + CastToUnsized { expr, cast_ty: Type::new(db, def, *cast_ty) }.into() } InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => { let expr = expr_syntax(*expr)?; - let expr_ty = Type::new(db, def, expr_ty.to_chalk(interner)); - let cast_ty = Type::new(db, def, cast_ty.to_chalk(interner)); + let expr_ty = Type::new(db, def, *expr_ty); + let cast_ty = Type::new(db, def, *cast_ty); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } InferenceDiagnostic::TyDiagnostic { source, diag } => { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 2bf9bb85e50dd..49bf843367d37 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -11,7 +11,7 @@ use hir_def::{ type_ref::{TypeBound, TypeRef, TypeRefId}, }; use hir_ty::{ - AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, + AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyBuilder, TyKind, WhereClause, db::HirDatabase, display::{ HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault, @@ -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, TraitRef, TupleField, TyBuilder, - Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, + Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type, + TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { 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 ae82275e38736..6f427d728b20b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -238,7 +238,7 @@ impl HasSource for Param<'_> { .map(|value| InFile { file_id, value }) } Callee::Closure(closure, _) => { - let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into()); + let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure); let (_, source_map) = db.body_with_source_map(owner); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; let root = db.parse_or_expand(file_id); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 59038c2656c9d..55da27781db13 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -71,29 +71,31 @@ use hir_expand::{ proc_macro::ProcMacroKind, }; use hir_ty::{ - AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, - 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_chalk::{ConstExt, try_const_usize, unknown_const_as_generic}, + TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, + check_orphan_rules, + consteval::try_const_usize, + db::InternedClosureId, diagnostics::BodyValidationDiagnostic, - direct_super_traits, error_lifetime, known_const_to_ast, + direct_super_traits, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - ClauseKind, DbInterner, GenericArgs, TypingMode, + AliasTy, Canonical, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, + GenericArgs, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, - mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, - primitive::UintTy, - traits::FnTrait, + traits::{self, FnTrait, structurally_normalize_ty}, }; use itertools::Itertools; use rustc_hash::FxHashSet; +use rustc_type_ir::{ + AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, + inherent::{AdtDef, IntoKind, SliceLike, Term as _, Ty as _}, +}; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; -use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime}; +use stdx::{format_to, impl_from, never}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, ast::{self, HasAttrs as _, HasName, HasVisibility as _}, @@ -112,7 +114,6 @@ pub use crate::{ VisibleTraits, }, }; -use rustc_type_ir::inherent::{IntoKind, SliceLike}; // Be careful with these re-exports. // @@ -156,6 +157,8 @@ pub use { proc_macro::{ProcMacros, ProcMacrosBuilder}, tt, }, + // FIXME: Properly encapsulate mir + hir_ty::mir, hir_ty::{ CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, consteval::ConstEvalError, @@ -168,8 +171,6 @@ pub use { mir::{MirEvalError, MirLowerError}, next_solver::abi::Safety, }, - // FIXME: Properly encapsulate mir - hir_ty::{Interner as ChalkTyInterner, mir}, intern::{Symbol, sym}, }; @@ -750,6 +751,9 @@ impl Module { let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); + let interner = DbInterner::new_with(db, Some(self.id.krate()), self.id.containing_block()); + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { GenericDef::Impl(impl_def).diagnostics(db, acc); @@ -874,26 +878,15 @@ impl Module { .collect(); if !missing.is_empty() { - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = - hir_ty::generics::generics(db, impl_def.id.into()) - .placeholder_subst(db) - .to_nextsolver(interner); - let self_ty = - db.impl_self_ty(impl_def.id).instantiate(interner, args).to_chalk(interner); - let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) = - self_ty.kind(Interner) - { - db.normalize_projection( - projection.clone(), - db.trait_environment(impl_def.id.into()), - ) - } else { - self_ty - }; + let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity(); + let self_ty = structurally_normalize_ty( + &infcx, + self_ty, + db.trait_environment(impl_def.id.into()), + ); let self_ty_is_guaranteed_unsized = matches!( - self_ty.kind(Interner), - TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str + self_ty.kind(), + TyKind::Dynamic(..) | TyKind::Slice(..) | TyKind::Str ); if self_ty_is_guaranteed_unsized { missing.retain(|(_, assoc_item)| { @@ -1300,17 +1293,11 @@ impl TupleField { let ty = db .infer(self.owner) .tuple_field_access_type(self.tuple) - .to_chalk(interner) - .as_slice(Interner) + .as_slice() .get(self.index as usize) - .and_then(|arg| arg.ty(Interner)) - .cloned() - .unwrap_or_else(|| TyKind::Error.intern(Interner)); - Type { - env: db.trait_environment_for_body(self.owner), - ty, - _pd: PhantomCovariantLifetime::new(), - } + .copied() + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); + Type { env: db.trait_environment_for_body(self.owner), ty } } } @@ -1378,17 +1365,9 @@ impl Field { VariantDef::Union(it) => it.id.into(), VariantDef::Variant(it) => it.parent_enum(db).id.into(), }; - let mut generics = generics.map(|it| it.ty); - let substs = TyBuilder::subst_for_def(db, def_id, None) - .fill(|x| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - .build(); - let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty)); + let ty = db.field_types_ns(var_id)[self.id].instantiate(interner, args); Type::new(db, var_id, ty) } @@ -1448,8 +1427,8 @@ impl Struct { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { @@ -1537,8 +1516,8 @@ impl Union { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { @@ -1604,40 +1583,43 @@ impl Enum { Type::from_def(db, self.id) } - pub fn ty_placeholders<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + Type::from_def_params(db, self.id) } /// The type of the enum variant bodies. pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + let interner = DbInterner::new_with(db, None, None); Type::new_for_crate( self.id.lookup(db).container.krate(), - TyBuilder::builtin(match db.enum_signature(self.id).variant_body_type() { + match db.enum_signature(self.id).variant_body_type() { layout::IntegerType::Pointer(sign) => match sign { - true => hir_def::builtin_type::BuiltinType::Int( - hir_def::builtin_type::BuiltinInt::Isize, - ), - false => hir_def::builtin_type::BuiltinType::Uint( - hir_def::builtin_type::BuiltinUint::Usize, - ), + true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), + false => Ty::new_uint(interner, rustc_type_ir::UintTy::Usize), }, layout::IntegerType::Fixed(i, sign) => match sign { - true => hir_def::builtin_type::BuiltinType::Int(match i { - layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, - layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, - layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, - layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, - layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, - }), - false => hir_def::builtin_type::BuiltinType::Uint(match i { - layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, - layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, - layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, - layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, - layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, - }), + true => Ty::new_int( + interner, + match i { + layout::Integer::I8 => rustc_type_ir::IntTy::I8, + layout::Integer::I16 => rustc_type_ir::IntTy::I16, + layout::Integer::I32 => rustc_type_ir::IntTy::I32, + layout::Integer::I64 => rustc_type_ir::IntTy::I64, + layout::Integer::I128 => rustc_type_ir::IntTy::I128, + }, + ), + false => Ty::new_uint( + interner, + match i { + layout::Integer::I8 => rustc_type_ir::UintTy::U8, + layout::Integer::I16 => rustc_type_ir::UintTy::U16, + layout::Integer::I32 => rustc_type_ir::UintTy::U32, + layout::Integer::I64 => rustc_type_ir::UintTy::U64, + layout::Integer::I128 => rustc_type_ir::UintTy::U128, + }, + ), }, - }), + }, ) } @@ -1813,26 +1795,18 @@ impl_from!(Struct, Union, Enum for Adt); impl Adt { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.into()); - (subst.is_empty() && db.generic_params(self.into()).len_type_or_consts() != 0) - || subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(it) => it.is_unknown(), - _ => false, - }) + has_non_default_type_params(db, self.into()) } 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( - self.into(), - TyBuilder::adt(db, self.into()) - .fill_with_defaults(db, || TyKind::Error.intern(Interner)) - .build_into_subst() - .to_nextsolver(interner), - env, - ) - .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) + let adt_id = AdtId::from(self); + let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, _, id, _| { + GenericArg::error_from_id(interner, id) + }); + db.layout_of_adt(adt_id, args, env) + .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) } /// Turns this ADT into a type. Any type parameters of the ADT will be @@ -1851,18 +1825,12 @@ impl Adt { args: impl IntoIterator>, ) -> Type<'db> { let id = AdtId::from(self); - let mut it = args.into_iter().map(|t| t.ty); - let ty = TyBuilder::def_ty(db, id.into(), None) - .fill(|x| { - let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); - match x { - ParamKind::Type => r.cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(DbInterner::conjure()) - .to_chalk(DbInterner::conjure()); + let interner = DbInterner::new_with(db, None, None); + let ty = Ty::new_adt( + interner, + id, + generic_args_from_tys(interner, id.into(), args.into_iter().map(|ty| ty.ty)), + ); Type::new(db, id, ty) } @@ -2023,7 +1991,6 @@ impl DefWithBody { style_lints: bool, ) { let krate = self.module(db).id.krate(); - let interner = DbInterner::new_with(db, Some(krate), None); let (body, source_map) = db.body_with_source_map(self.into()); let sig_source_map = match self { @@ -2073,16 +2040,8 @@ impl DefWithBody { acc.push( TypeMismatch { expr_or_pat, - expected: Type::new( - db, - DefWithBodyId::from(self), - mismatch.expected.to_chalk(interner), - ), - actual: Type::new( - db, - DefWithBodyId::from(self), - mismatch.actual.to_chalk(interner), - ), + expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected), + actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual), } .into(), ); @@ -2152,13 +2111,7 @@ impl DefWithBody { } mir::MirSpan::Unknown => continue, }; - acc.push( - MovedOutOfRef { - ty: Type::new_for_crate(krate, moof.ty.to_chalk(interner)), - span, - } - .into(), - ) + acc.push(MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty), span }.into()) } let mol = &borrowck_result.mutability_of_locals; for (binding_id, binding_data) in body.bindings() { @@ -2308,30 +2261,24 @@ impl Function { pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); - let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity(); + let ty = Ty::new_fn_ptr(interner, callable_sig); Type::new_with_resolver_inner(db, &resolver, ty) } + // FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`? + /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let ty = db .callable_item_signature(self.id.into()) - .instantiate(interner, args) + .instantiate_identity() .skip_binder() - .output() - .to_chalk(interner); + .output(); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2342,32 +2289,15 @@ impl Function { generics: impl Iterator>, ) -> Type<'db> { let resolver = self.id.resolver(db); - let parent_id: Option = match self.id.lookup(db).container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - }; - let mut generics = generics.map(|it| it.ty); - let mut filler = |x: &_| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }; - - let parent_substs = - parent_id.map(|id| TyBuilder::subst_for_def(db, id, None).fill(&mut filler).build()); - let substs = TyBuilder::subst_for_def(db, self.id, parent_substs).fill(&mut filler).build(); + let interner = DbInterner::new_with(db, None, None); + let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); let ty = db .callable_item_signature(self.id.into()) .instantiate(interner, args) .skip_binder() - .output() - .to_chalk(interner); + .output(); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2376,18 +2306,17 @@ impl Function { return None; } let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let ret_ty = db .callable_item_signature(self.id.into()) - .instantiate(interner, args) + .instantiate_identity() .skip_binder() - .output() - .to_chalk(interner); + .output(); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { - if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 { - return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into(); + if let ClauseKind::Projection(projection) = pred.kind().skip_binder() + && let Some(output_ty) = projection.term.as_type() + { + return Type::new_with_resolver_inner(db, &resolver, output_ty).into(); } } None @@ -2403,24 +2332,15 @@ impl Function { pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = + db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); callable_sig - .params() + .inputs() .iter() .enumerate() .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2437,26 +2357,17 @@ impl Function { pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = + db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; callable_sig - .params() + .inputs() .iter() .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2469,50 +2380,18 @@ impl Function { generics: impl Iterator>, ) -> Vec> { let environment = db.trait_environment(self.id.into()); - let parent_id: Option = match self.id.lookup(db).container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - }; - let mut generics = generics.map(|it| it.ty); - let parent_substs = parent_id.map(|id| { - TyBuilder::subst_for_def(db, id, None) - .fill(|x| match x { - ParamKind::Type => generics - .next() - .unwrap_or_else(|| TyKind::Error.intern(Interner)) - .cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - .build() - }); - - let substs = TyBuilder::subst_for_def(db, self.id, parent_substs) - .fill(|_| { - let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); - GenericArg::new(Interner, GenericArgData::Ty(ty)) - }) - .build(); let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); + let callable_sig = + db.callable_item_signature(self.id.into()).instantiate(interner, args).skip_binder(); let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; callable_sig - .params() + .inputs() .iter() .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2694,18 +2573,18 @@ pub enum Access { Owned, } -impl From for Access { - fn from(mutability: hir_ty::Mutability) -> Access { +impl From for Access { + fn from(mutability: hir_ty::next_solver::Mutability) -> Access { match mutability { - hir_ty::Mutability::Not => Access::Shared, - hir_ty::Mutability::Mut => Access::Exclusive, + hir_ty::next_solver::Mutability::Not => Access::Shared, + hir_ty::next_solver::Mutability::Mut => Access::Exclusive, } } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Param<'db> { - func: Callee, + func: Callee<'db>, /// The index in parameter list, including self parameter. idx: usize, ty: Type<'db>, @@ -2751,7 +2630,7 @@ impl<'db> Param<'db> { } } Callee::Closure(closure, _) => { - let c = db.lookup_intern_closure(closure.into()); + let c = db.lookup_intern_closure(closure); let body = db.body(c.0); if let Expr::Closure { args, .. } = &body[c.1] && let Pat::Bind { id, .. } = &body[args[self.idx]] @@ -2795,17 +2674,12 @@ impl SelfParam { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - let substs = TyBuilder::placeholder_subst(db, self.func); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.func.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = + db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + let ty = callable_sig.inputs().as_slice()[0]; + Type { env: environment, ty } } // FIXME: Find better API to also handle const generics @@ -2814,36 +2688,13 @@ impl SelfParam { db: &'db dyn HirDatabase, generics: impl Iterator>, ) -> Type<'db> { - let parent_id: GenericDefId = match self.func.lookup(db).container { - ItemContainerId::ImplId(it) => it.into(), - ItemContainerId::TraitId(it) => it.into(), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { - panic!("Never get here") - } - }; - - let mut generics = generics.map(|it| it.ty); - let mut filler = |x: &_| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }; - - let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build(); - let substs = - TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build(); let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let callable_sig = db - .callable_item_signature(self.func.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty)); + let callable_sig = + db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + let ty = callable_sig.inputs().as_slice()[0]; + Type { env: environment, ty } } } @@ -2936,11 +2787,11 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let interner = DbInterner::new_with(db, None, None); - let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner); + let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity(); db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) - .map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty }) + .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty }) } } @@ -2950,29 +2801,28 @@ impl HasVisibility for Const { } } -pub struct EvaluatedConst { +pub struct EvaluatedConst<'db> { def: DefWithBodyId, - const_: hir_ty::Const, - ty: hir_ty::Ty, + const_: hir_ty::next_solver::Const<'db>, + ty: Ty<'db>, } -impl EvaluatedConst { +impl<'db> EvaluatedConst<'db> { pub fn render(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { format!("{}", self.const_.display(db, display_target)) } - pub fn render_debug<'db>(&self, db: &'db dyn HirDatabase) -> Result> { - let interner = DbInterner::new_with(db, None, None); - let data = self.const_.data(Interner); - if let TyKind::Scalar(s) = data.ty.kind(Interner) - && matches!(s, Scalar::Int(_) | Scalar::Uint(_)) - && let hir_ty::ConstValue::Concrete(c) = &data.value - && let hir_ty::ConstScalar::Bytes(b, _) = &c.interned + pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result> { + let kind = self.const_.kind(); + if let ConstKind::Value(c) = kind + && let ty = c.ty.kind() + && let TyKind::Int(_) | TyKind::Uint(_) = ty { + let b = &c.value.inner().memory; let value = u128::from_le_bytes(mir::pad16(b, false)); - let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(ty, TyKind::Int(_)))); let mut result = - if let Scalar::Int(_) = s { value_signed.to_string() } else { value.to_string() }; + if let TyKind::Int(_) = ty { value_signed.to_string() } else { value.to_string() }; if value >= 10 { format_to!(result, " ({value:#X})"); return Ok(result); @@ -2980,12 +2830,7 @@ impl EvaluatedConst { return Ok(result); } } - mir::render_const_using_debug_impl( - db, - self.def, - self.const_.to_nextsolver(interner), - self.ty.to_nextsolver(interner), - ) + mir::render_const_using_debug_impl(db, self.def, self.const_, self.ty) } } @@ -3023,11 +2868,11 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let interner = DbInterner::new_with(db, None, None); - let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner); + let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity(); db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) - .map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty }) + .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty }) } } @@ -3148,12 +2993,7 @@ pub struct TypeAlias { impl TypeAlias { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.id.into()); - (subst.is_empty() && db.generic_params(self.id.into()).len_type_or_consts() != 0) - || subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(it) => it.is_unknown(), - _ => false, - }) + has_non_default_type_params(db, self.id.into()) } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -3164,8 +3004,8 @@ impl TypeAlias { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn name(self, db: &dyn HirDatabase) -> Name { @@ -3218,7 +3058,8 @@ impl BuiltinType { pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]); - Type::new_for_crate(core, TyBuilder::builtin(self.inner)) + let interner = DbInterner::new_with(db, None, None); + Type::new_for_crate(core, Ty::from_builtin_type(interner, self.inner)) } pub fn name(self) -> Name { @@ -3894,14 +3735,13 @@ impl GenericDef { #[derive(Debug)] pub struct GenericSubstitution<'db> { def: GenericDefId, - subst: Substitution, + subst: GenericArgs<'db>, env: Arc>, - _pd: PhantomCovariantLifetime<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: Substitution, env: Arc>) -> Self { - Self { def, subst, env, _pd: PhantomCovariantLifetime::new() } + fn new(def: GenericDefId, subst: GenericArgs<'db>, env: Arc>) -> Self { + Self { def, subst, env } } pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { @@ -3931,26 +3771,23 @@ impl<'db> GenericSubstitution<'db> { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), TypeOrConstParamData::ConstParamData(_) => None, }); - let parent_len = self.subst.len(Interner) + let parent_len = self.subst.len() - generics .iter_type_or_consts() .filter(|g| matches!(g.1, TypeOrConstParamData::TypeParamData(..))) .count(); - let container_params = self.subst.as_slice(Interner)[..parent_len] + let container_params = self.subst.as_slice()[..parent_len] .iter() - .filter_map(|param| param.ty(Interner).cloned()) + .filter_map(|param| param.ty()) .zip(container_type_params.into_iter().flatten()); - let self_params = self.subst.as_slice(Interner)[parent_len..] + let self_params = self.subst.as_slice()[parent_len..] .iter() - .filter_map(|param| param.ty(Interner).cloned()) + .filter_map(|param| param.ty()) .zip(type_params); container_params .chain(self_params) .filter_map(|(ty, name)| { - Some(( - name?.symbol().clone(), - Type { ty, env: self.env.clone(), _pd: PhantomCovariantLifetime::new() }, - )) + Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) }) .collect() } @@ -4057,8 +3894,7 @@ impl Local { let def = self.parent; let infer = db.infer(def); let ty = infer[self.binding_id]; - let interner = DbInterner::new_with(db, None, None); - Type::new(db, def, ty.to_chalk(interner)) + Type::new(db, def, ty) } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` @@ -4313,8 +4149,10 @@ 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_no_index(db, self.id.into())) - .intern(Interner); + let interner = DbInterner::new_with(db, None, None); + let index = hir_ty::param_idx(db, self.id.into()).unwrap(); + let name = self.name(db).symbol().clone(); + let ty = Ty::new_param(interner, self.id, index as u32, name); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -4334,9 +4172,9 @@ impl TypeParam { pub fn default(self, db: &dyn HirDatabase) -> Option> { let ty = generic_arg_from_param(db, self.id.into())?; let resolver = self.id.parent().resolver(db); - match ty.data(Interner) { - GenericArgData::Ty(it) if *it.kind(Interner) != TyKind::Error => { - Some(Type::new_with_resolver_inner(db, &resolver, it.clone())) + match ty { + GenericArg::Ty(it) if !it.is_ty_error() => { + Some(Type::new_with_resolver_inner(db, &resolver, it)) } _ => None, } @@ -4397,7 +4235,7 @@ impl ConstParam { } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - Type::new(db, self.id.parent(), db.const_param_ty(self.id)) + Type::new(db, self.id.parent(), db.const_param_ty_ns(self.id)) } pub fn default( @@ -4406,17 +4244,16 @@ impl ConstParam { display_target: DisplayTarget, ) -> Option { let arg = generic_arg_from_param(db, self.id.into())?; - known_const_to_ast(arg.constant(Interner)?, db, display_target) + known_const_to_ast(arg.konst()?, db, display_target) } } -fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option { +fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option> { let local_idx = hir_ty::param_idx(db, id)?; - let defaults = db.generic_defaults(id.parent); - let ty = defaults.get(local_idx)?.clone(); - let full_subst = TyBuilder::placeholder_subst(db, id.parent); - let subst = &full_subst.as_slice(Interner)[..local_idx]; - Some(ty.substitute(Interner, &subst)) + let defaults = db.generic_defaults_ns(id.parent); + let ty = defaults.get(local_idx)?; + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + Some(ty.instantiate_identity()) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -4498,13 +4335,8 @@ impl Impl { module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect() } - pub fn all_for_type<'db>( - db: &'db dyn HirDatabase, - Type { ty, env, _pd: _ }: Type<'db>, - ) -> Vec { - let interner = DbInterner::new_with(db, None, None); - let ty_ns = ty.to_nextsolver(interner); - let def_crates = match method_resolution::def_crates(db, ty_ns, env.krate) { + pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>) -> Vec { + let def_crates = match method_resolution::def_crates(db, ty, env.krate) { Some(def_crates) => def_crates, None => return Vec::new(), }; @@ -4512,10 +4344,10 @@ impl Impl { let filter = |impl_def: &Impl| { let self_ty = impl_def.self_ty(db); let rref = self_ty.remove_ref(); - ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) + ty.equals_ctor(rref.as_ref().map_or(self_ty.ty, |it| it.ty)) }; - let fp = TyFingerprint::for_inherent_impl(ty_ns); + let fp = TyFingerprint::for_inherent_impl(ty); let fp = match fp { Some(fp) => fp, None => return Vec::new(), @@ -4525,7 +4357,7 @@ impl Impl { def_crates.iter().for_each(|&id| { all.extend( db.inherent_impls_in_crate(id) - .for_self_ty(ty_ns) + .for_self_ty(ty) .iter() .cloned() .map(Self::from) @@ -4546,16 +4378,10 @@ impl Impl { ); } - if let Some(block) = ty.adt_id(Interner).and_then(|def| def.0.module(db).containing_block()) - { + if let Some(block) = ty.as_adt().and_then(|(def, _)| def.module(db).containing_block()) { if let Some(inherent_impls) = db.inherent_impls_in_block(block) { all.extend( - inherent_impls - .for_self_ty(ty_ns) - .iter() - .cloned() - .map(Self::from) - .filter(filter), + inherent_impls.for_self_ty(ty).iter().cloned().map(Self::from).filter(filter), ); } if let Some(trait_impls) = db.trait_impls_in_block(block) { @@ -4601,10 +4427,8 @@ impl Impl { pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let substs = TyBuilder::placeholder_subst(db, self.id); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let ty = db.impl_self_ty(self.id).instantiate(interner, args).to_chalk(interner); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let ty = db.impl_self_ty(self.id).instantiate_identity(); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -4666,7 +4490,6 @@ impl Impl { pub struct TraitRef<'db> { env: Arc>, trait_ref: hir_ty::next_solver::TraitRef<'db>, - _pd: PhantomCovariantLifetime<'db>, } impl<'db> TraitRef<'db> { @@ -4678,7 +4501,7 @@ impl<'db> TraitRef<'db> { let env = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - TraitRef { env, trait_ref, _pd: PhantomCovariantLifetime::new() } + TraitRef { env, trait_ref } } pub fn trait_(&self) -> Trait { @@ -4687,57 +4510,51 @@ impl<'db> TraitRef<'db> { pub fn self_ty(&self) -> TypeNs<'_> { let ty = self.trait_ref.self_ty(); - TypeNs { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } + TypeNs { env: self.env.clone(), ty } } /// 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.args.as_slice().get(idx).and_then(|arg| arg.ty()).map(|ty| TypeNs { - env: self.env.clone(), - ty, - _pd: PhantomCovariantLifetime::new(), - }) + self.trait_ref + .args + .as_slice() + .get(idx) + .and_then(|arg| arg.ty()) + .map(|ty| TypeNs { env: self.env.clone(), ty }) } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Closure { - id: ClosureId, - subst: Substitution, -} - -impl From for ClosureId { - fn from(value: Closure) -> Self { - value.id - } +pub struct Closure<'db> { + id: InternedClosureId, + subst: GenericArgs<'db>, } -impl Closure { - fn as_ty(self) -> Ty { - TyKind::Closure(self.id, self.subst).intern(Interner) +impl<'db> Closure<'db> { + fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> { + let interner = DbInterner::new_with(db, None, None); + Ty::new_closure(interner, self.id.into(), self.subst) } pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - self.clone() - .as_ty() + self.as_ty(db) .display(db, display_target) .with_closure_style(ClosureStyle::ClosureWithId) .to_string() } pub fn display_with_impl(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - self.clone() - .as_ty() + self.as_ty(db) .display(db, display_target) .with_closure_style(ClosureStyle::ImplFn) .to_string() } - pub fn captured_items<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let info = infer.closure_info(self.id.into()); + pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec> { + let owner = db.lookup_intern_closure(self.id).0; + let infer = db.infer(owner); + let info = infer.closure_info(self.id); info.0 .iter() .cloned() @@ -4745,25 +4562,21 @@ impl Closure { .collect() } - pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let (captures, _) = infer.closure_info(self.id.into()); - let interner = DbInterner::new_with(db, None, None); + pub fn capture_types(&self, db: &'db dyn HirDatabase) -> Vec> { + let owner = db.lookup_intern_closure(self.id).0; + let infer = db.infer(owner); + let (captures, _) = infer.closure_info(self.id); + let env = db.trait_environment_for_body(owner); captures .iter() - .map(|capture| Type { - env: db.trait_environment_for_body(owner), - ty: capture.ty(db, self.subst.to_nextsolver(interner)).to_chalk(interner), - _pd: PhantomCovariantLifetime::new(), - }) + .map(|capture| Type { env: env.clone(), ty: capture.ty(db, self.subst) }) .collect() } pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let info = infer.closure_info(self.id.into()); + let owner = db.lookup_intern_closure(self.id).0; + let infer = db.infer(owner); + let info = infer.closure_info(self.id); info.1 } } @@ -4771,7 +4584,7 @@ impl Closure { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { owner: DefWithBodyId, - closure: ClosureId, + closure: InternedClosureId, capture: hir_ty::CapturedItem<'db>, } @@ -4889,15 +4702,14 @@ impl CaptureUsageSource { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type<'db> { env: Arc>, - ty: Ty, - _pd: PhantomCovariantLifetime<'db>, + ty: Ty<'db>, } impl<'db> Type<'db> { pub(crate) fn new_with_resolver( db: &'db dyn HirDatabase, resolver: &Resolver<'_>, - ty: Ty, + ty: Ty<'db>, ) -> Self { Type::new_with_resolver_inner(db, resolver, ty) } @@ -4905,275 +4717,252 @@ impl<'db> Type<'db> { pub(crate) fn new_with_resolver_inner( db: &'db dyn HirDatabase, resolver: &Resolver<'_>, - ty: Ty, + ty: Ty<'db>, ) -> Self { let environment = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + Type { env: environment, ty } } - pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Self { - Type { env: TraitEnvironment::empty(krate), ty, _pd: PhantomCovariantLifetime::new() } + pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty<'db>) -> Self { + Type { env: TraitEnvironment::empty(krate), ty } } - fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Self { + fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: 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)); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + Type { env: environment, ty } } fn from_def(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { let interner = DbInterner::new_with(db, None, None); let ty = db.ty(def.into()); - let substs = TyBuilder::unknown_subst( - db, - match def.into() { - TyDefId::AdtId(it) => GenericDefId::AdtId(it), - TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => { - return Type::new(db, def, ty.skip_binder().to_chalk(interner)); - } - }, - ); - let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) + let def = match def.into() { + TyDefId::AdtId(it) => GenericDefId::AdtId(it), + TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TyDefId::BuiltinType(_) => { + return Type::new(db, def, ty.skip_binder()); + } + }; + let args = GenericArgs::error_for_item(interner, def.into()); + Type::new(db, def, ty.instantiate(interner, args)) } - fn from_def_placeholders( - db: &'db dyn HirDatabase, - def: impl Into + HasResolver, - ) -> Self { - let interner = DbInterner::new_with(db, None, None); + // FIXME: We shouldn't leak `TyKind::Param`s. + fn from_def_params(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { let ty = db.ty(def.into()); - let substs = TyBuilder::placeholder_subst( - db, - match def.into() { - TyDefId::AdtId(it) => GenericDefId::AdtId(it), - TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => { - return Type::new(db, def, ty.skip_binder().to_chalk(interner)); - } - }, - ); - let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) + Type::new(db, def, ty.instantiate_identity()) } fn from_value_def( db: &'db dyn HirDatabase, def: impl Into + HasResolver, ) -> Self { + let interner = DbInterner::new_with(db, None, None); let Some(ty) = db.value_ty(def.into()) else { - return Type::new(db, def, TyKind::Error.intern(Interner)); + return Type::new(db, def, Ty::new_error(interner, ErrorGuaranteed)); }; - let interner = DbInterner::new_with(db, None, None); - let substs = TyBuilder::unknown_subst( - db, - match def.into() { - ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), - ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), - ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), - ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), - ValueTyDefId::EnumVariantId(it) => { - GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) - } - ValueTyDefId::StaticId(_) => { - return Type::new(db, def, ty.skip_binder().to_chalk(interner)); - } - }, - ); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) + let def = match def.into() { + ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), + ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), + ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), + ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), + ValueTyDefId::EnumVariantId(it) => { + GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) + } + ValueTyDefId::StaticId(_) => { + return Type::new(db, def, ty.skip_binder()); + } + }; + let args = GenericArgs::error_for_item(interner, def.into()); + Type::new(db, def, ty.instantiate(interner, args)) } pub fn new_slice(ty: Self) -> Self { - Type { env: ty.env, ty: TyBuilder::slice(ty.ty), _pd: PhantomCovariantLifetime::new() } + let interner = DbInterner::conjure(); + Type { env: ty.env, ty: Ty::new_slice(interner, ty.ty) } } pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self { - let tys = tys.iter().map(|it| it.ty.clone()); - Type { - env: TraitEnvironment::empty(krate), - ty: TyBuilder::tuple_with(tys), - _pd: PhantomCovariantLifetime::new(), - } + let tys = tys.iter().map(|it| it.ty); + let interner = DbInterner::conjure(); + Type { env: TraitEnvironment::empty(krate), ty: Ty::new_tup_from_iter(interner, tys) } } pub fn is_unit(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..)) + self.ty.is_unit() } pub fn is_bool(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool)) + matches!(self.ty.kind(), TyKind::Bool) } pub fn is_str(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Str) + matches!(self.ty.kind(), TyKind::Str) } pub fn is_never(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Never) + matches!(self.ty.kind(), TyKind::Never) } pub fn is_mutable_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) + matches!(self.ty.kind(), TyKind::Ref(.., hir_ty::next_solver::Mutability::Mut)) } pub fn is_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(..)) + matches!(self.ty.kind(), TyKind::Ref(..)) } pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { - return go(db, &self.ty); + let interner = DbInterner::new_with(db, None, None); + return self.ty.visit_with(&mut Visitor { interner }).is_break(); fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { match adt_id { - hir_def::AdtId::StructId(s) => { + 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, + AdtId::UnionId(_) | AdtId::EnumId(_) => false, } } - fn go(db: &dyn HirDatabase, ty: &Ty) -> bool { - match ty.kind(Interner) { - // Reference itself - TyKind::Ref(_, _, _) => true, + struct Visitor<'db> { + interner: DbInterner<'db>, + } - // For non-phantom_data adts we check variants/fields as well as generic parameters - 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![]; + impl<'db> TypeVisitor> for Visitor<'db> { + type Result = ControlFlow<()>; - 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())] - } - }; + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + match ty.kind() { + // Reference itself + TyKind::Ref(..) => ControlFlow::Break(()), - variants - .into_iter() - .flat_map(|variant| variant.into_iter()) - .any(|ty| go(db, &ty)) - || substitution - .iter(Interner) - .filter_map(|x| x.ty(Interner)) - .any(|ty| go(db, ty)) - } - // And for `PhantomData`, we check `T`. - TyKind::Adt(_, substitution) - | 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)) - } + // For non-phantom_data adts we check variants/fields as well as generic parameters + TyKind::Adt(adt_def, args) + if !is_phantom_data(self.interner.db(), adt_def.def_id().0) => + { + let _variant_id_to_fields = |id: VariantId| { + let variant_data = &id.fields(self.interner.db()); + if variant_data.fields().is_empty() { + vec![] + } else { + let field_types = self.interner.db().field_types_ns(id); + variant_data + .fields() + .iter() + .map(|(idx, _)| { + field_types[idx].instantiate(self.interner, args) + }) + .filter(|it| !it.references_non_lt_error()) + .collect() + } + }; + let variant_id_to_fields = |_: VariantId| vec![]; - // For `[T]` or `*T` we check `T` - TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, ty), + let variants: Vec>> = match adt_def.def_id().0 { + AdtId::StructId(id) => { + vec![variant_id_to_fields(id.into())] + } + AdtId::EnumId(id) => id + .enum_variants(self.interner.db()) + .variants + .iter() + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) + .collect(), + AdtId::UnionId(id) => { + vec![variant_id_to_fields(id.into())] + } + }; - // Consider everything else as not reference - _ => false, + variants + .into_iter() + .flat_map(|variant| variant.into_iter()) + .try_for_each(|ty| ty.visit_with(self))?; + args.visit_with(self) + } + // And for `PhantomData`, we check `T`. + _ => ty.super_visit_with(self), + } } } } pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> { - let (ty, _lt, m) = self.ty.as_reference()?; - let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut)); - Some((self.derived(ty.clone()), m)) + let TyKind::Ref(_lt, ty, m) = self.ty.kind() else { return None }; + let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); + Some((self.derived(ty), m)) } pub fn add_reference(&self, mutability: Mutability) -> Self { + let interner = DbInterner::conjure(); let ty_mutability = match mutability { - Mutability::Shared => hir_ty::Mutability::Not, - Mutability::Mut => hir_ty::Mutability::Mut, + Mutability::Shared => hir_ty::next_solver::Mutability::Not, + Mutability::Mut => hir_ty::next_solver::Mutability::Mut, }; - self.derived(TyKind::Ref(ty_mutability, error_lifetime(), self.ty.clone()).intern(Interner)) + self.derived(Ty::new_ref(interner, Region::error(interner), self.ty, ty_mutability)) } pub fn is_slice(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Slice(..)) + matches!(self.ty.kind(), TyKind::Slice(..)) } pub fn is_usize(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) + matches!(self.ty.kind(), TyKind::Uint(rustc_type_ir::UintTy::Usize)) } pub fn is_float(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + matches!(self.ty.kind(), TyKind::Float(_)) } pub fn is_char(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Char)) + matches!(self.ty.kind(), TyKind::Char) } pub fn is_int_or_uint(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) + matches!(self.ty.kind(), TyKind::Int(_) | TyKind::Uint(_)) } pub fn is_scalar(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(_)) + matches!( + self.ty.kind(), + TyKind::Bool | TyKind::Char | TyKind::Int(_) | TyKind::Uint(_) | TyKind::Float(_) + ) } pub fn is_tuple(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Tuple(..)) + matches!(self.ty.kind(), TyKind::Tuple(..)) } pub fn remove_ref(&self) -> Option> { - match &self.ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), + match self.ty.kind() { + TyKind::Ref(_, ty, _) => Some(self.derived(ty)), _ => None, } } pub fn as_slice(&self) -> Option> { - match &self.ty.kind(Interner) { - TyKind::Slice(ty) => Some(self.derived(ty.clone())), + match self.ty.kind() { + TyKind::Slice(ty) => Some(self.derived(ty)), _ => None, } } pub fn strip_references(&self) -> Self { - self.derived(self.ty.strip_references().clone()) + self.derived(self.ty.strip_references()) } + // FIXME: This is the same as `remove_ref()`, remove one of these methods. pub fn strip_reference(&self) -> Self { - self.derived(self.ty.strip_reference().clone()) + self.derived(self.ty.strip_reference()) } pub fn is_unknown(&self) -> bool { - self.ty.is_unknown() + self.ty.is_ty_error() } /// Checks that particular type `ty` implements `std::future::IntoFuture` or @@ -5189,9 +4978,7 @@ impl<'db> Type<'db> { }) .or_else(|| LangItem::Future.resolve_trait(db, self.env.krate))?; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { return None; } @@ -5219,9 +5006,7 @@ impl<'db> Type<'db> { let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else { return false; }; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, iterator_trait) + traits::implements_trait_unique(self.ty, db, self.env.clone(), iterator_trait) } /// Resolves the projection `::IntoIter` and returns the resulting type @@ -5234,9 +5019,7 @@ impl<'db> Type<'db> { }, )?; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { return None; } @@ -5256,43 +5039,18 @@ impl<'db> Type<'db> { None => return false, }; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, fnonce_trait) + traits::implements_trait_unique(self.ty, db, self.env.clone(), fnonce_trait) } // FIXME: Find better API that also handles const generics pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool { - let mut it = args.iter().map(|t| t.ty.clone()); - let trait_ref = TyBuilder::trait_ref(db, trait_.id) - .push(self.ty.clone()) - .fill(|x| { - match x { - ParamKind::Type => { - it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => { - // FIXME: this code is not covered in tests. - unknown_const_as_generic(ty.clone()) - } - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(); - - let goal = Canonical { - value: hir_ty::InEnvironment::new( - &self.env.env.to_chalk(DbInterner::new_with( - db, - Some(self.env.krate), - self.env.block, - )), - trait_ref.cast(Interner), - ), - binders: CanonicalVarKinds::empty(Interner), - }; - - !db.trait_solve(self.env.krate, self.env.block, goal).no_solution() + let interner = DbInterner::new_with(db, None, None); + let args = generic_args_from_tys( + interner, + trait_.id.into(), + std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)), + ); + traits::implements_trait_unique_with_args(db, self.env.clone(), trait_.id, args) } pub fn normalize_trait_assoc_type( @@ -5301,27 +5059,25 @@ impl<'db> Type<'db> { args: &[Type<'db>], alias: TypeAlias, ) -> Option> { - let mut args = args.iter(); - let trait_id = match alias.id.lookup(db).container { - ItemContainerId::TraitId(id) => id, - _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"), - }; - let parent_subst = TyBuilder::subst_for_def(db, trait_id, None) - .push(self.ty.clone()) - .fill(|it| { - // FIXME: this code is not covered in tests. - match it { - ParamKind::Type => args.next().unwrap().ty.clone().cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(); + let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + let args = generic_args_from_tys( + interner, + alias.id.into(), + std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)), + ); // FIXME: We don't handle GATs yet. - let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build(); + let projection = Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy::new(interner, alias.id.into(), args), + ); - let ty = db.normalize_projection(projection, self.env.clone()); - if ty.is_unknown() { None } else { Some(self.derived(ty)) } + // FIXME(next-solver): This needs to be `PostAnalysis`, but this currently causes errors due to our incorrect + // handling of opaques. `non_body_analysis()` will also cause errors (from not revealing opaques inside their + // defining places), so we choose between two bad options. + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + let ty = structurally_normalize_ty(&infcx, projection, self.env.clone()); + if ty.is_ty_error() { None } else { Some(self.derived(ty)) } } pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool { @@ -5332,23 +5088,27 @@ impl<'db> Type<'db> { } pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option> { - let callee = match self.ty.kind(Interner) { - TyKind::Closure(id, subst) => Callee::Closure(*id, subst.clone()), - TyKind::Function(_) => Callee::FnPtr, - TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), + let interner = DbInterner::new_with(db, None, None); + let callee = match self.ty.kind() { + TyKind::Closure(id, subst) => Callee::Closure(id.0, subst), + TyKind::FnPtr(..) => Callee::FnPtr, + TyKind::FnDef(id, _) => Callee::Def(id.0), kind => { // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment - let (ty, kind) = if let TyKind::Ref(_, _, ty) = kind { - (ty, ty.kind(Interner)) + let (ty, kind) = if let TyKind::Ref(_, ty, _) = kind { + (ty, ty.kind()) } else { - (&self.ty, kind) + (self.ty, kind) }; if let TyKind::Closure(closure, subst) = kind { - let sig = ty.callable_sig(db)?; + let sig = subst + .split_closure_args_untupled() + .closure_sig_as_fn_ptr_ty + .callable_sig(interner)?; return Some(Callable { ty: self.clone(), sig, - callee: Callee::Closure(*closure, subst.clone()), + callee: Callee::Closure(closure.0, subst), is_bound_method: false, }); } @@ -5362,32 +5122,32 @@ impl<'db> Type<'db> { } }; - let sig = self.ty.callable_sig(db)?; + let sig = self.ty.callable_sig(interner)?; Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) } pub fn is_closure(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Closure { .. }) + matches!(self.ty.kind(), TyKind::Closure { .. }) } - pub fn as_closure(&self) -> Option { - match self.ty.kind(Interner) { - TyKind::Closure(id, subst) => Some(Closure { id: *id, subst: subst.clone() }), + pub fn as_closure(&self) -> Option> { + match self.ty.kind() { + TyKind::Closure(id, subst) => Some(Closure { id: id.0, subst }), _ => None, } } pub fn is_fn(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. }) + matches!(self.ty.kind(), TyKind::FnDef(..) | TyKind::FnPtr { .. }) } pub fn is_array(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Array(..)) + matches!(self.ty.kind(), TyKind::Array(..)) } pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool { - let adt_id = match *self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, + let adt_id = match self.ty.kind() { + TyKind::Adt(adt_def, ..) => adt_def.def_id().0, _ => return false, }; @@ -5399,100 +5159,64 @@ impl<'db> Type<'db> { } pub fn is_raw_ptr(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Raw(..)) + matches!(self.ty.kind(), TyKind::RawPtr(..)) } pub fn remove_raw_ptr(&self) -> Option> { - if let TyKind::Raw(_, ty) = self.ty.kind(Interner) { - Some(self.derived(ty.clone())) - } else { - None - } + if let TyKind::RawPtr(ty, _) = self.ty.kind() { Some(self.derived(ty)) } else { None } } pub fn contains_unknown(&self) -> bool { - // FIXME: When we get rid of `ConstScalar::Unknown`, we can just look at precomputed - // `TypeFlags` in `TyData`. - return go(&self.ty); - - fn go(ty: &Ty) -> bool { - match ty.kind(Interner) { - TyKind::Error => true, - - TyKind::Adt(_, substs) - | TyKind::AssociatedType(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::OpaqueType(_, substs) - | TyKind::FnDef(_, substs) - | TyKind::Closure(_, substs) => { - substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go) - } - - TyKind::Array(_ty, len) if len.is_unknown() => true, - TyKind::Array(ty, _) - | TyKind::Slice(ty) - | TyKind::Raw(_, ty) - | TyKind::Ref(_, _, ty) => go(ty), - - TyKind::Scalar(_) - | TyKind::Str - | TyKind::Never - | TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) - | TyKind::Dyn(_) - | TyKind::Function(_) - | TyKind::Alias(_) - | TyKind::Foreign(_) - | TyKind::Coroutine(..) - | TyKind::CoroutineWitness(..) => false, - } - } + self.ty.references_non_lt_error() } pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> { - let (variant_id, substs) = match self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs), - TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs), + let interner = DbInterner::new_with(db, None, None); + let (variant_id, substs) = match self.ty.kind() { + TyKind::Adt(adt_def, substs) => { + let id = match adt_def.def_id().0 { + AdtId::StructId(id) => id.into(), + AdtId::UnionId(id) => id.into(), + AdtId::EnumId(_) => return Vec::new(), + }; + (id, substs) + } _ => return Vec::new(), }; - db.field_types(variant_id) + db.field_types_ns(variant_id) .iter() .map(|(local_id, ty)| { let def = Field { parent: variant_id.into(), id: local_id }; - let ty = ty.clone().substitute(Interner, substs); + let ty = ty.instantiate(interner, substs); (def, self.derived(ty)) }) .collect() } pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec { - if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) { - substs - .iter(Interner) - .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())) - .collect() + if let TyKind::Tuple(substs) = self.ty.kind() { + substs.iter().map(|ty| self.derived(ty)).collect() } else { Vec::new() } } pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> { - if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize)) + if let TyKind::Array(ty, len) = self.ty.kind() { + try_const_usize(db, len).map(|it| (self.derived(ty), it as usize)) } else { None } } pub fn fingerprint_for_trait_impl(&self) -> Option { - let interner = DbInterner::conjure(); - TyFingerprint::for_trait_impl(self.ty.to_nextsolver(interner)) + TyFingerprint::for_trait_impl(self.ty) } - pub(crate) fn canonical(&self) -> Canonical { - hir_ty::replace_errors_with_variables(&self.ty) + pub(crate) fn canonical(&self, db: &'db dyn HirDatabase) -> Canonical<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + hir_ty::replace_errors_with_variables(interner, &self.ty) } /// Returns types that this type dereferences to (including this type itself). The returned @@ -5504,9 +5228,10 @@ impl<'db> Type<'db> { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator { + fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator> { + let interner = DbInterner::new_with(db, None, None); // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(&self.ty); + let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); autoderef(db, self.env.clone(), canonical) } @@ -5532,8 +5257,7 @@ impl<'db> Type<'db> { krate: Crate, callback: &mut dyn FnMut(AssocItemId) -> bool, ) { - let interner = DbInterner::new_with(db, None, None); - let ty_ns = self.ty.to_nextsolver(interner); + let ty_ns = self.ty; let def_crates = match method_resolution::def_crates(db, ty_ns, krate.id) { Some(it) => it, None => return, @@ -5570,15 +5294,13 @@ impl<'db> Type<'db> { /// - "U" /// ``` pub fn type_arguments(&self) -> impl Iterator> + '_ { - self.ty - .strip_references() - .as_adt() - .map(|(_, substs)| substs) - .or_else(|| self.ty.strip_references().as_tuple()) - .into_iter() - .flat_map(|substs| substs.iter(Interner)) - .filter_map(|arg| arg.ty(Interner).cloned()) - .map(move |ty| self.derived(ty)) + match self.ty.strip_references().kind() { + TyKind::Adt(_, substs) => Either::Left(substs.types().map(move |ty| self.derived(ty))), + TyKind::Tuple(substs) => { + Either::Right(Either::Left(substs.iter().map(move |ty| self.derived(ty)))) + } + _ => Either::Right(Either::Right(std::iter::empty())), + } } /// Iterates its type and const arguments @@ -5608,15 +5330,13 @@ impl<'db> Type<'db> { .strip_references() .as_adt() .into_iter() - .flat_map(|(_, substs)| substs.iter(Interner)) - .filter_map(move |arg| { - // arg can be either a `Ty` or `constant` - if let Some(ty) = arg.ty(Interner) { - Some(format_smolstr!("{}", ty.display(db, display_target))) - } else { - arg.constant(Interner) - .map(|const_| format_smolstr!("{}", const_.display(db, display_target))) + .flat_map(|(_, substs)| substs.iter()) + .filter_map(move |arg| match arg { + GenericArg::Ty(ty) => Some(format_smolstr!("{}", ty.display(db, display_target))), + GenericArg::Const(const_) => { + Some(format_smolstr!("{}", const_.display(db, display_target))) } + GenericArg::Lifetime(_) => None, }) } @@ -5733,8 +5453,9 @@ impl<'db> Type<'db> { ?name, ) .entered(); + let interner = DbInterner::new_with(db, None, None); // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(&self.ty); + let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); let krate = scope.krate(); let environment = scope @@ -5743,11 +5464,7 @@ impl<'db> Type<'db> { .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); _ = method_resolution::iterate_method_candidates_dyn( - &canonical.to_nextsolver(DbInterner::new_with( - db, - Some(environment.krate), - environment.block, - )), + &canonical, db, environment, traits_in_scope, @@ -5825,7 +5542,8 @@ impl<'db> Type<'db> { } } - let canonical = hir_ty::replace_errors_with_variables(&self.ty); + let interner = DbInterner::new_with(db, None, None); + let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); let krate = scope.krate(); let environment = scope @@ -5834,11 +5552,7 @@ impl<'db> Type<'db> { .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); _ = method_resolution::iterate_path_candidates( - &canonical.to_nextsolver(DbInterner::new_with( - db, - Some(environment.krate), - environment.block, - )), + &canonical, db, environment, traits_in_scope, @@ -5877,7 +5591,7 @@ impl<'db> Type<'db> { pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator { let _p = tracing::info_span!("env_traits").entered(); self.autoderef_(db) - .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) + .filter(|ty| matches!(ty.kind(), TyKind::Param(_))) .flat_map(|ty| { self.env .traits_in_scope_from_clauses(ty) @@ -5888,136 +5602,66 @@ impl<'db> Type<'db> { pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option> { self.ty.impl_trait_bounds(db).map(|it| { - it.into_iter().filter_map(|pred| match pred.skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) - } + it.into_iter().filter_map(|pred| match pred.kind().skip_binder() { + ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), _ => None, }) }) } pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option { - self.ty.associated_type_parent_trait(db).map(Into::into) + let TyKind::Alias(AliasTyKind::Projection, alias) = self.ty.kind() else { return None }; + match alias.def_id.expect_type_alias().loc(db).container { + ItemContainerId::TraitId(id) => Some(Trait { id }), + _ => None, + } } - fn derived(&self, ty: Ty) -> Self { - Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } + fn derived(&self, ty: Ty<'db>) -> Self { + Type { env: self.env.clone(), ty } } - /// Visits every type, including generic arguments, in this type. `cb` is called with type + /// Visits every type, including generic arguments, in this type. `callback` is called with type /// itself first, and then with its generic arguments. - pub fn walk(&self, db: &'db dyn HirDatabase, mut cb: impl FnMut(Type<'db>)) { - fn walk_substs<'db>( + pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { + struct Visitor<'db, F> { db: &'db dyn HirDatabase, - type_: &Type<'db>, - substs: &Substitution, - cb: &mut impl FnMut(Type<'db>), - ) { - for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) { - walk_type(db, &type_.derived(ty.clone()), cb); - } - } - - fn walk_bounds<'db>( - db: &'db dyn HirDatabase, - type_: &Type<'db>, - bounds: &[QuantifiedWhereClause], - cb: &mut impl FnMut(Type<'db>), - ) { - for pred in bounds { - if let WhereClause::Implemented(trait_ref) = pred.skip_binders() { - cb(type_.clone()); - // skip the self type. it's likely the type we just got the bounds from - if let [self_ty, params @ ..] = trait_ref.substitution.as_slice(Interner) { - for ty in - params.iter().filter(|&ty| ty != self_ty).filter_map(|a| a.ty(Interner)) - { - walk_type(db, &type_.derived(ty.clone()), cb); - } - } - } - } + env: Arc>, + callback: F, + visited: FxHashSet>, } + impl<'db, F> TypeVisitor> for Visitor<'db, F> + where + F: FnMut(Type<'db>), + { + type Result = (); - fn walk_type<'db>( - db: &'db dyn HirDatabase, - type_: &Type<'db>, - cb: &mut impl FnMut(Type<'db>), - ) { - let ty = type_.ty.strip_references(); - match ty.kind(Interner) { - TyKind::Adt(_, substs) => { - cb(type_.derived(ty.clone())); - walk_substs(db, type_, substs, cb); - } - 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())); - } - walk_substs(db, type_, substs, cb); - } - TyKind::OpaqueType(_, subst) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, subst, cb); - } - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, &opaque_ty.substitution, cb); - } - TyKind::Placeholder(_) => { - cb(type_.derived(ty.clone())); - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - } - TyKind::Dyn(bounds) => { - walk_bounds( - db, - &type_.derived(ty.clone()), - bounds.bounds.skip_binders().interned(), - cb, - ); + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if !self.visited.insert(ty) { + return; } - TyKind::Ref(_, _, ty) - | TyKind::Raw(_, ty) - | TyKind::Array(ty, _) - | TyKind::Slice(ty) => { - walk_type(db, &type_.derived(ty.clone()), cb); - } + (self.callback)(Type { env: self.env.clone(), ty }); - TyKind::FnDef(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::Closure(.., substs) => { - walk_substs(db, type_, substs, cb); - } - TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { - walk_substs(db, type_, &substitution.0, cb); + if let Some(bounds) = ty.impl_trait_bounds(self.db) { + bounds.visit_with(self); } - _ => {} + ty.super_visit_with(self); } } - walk_type(db, self, &mut cb); + let mut visitor = + Visitor { db, env: self.env.clone(), callback, visited: FxHashSet::default() }; + self.ty.visit_with(&mut visitor); } /// Check if type unifies with another type. /// /// Note that we consider placeholder types to unify with everything. /// For example `Option` and `Option` unify although there is unresolved goal `T = U`. pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); + let interner = DbInterner::new_with(db, None, None); + let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); hir_ty::could_unify(db, self.env.clone(), &tys) } @@ -6026,35 +5670,34 @@ impl<'db> Type<'db> { /// This means that placeholder types are not considered to unify if there are any bounds set on /// them. For example `Option` and `Option` do not unify as we cannot show that `T = U` pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); + let interner = DbInterner::new_with(db, None, None); + let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); hir_ty::could_unify_deeply(db, self.env.clone(), &tys) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone())); + let interner = DbInterner::new_with(db, None, None); + let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, to.ty)); hir_ty::could_coerce(db, self.env.clone(), &tys) } - 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).0), - }), + pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option { + match self.ty.kind() { + TyKind::Param(param) => Some(TypeParam { id: param.id }), _ => None, } } /// Returns unique `GenericParam`s contained in this type. pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet { - hir_ty::collect_placeholders(&self.ty, db) + hir_ty::collect_params(&self.ty) .into_iter() .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result { - let interner = DbInterner::new_with(db, None, None); - db.layout_of_ty(self.ty.to_nextsolver(interner), self.env.clone()) + db.layout_of_ty(self.ty, self.env.clone()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } @@ -6062,33 +5705,27 @@ impl<'db> Type<'db> { let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); // FIXME: This should be `PostAnalysis` I believe. let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); - hir_ty::drop::has_drop_glue(&infcx, self.ty.to_nextsolver(interner), self.env.clone()) + hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.clone()) } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeNs<'db> { env: Arc>, - ty: hir_ty::next_solver::Ty<'db>, - _pd: PhantomCovariantLifetime<'db>, + ty: Ty<'db>, } impl<'db> TypeNs<'db> { - fn new( - db: &'db dyn HirDatabase, - lexical_env: impl HasResolver, - ty: hir_ty::next_solver::Ty<'db>, - ) -> Self { + fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: 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() } + TypeNs { env: environment, ty } } - pub fn to_type(&self, db: &'db dyn HirDatabase) -> Type<'db> { - let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); - Type { env: self.env.clone(), ty: convert_ty_for_result(interner, self.ty), _pd: self._pd } + pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> { + Type { env: self.env.clone(), ty: self.ty } } // FIXME: Find better API that also handles const generics @@ -6144,40 +5781,38 @@ impl InlineAsmOperand { #[derive(Debug)] pub struct Callable<'db> { ty: Type<'db>, - sig: CallableSig, - callee: Callee, + sig: PolyFnSig<'db>, + callee: Callee<'db>, /// Whether this is a method that was called with method call syntax. is_bound_method: bool, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] -enum Callee { +enum Callee<'db> { Def(CallableDefId), - Closure(ClosureId, Substitution), + Closure(InternedClosureId, GenericArgs<'db>), FnPtr, FnImpl(FnTrait), } -pub enum CallableKind { +pub enum CallableKind<'db> { Function(Function), TupleStruct(Struct), TupleEnumVariant(Variant), - Closure(Closure), + Closure(Closure<'db>), FnPtr, FnImpl(FnTrait), } impl<'db> Callable<'db> { - pub fn kind(&self) -> CallableKind { + pub fn kind(&self) -> CallableKind<'db> { match self.callee { Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) } - Callee::Closure(id, ref subst) => { - CallableKind::Closure(Closure { id, subst: subst.clone() }) - } + Callee::Closure(id, ref subst) => CallableKind::Closure(Closure { id, subst: *subst }), Callee::FnPtr => CallableKind::FnPtr, Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_), } @@ -6188,25 +5823,31 @@ impl<'db> Callable<'db> { _ => return None, }; let func = Function { id: func }; - Some((func.self_param(db)?, self.ty.derived(self.sig.params()[0].clone()))) + Some(( + func.self_param(db)?, + self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]), + )) } pub fn n_params(&self) -> usize { - self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } + self.sig.skip_binder().inputs_and_output.inputs().len() + - if self.is_bound_method { 1 } else { 0 } } pub fn params(&self) -> Vec> { self.sig - .params() + .skip_binder() + .inputs_and_output + .inputs() .iter() .enumerate() .skip(if self.is_bound_method { 1 } else { 0 }) - .map(|(idx, ty)| (idx, self.ty.derived(ty.clone()))) + .map(|(idx, ty)| (idx, self.ty.derived(*ty))) .map(|(idx, ty)| Param { func: self.callee.clone(), idx, ty }) .collect() } pub fn return_type(&self) -> Type<'db> { - self.ty.derived(self.sig.ret().clone()) + self.ty.derived(self.sig.skip_binder().output()) } - pub fn sig(&self) -> &CallableSig { + pub fn sig(&self) -> impl Eq { &self.sig } @@ -6758,5 +6399,37 @@ fn as_name_opt(name: Option) -> Name { name.map_or_else(Name::missing, |name| name.as_name()) } +fn generic_args_from_tys<'db>( + interner: DbInterner<'db>, + def_id: SolverDefId, + args: impl IntoIterator>, +) -> GenericArgs<'db> { + let mut args = args.into_iter(); + GenericArgs::for_item(interner, def_id, |_, _, id, _| { + if matches!(id, GenericParamId::TypeParamId(_)) + && let Some(arg) = args.next() + { + arg.into() + } else { + next_solver::GenericArg::error_from_id(interner, id) + } + }) +} + +fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { + let params = db.generic_params(generic_def); + let defaults = db.generic_defaults_ns(generic_def); + params + .iter_type_or_consts() + .filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_))) + .map(|(local_id, _)| TypeOrConstParamId { parent: generic_def, local_id }) + .any(|param| { + let Some(param) = hir_ty::param_idx(db, param) else { + return false; + }; + defaults.get(param).is_none() + }) +} + pub use hir_ty::next_solver; pub use hir_ty::setup_tracing; diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 45c2020bc8cea..eecca02440919 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -28,9 +28,10 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::AsName, }; -use hir_ty::diagnostics::{unsafe_operations, unsafe_operations_for_body}; -use hir_ty::next_solver::DbInterner; -use hir_ty::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; +use hir_ty::{ + diagnostics::{unsafe_operations, unsafe_operations_for_body}, + next_solver::DbInterner, +}; use intern::{Interned, Symbol, sym}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; @@ -1563,16 +1564,11 @@ impl<'db> SemanticsImpl<'db> { let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?; - let interner = DbInterner::new_with(self.db, None, None); - analyzer.expr_adjustments(expr).map(|it| { it.iter() .map(|adjust| { - let target = Type::new_with_resolver( - self.db, - &analyzer.resolver, - adjust.target.to_chalk(interner), - ); + let target = + Type::new_with_resolver(self.db, &analyzer.resolver, adjust.target); let kind = match adjust.kind { hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { @@ -1666,7 +1662,7 @@ impl<'db> SemanticsImpl<'db> { trait_.id.into(), |_, _, id, _| { assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type"); - subst.next().expect("too few subst").ty.to_nextsolver(interner).into() + subst.next().expect("too few subst").ty.into() }, ); assert!(subst.next().is_none(), "too many subst"); 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 a4bc3e8f1a13a..8d2ba7e604e76 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -7,13 +7,6 @@ //! purely for "IDE needs". 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, - TupleField, Type, TypeAlias, Variant, - db::HirDatabase, - semantics::{PathResolution, PathResolutionPerNs}, -}; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, @@ -36,23 +29,24 @@ use hir_expand::{ name::{AsName, Name}, }; use hir_ty::{ - Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy, - Substitution, ToChalk, TraitEnvironment, Ty, TyKind, TyLoweringContext, + Adjustment, InferenceResult, LifetimeElisionKind, TraitEnvironment, TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, }, - from_assoc_type_id, lang_items::lang_items_for_bin_op, method_resolution, next_solver::{ - DbInterner, GenericArgs, TypingMode, - infer::DbInternerInferExt, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + DbInterner, ErrorGuaranteed, GenericArgs, Ty, TyKind, TypingMode, infer::DbInternerInferExt, }, + traits::structurally_normalize_ty, }; use intern::sym; use itertools::Itertools; +use rustc_type_ir::{ + AliasTyKind, + inherent::{AdtDef, IntoKind, Ty as _}, +}; use smallvec::SmallVec; use stdx::never; use syntax::{ @@ -61,6 +55,14 @@ use syntax::{ }; use triomphe::Arc; +use crate::{ + Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, + Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, + TupleField, Type, TypeAlias, Variant, + db::HirDatabase, + semantics::{PathResolution, PathResolutionPerNs}, +}; + /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of /// original source files. It should not be used inside the HIR itself. #[derive(Debug)] @@ -292,9 +294,7 @@ impl<'db> SourceAnalyzer<'db> { .and_then(|expr_id| infer.expr_adjustment(expr_id)) .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target)); let ty = infer[expr_id]; - let mk_ty = |ty: hir_ty::next_solver::Ty<'_>| { - Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) - }; + let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); Some((mk_ty(ty), coerced.map(mk_ty))) } @@ -316,9 +316,7 @@ impl<'db> SourceAnalyzer<'db> { }; let ty = infer[expr_or_pat_id]; - let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| { - Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) - }; + let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); Some((mk_ty(ty), coerced.map(mk_ty))) } @@ -330,9 +328,7 @@ impl<'db> SourceAnalyzer<'db> { let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer()?; let ty = infer[binding_id]; - let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| { - Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) - }; + let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); Some(mk_ty(ty)) } @@ -343,7 +339,7 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option> { let binding = self.body()?.self_param?; let ty = self.infer()?[binding]; - Some(Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))) + Some(Type::new_with_resolver(db, &self.resolver, ty)) } pub(crate) fn binding_mode_of_pat( @@ -374,9 +370,7 @@ impl<'db> SourceAnalyzer<'db> { infer .pat_adjustment(pat_id.as_pat()?)? .iter() - .map(|ty| { - Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())) - }) + .map(|ty| Type::new_with_resolver(db, &self.resolver, *ty)) .collect(), ) } @@ -390,7 +384,7 @@ impl<'db> SourceAnalyzer<'db> { let (func, args) = self.infer()?.method_resolution(expr_id)?; let interner = DbInterner::new_with(db, None, None); let ty = db.value_ty(func.into())?.instantiate(interner, args); - let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner)); + let ty = Type::new_with_resolver(db, &self.resolver, ty); let mut res = ty.as_callable(db)?; res.is_bound_method = true; Some(res) @@ -414,18 +408,13 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option<(Either, Option>)> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let inference_result = self.infer()?; - let interner = DbInterner::new_with(db, None, None); match inference_result.method_resolution(expr_id) { Some((f_in_trait, substs)) => { let (fn_, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs); Some(( Either::Left(fn_.into()), - Some(GenericSubstitution::new( - fn_.into(), - subst.to_chalk(interner), - self.trait_environment(db), - )), + Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))), )) } None => { @@ -465,11 +454,7 @@ impl<'db> SourceAnalyzer<'db> { let body = self.store()?; if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] { let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?; - return Some(GenericSubstitution::new( - adt.into(), - subst.to_chalk(DbInterner::conjure()), - self.trait_environment(db), - )); + return Some(GenericSubstitution::new(adt.into(), subst, self.trait_environment(db))); } None } @@ -483,7 +468,6 @@ impl<'db> SourceAnalyzer<'db> { let (def, ..) = self.body_()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; - let interner = DbInterner::new_with(db, None, None); match inference_result.field_resolution(expr_id) { Some(field) => match field { Either::Left(field) => Some(( @@ -503,11 +487,7 @@ impl<'db> SourceAnalyzer<'db> { let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs); ( Either::Right(f.into()), - Some(GenericSubstitution::new( - f.into(), - subst.to_chalk(interner), - self.trait_environment(db), - )), + Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))), ) }), } @@ -557,7 +537,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option { - let mut ty = self.ty_of_expr(await_expr.expr()?)?.clone(); + let mut ty = self.ty_of_expr(await_expr.expr()?)?; let into_future_trait = self .resolver @@ -565,7 +545,7 @@ impl<'db> SourceAnalyzer<'db> { .map(Trait::from); if let Some(into_future_trait) = into_future_trait { - let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone()); + let type_ = Type::new_with_resolver(db, &self.resolver, ty); if type_.impls_trait(db, into_future_trait, &[]) { let items = into_future_trait.items(db); let into_future_type = items.into_iter().find_map(|item| match item { @@ -585,7 +565,7 @@ impl<'db> SourceAnalyzer<'db> { // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself // doesn't have any generic parameters, so we skip building another subst for `poll()`. let interner = DbInterner::new_with(db, None, None); - let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); + let substs = GenericArgs::new_from_iter(interner, [ty.into()]); Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs)) } @@ -627,7 +607,7 @@ impl<'db> SourceAnalyzer<'db> { let interner = DbInterner::new_with(db, None, None); // HACK: subst for all methods coincides with that for their trait because the methods // don't have any generic parameters, so we skip building another subst for the methods. - let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); + let substs = GenericArgs::new_from_iter(interner, [ty.into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -658,10 +638,7 @@ impl<'db> SourceAnalyzer<'db> { // HACK: subst for all methods coincides with that for their trait because the methods // don't have any generic parameters, so we skip building another subst for the methods. let interner = DbInterner::new_with(db, None, None); - let substs = GenericArgs::new_from_iter( - interner, - [base_ty.to_nextsolver(interner).into(), index_ty.to_nextsolver(interner).into()], - ); + let substs = GenericArgs::new_from_iter(interner, [base_ty.into(), index_ty.into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -679,10 +656,7 @@ impl<'db> SourceAnalyzer<'db> { // HACK: subst for `index()` coincides with that for `Index` because `index()` itself // doesn't have any generic parameters, so we skip building another subst for `index()`. let interner = DbInterner::new_with(db, None, None); - let substs = GenericArgs::new_from_iter( - interner, - [lhs.to_nextsolver(interner).into(), rhs.to_nextsolver(interner).into()], - ); + let substs = GenericArgs::new_from_iter(interner, [lhs.into(), rhs.into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -698,7 +672,7 @@ impl<'db> SourceAnalyzer<'db> { // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself // doesn't have any generic parameters, so we skip building another subst for `branch()`. let interner = DbInterner::new_with(db, None, None); - let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]); + let substs = GenericArgs::new_from_iter(interner, [ty.into()]); Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs)) } @@ -735,12 +709,11 @@ impl<'db> SourceAnalyzer<'db> { } }; let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?; - let subst = subst.to_chalk(interner); let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?; let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; let field_ty = - db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst); + (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst); Some(( field.into(), local, @@ -762,9 +735,8 @@ impl<'db> SourceAnalyzer<'db> { let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?; - let subst = subst.to_chalk(interner); let field_ty = - db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst); + (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst); Some(( field.into(), Type::new_with_resolver(db, &self.resolver, field_ty), @@ -817,43 +789,40 @@ impl<'db> SourceAnalyzer<'db> { let container = self.type_of_type(db, &container)?; let trait_env = container.env; + + let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let mut container = Either::Right(container.ty); for field_name in offset_of_expr.fields() { - if let Some( - TyKind::Alias(AliasTy::Projection(ProjectionTy { associated_ty_id, substitution })) - | TyKind::AssociatedType(associated_ty_id, substitution), - ) = container.as_ref().right().map(|it| it.kind(Interner)) - { - let projection = ProjectionTy { - associated_ty_id: *associated_ty_id, - substitution: substitution.clone(), - }; - container = Either::Right(db.normalize_projection(projection, trait_env.clone())); + if let Either::Right(container) = &mut container { + *container = structurally_normalize_ty(&infcx, *container, trait_env.clone()); } - let handle_variants = |variant: VariantId, subst: &Substitution, container: &mut _| { - let fields = variant.fields(db); - let field = fields.field(&field_name.as_name())?; - let field_types = db.field_types(variant); - *container = Either::Right(field_types[field].clone().substitute(Interner, subst)); - let generic_def = match variant { - VariantId::EnumVariantId(it) => it.loc(db).parent.into(), - VariantId::StructId(it) => it.into(), - VariantId::UnionId(it) => it.into(), + let handle_variants = + |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| { + let fields = variant.fields(db); + let field = fields.field(&field_name.as_name())?; + let field_types = db.field_types_ns(variant); + *container = Either::Right(field_types[field].instantiate(interner, subst)); + let generic_def = match variant { + VariantId::EnumVariantId(it) => it.loc(db).parent.into(), + VariantId::StructId(it) => it.into(), + VariantId::UnionId(it) => it.into(), + }; + Some(( + Either::Right(Field { parent: variant.into(), id: field }), + generic_def, + subst, + )) }; - Some(( - Either::Right(Field { parent: variant.into(), id: field }), - generic_def, - subst.clone(), - )) - }; - let temp_ty = TyKind::Error.intern(Interner); + let temp_ty = Ty::new_error(interner, ErrorGuaranteed); let (field_def, generic_def, subst) = - match std::mem::replace(&mut container, Either::Right(temp_ty.clone())) { + match std::mem::replace(&mut container, Either::Right(temp_ty)) { Either::Left((variant_id, subst)) => { - handle_variants(VariantId::from(variant_id), &subst, &mut container)? + handle_variants(VariantId::from(variant_id), subst, &mut container)? } - Either::Right(container_ty) => match container_ty.kind(Interner) { - TyKind::Adt(adt_id, subst) => match adt_id.0 { + Either::Right(container_ty) => match container_ty.kind() { + TyKind::Adt(adt_def, subst) => match adt_def.def_id().0 { AdtId::StructId(id) => { handle_variants(id.into(), subst, &mut container)? } @@ -863,8 +832,8 @@ impl<'db> SourceAnalyzer<'db> { AdtId::EnumId(id) => { let variants = id.enum_variants(db); let variant = variants.variant(&field_name.as_name())?; - container = Either::Left((variant, subst.clone())); - (Either::Left(Variant { id: variant }), id.into(), subst.clone()) + container = Either::Left((variant, subst)); + (Either::Left(Variant { id: variant }), id.into(), subst) } }, _ => return None, @@ -884,7 +853,6 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, path: &ast::Path, ) -> Option<(PathResolution, Option>)> { - let interner = DbInterner::new_with(db, None, None); let parent = path.syntax().parent(); let parent = || parent.clone(); @@ -900,31 +868,27 @@ impl<'db> SourceAnalyzer<'db> { None => { let subst = GenericSubstitution::new( f_in_trait.into(), - subs.to_chalk(interner), + subs, self.trait_environment(db), ); (assoc, subst) } Some(func_ty) => { - if let TyKind::FnDef(_fn_def, subs) = - func_ty.to_chalk(interner).kind(Interner) - { + if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() { let (fn_, subst) = self .resolve_impl_method_or_trait_def_with_subst( - db, - f_in_trait, - subs.to_nextsolver(interner), + db, f_in_trait, subs, ); let subst = GenericSubstitution::new( fn_.into(), - subst.to_chalk(interner), + subst, self.trait_environment(db), ); (fn_.into(), subst) } else { let subst = GenericSubstitution::new( f_in_trait.into(), - subs.to_chalk(interner), + subs, self.trait_environment(db), ); (assoc, subst) @@ -937,7 +901,7 @@ impl<'db> SourceAnalyzer<'db> { self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); let subst = GenericSubstitution::new( konst.into(), - subst.to_chalk(interner), + subst, self.trait_environment(db), ); (konst.into(), subst) @@ -946,7 +910,7 @@ impl<'db> SourceAnalyzer<'db> { assoc, GenericSubstitution::new( type_alias.into(), - subs.to_chalk(interner), + subs, self.trait_environment(db), ), ), @@ -970,7 +934,7 @@ impl<'db> SourceAnalyzer<'db> { self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); let subst = GenericSubstitution::new( konst.into(), - subst.to_chalk(interner), + subst, self.trait_environment(db), ); (konst.into(), subst) @@ -979,7 +943,7 @@ impl<'db> SourceAnalyzer<'db> { assoc, GenericSubstitution::new( assoc.into(), - subs.to_chalk(interner), + subs, self.trait_environment(db), ), ), @@ -1177,36 +1141,38 @@ impl<'db> SourceAnalyzer<'db> { let parent = parent()?; let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { let expr_id = self.expr_id(expr)?; - self.infer()?.type_of_expr_or_pat(expr_id)?.to_chalk(interner) + self.infer()?.type_of_expr_or_pat(expr_id)? } else if let Some(pat) = ast::Pat::cast(parent) { let pat_id = self.pat_id(&pat)?; - self.infer()?[pat_id].to_chalk(interner) + self.infer()?[pat_id] } else { return None; }; let env = self.trait_environment(db); - let (subst, expected_resolution) = match ty.kind(Interner) { - TyKind::Adt(adt_id, subst) => ( - GenericSubstitution::new(adt_id.0.into(), subst.clone(), env), - PathResolution::Def(ModuleDef::Adt(adt_id.0.into())), - ), - TyKind::AssociatedType(assoc_id, subst) => { - let assoc_id = from_assoc_type_id(*assoc_id); + let (subst, expected_resolution) = match ty.kind() { + TyKind::Adt(adt_def, subst) => { + let adt_id = adt_def.def_id().0; + ( + GenericSubstitution::new(adt_id.into(), subst, env), + PathResolution::Def(ModuleDef::Adt(adt_id.into())), + ) + } + TyKind::Alias(AliasTyKind::Projection, alias) => { + let assoc_id = alias.def_id.expect_type_alias(); ( - GenericSubstitution::new(assoc_id.into(), subst.clone(), env), + GenericSubstitution::new(assoc_id.into(), alias.args, env), PathResolution::Def(ModuleDef::TypeAlias(assoc_id.into())), ) } TyKind::FnDef(fn_id, subst) => { - let fn_id = ToChalk::from_chalk(db, *fn_id); - let generic_def_id = match fn_id { + let generic_def_id = match fn_id.0 { CallableDefId::StructId(id) => id.into(), CallableDefId::FunctionId(id) => id.into(), CallableDefId::EnumVariantId(_) => return None, }; ( - GenericSubstitution::new(generic_def_id, subst.clone(), env), - PathResolution::Def(ModuleDefId::from(fn_id).into()), + GenericSubstitution::new(generic_def_id, subst, env), + PathResolution::Def(ModuleDefId::from(fn_id.0).into()), ) } _ => return None, @@ -1260,8 +1226,7 @@ impl<'db> SourceAnalyzer<'db> { record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])? } }; - let interner = DbInterner::new_with(db, None, None); - let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields); + let res = self.missing_fields(db, substs, variant, missing_fields); Some(res) } @@ -1278,25 +1243,25 @@ impl<'db> SourceAnalyzer<'db> { let (variant, missing_fields, _exhaustive) = record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; - let interner = DbInterner::new_with(db, None, None); - let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields); + let res = self.missing_fields(db, substs, variant, missing_fields); Some(res) } fn missing_fields( &self, db: &'db dyn HirDatabase, - substs: &Substitution, + substs: GenericArgs<'db>, variant: VariantId, missing_fields: Vec, ) -> Vec<(Field, Type<'db>)> { - let field_types = db.field_types(variant); + let interner = DbInterner::new_with(db, None, None); + let field_types = db.field_types_ns(variant); missing_fields .into_iter() .map(|local_id| { let field = FieldId { parent: variant, local_id }; - let ty = field_types[local_id].clone().substitute(Interner, substs); + let ty = field_types[local_id].instantiate(interner, substs); (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty)) }) .collect() @@ -1455,10 +1420,8 @@ impl<'db> SourceAnalyzer<'db> { Some((trait_id, fn_id)) } - fn ty_of_expr(&self, expr: ast::Expr) -> Option { - self.infer()? - .type_of_expr_or_pat(self.expr_id(expr)?) - .map(|ty| ty.to_chalk(DbInterner::conjure())) + fn ty_of_expr(&self, expr: ast::Expr) -> Option> { + self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index 9df131f90e406..dddc03585a282 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -10,20 +10,21 @@ use std::iter; -use hir_ty::TyBuilder; -use hir_ty::db::HirDatabase; -use hir_ty::mir::BorrowKind; +use hir_ty::{ + db::HirDatabase, + mir::BorrowKind, + next_solver::{DbInterner, Ty}, +}; use itertools::Itertools; use rustc_hash::FxHashSet; +use rustc_type_ir::inherent::Ty as _; use span::Edition; use crate::{ Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef, - Type, TypeParam, + Type, TypeParam, term_search::Expr, }; -use crate::term_search::Expr; - use super::{LookupTable, NewTypesKey, TermSearchCtx}; /// # Trivial tactic @@ -596,10 +597,13 @@ pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); + let interner = DbInterner::new_with(db, None, None); + let bool_ty = Ty::new_bool(interner); + let unit_ty = Ty::new_unit(interner); [ - Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::bool()), value: "true" }, - Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::bool()), value: "false" }, - Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::unit()), value: "()" }, + Expr::FamousType { ty: Type::new(db, module.id, bool_ty), value: "true" }, + Expr::FamousType { ty: Type::new(db, module.id, bool_ty), value: "false" }, + Expr::FamousType { ty: Type::new(db, module.id, unit_ty), value: "()" }, ] .into_iter() .inspect(|exprs| { 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 c5d695ccec3a7..f29ccc985c18d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -695,7 +695,7 @@ pub(super) fn definition( DropInfo { drop_glue: field.ty(db).to_type(db).drop_glue(db), has_dtor: None } } Definition::Adt(Adt::Struct(strukt)) => { - let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db); + let struct_drop_glue = strukt.ty_params(db).drop_glue(db); let mut fields_drop_glue = strukt .fields(db) .iter() @@ -716,10 +716,10 @@ pub(super) fn definition( // Unions cannot have fields with drop glue. Definition::Adt(Adt::Union(union)) => DropInfo { drop_glue: DropGlue::None, - has_dtor: Some(union.ty_placeholders(db).drop_glue(db) != DropGlue::None), + has_dtor: Some(union.ty_params(db).drop_glue(db) != DropGlue::None), }, Definition::Adt(Adt::Enum(enum_)) => { - let enum_drop_glue = enum_.ty_placeholders(db).drop_glue(db); + let enum_drop_glue = enum_.ty_params(db).drop_glue(db); let fields_drop_glue = enum_ .variants(db) .iter() @@ -748,7 +748,7 @@ pub(super) fn definition( DropInfo { drop_glue: fields_drop_glue, has_dtor: None } } Definition::TypeAlias(type_alias) => { - DropInfo { drop_glue: type_alias.ty_placeholders(db).drop_glue(db), has_dtor: None } + DropInfo { drop_glue: type_alias.ty_params(db).drop_glue(db), has_dtor: None } } Definition::Local(local) => { DropInfo { drop_glue: local.ty(db).drop_glue(db), has_dtor: None } From 1597162eeaedb8b389acbfaf7639fe4b1df34f23 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 14 Oct 2025 14:47:08 +0800 Subject: [PATCH 54/59] Fix applicable on let-else for convert_to_guarded_return Example --- ```rust fn foo() -> bool { let$0 Some(x) = Some(2) else { return false }; } ``` **Before this PR**: ```rust fn foo() -> bool { let Some(Some(x)) = Some(2) else { return }; } ``` **After this PR**: Assist not applicable --- .../src/handlers/convert_to_guarded_return.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 82213ae3217e7..7bbe13bedd896 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -182,7 +182,7 @@ fn let_stmt_to_guarded_return( let cursor_in_range = let_token_range.cover(let_pattern_range).contains_range(ctx.selection_trimmed()); - if !cursor_in_range { + if !cursor_in_range || let_stmt.let_else().is_some() { return None; } @@ -911,6 +911,19 @@ fn main() { ); } + #[test] + fn ignore_let_else_branch() { + check_assist_not_applicable( + convert_to_guarded_return, + r#" +//- minicore: option +fn main() { + let$0 Some(x) = Some(2) else { return }; +} +"#, + ); + } + #[test] fn ignore_statements_after_if() { check_assist_not_applicable( From 1d2c84d57eda0632dcdad3de2e5ce44b77df222f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 16 Sep 2025 16:48:19 +0800 Subject: [PATCH 55/59] Add break value completion support ```rust fn foo() -> i32 { loop { $0 } } ``` **Before this PR**: ```rust fn foo() -> i32 { loop { break; } } ``` **After this PR**: ```rust fn foo() -> i32 { loop { break $0; } } ``` --- .../ide-completion/src/completions/expr.rs | 17 +++++--- .../ide-completion/src/completions/postfix.rs | 2 +- .../ide-completion/src/completions/record.rs | 5 +-- .../crates/ide-completion/src/context.rs | 6 +-- .../ide-completion/src/context/analysis.rs | 28 +++++++------ .../ide-completion/src/tests/expression.rs | 39 +++++++++++++++++++ 6 files changed, 72 insertions(+), 25 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 4c79357941516..5cae7bd89fff6 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 @@ -9,7 +9,7 @@ use syntax::ast; use crate::{ CompletionContext, Completions, completions::record::add_default_update, - context::{BreakableKind, PathCompletionCtx, PathExprCtx, Qualified}, + context::{PathCompletionCtx, PathExprCtx, Qualified}, }; struct PathCallback<'a, F> { @@ -57,7 +57,6 @@ pub(crate) fn complete_expr_path( let &PathExprCtx { in_block_expr, - in_breakable, after_if_expr, before_else_kw, in_condition, @@ -68,6 +67,7 @@ pub(crate) fn complete_expr_path( after_amp, ref is_func_update, ref innermost_ret_ty, + ref innermost_breakable_ty, ref impl_, in_match_guard, .. @@ -405,14 +405,21 @@ pub(crate) fn complete_expr_path( add_keyword("mut", "mut "); } - if in_breakable != BreakableKind::None { + if let Some(loop_ty) = innermost_breakable_ty { if in_block_expr { add_keyword("continue", "continue;"); - add_keyword("break", "break;"); } else { add_keyword("continue", "continue"); - add_keyword("break", "break"); } + add_keyword( + "break", + match (loop_ty.is_unit(), in_block_expr) { + (true, true) => "break;", + (true, false) => "break", + (false, true) => "break $0;", + (false, false) => "break $0", + }, + ); } if let Some(ret_ty) = innermost_ret_ty { 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 51acdb7802b3f..73cbe3f0aaab9 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 @@ -291,7 +291,7 @@ pub(crate) fn complete_postfix( ) .add_to(acc, ctx.db); - if let BreakableKind::Block | BreakableKind::Loop = expr_ctx.in_breakable { + if let Some(BreakableKind::Block | BreakableKind::Loop) = expr_ctx.in_breakable { postfix_snippet( "break", "break expr", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 2f5abd18934fc..28b324d61afa5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -135,10 +135,7 @@ fn complete_fields( receiver: None, receiver_ty: None, kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, - ctx: DotAccessExprCtx { - in_block_expr: false, - in_breakable: crate::context::BreakableKind::None, - }, + ctx: DotAccessExprCtx { in_block_expr: false, in_breakable: None }, }, None, field, 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 d9b0d3296a964..4032329ac658e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -143,7 +143,7 @@ pub(crate) struct AttrCtx { #[derive(Debug, PartialEq, Eq)] pub(crate) struct PathExprCtx<'db> { pub(crate) in_block_expr: bool, - pub(crate) in_breakable: BreakableKind, + pub(crate) in_breakable: Option, pub(crate) after_if_expr: bool, pub(crate) before_else_kw: bool, /// Whether this expression is the direct condition of an if or while expression @@ -157,6 +157,7 @@ pub(crate) struct PathExprCtx<'db> { pub(crate) is_func_update: Option, pub(crate) self_param: Option, pub(crate) innermost_ret_ty: Option>, + pub(crate) innermost_breakable_ty: Option>, pub(crate) impl_: Option, /// Whether this expression occurs in match arm guard position: before the /// fat arrow token @@ -412,12 +413,11 @@ pub(crate) enum DotAccessKind { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct DotAccessExprCtx { pub(crate) in_block_expr: bool, - pub(crate) in_breakable: BreakableKind, + pub(crate) in_breakable: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum BreakableKind { - None, Loop, For, While, 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 440ac9ad07431..873eceff5f5fa 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 @@ -926,7 +926,7 @@ fn classify_name_ref<'db>( receiver_ty, kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -941,7 +941,7 @@ fn classify_name_ref<'db>( receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), kind: DotAccessKind::Method { has_parens }, receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) } + ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 } }); return Some(make_res(kind)); }, @@ -1229,7 +1229,7 @@ fn classify_name_ref<'db>( let make_path_kind_expr = |expr: ast::Expr| { let it = expr.syntax(); let in_block_expr = is_in_block(it); - let in_loop_body = is_in_breakable(it); + let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip(); let after_if_expr = after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); @@ -1283,6 +1283,11 @@ fn classify_name_ref<'db>( None => (None, None), } }; + let innermost_breakable_ty = innermost_breakable + .and_then(ast::Expr::cast) + .and_then(|expr| find_node_in_file_compensated(sema, original_file, &expr)) + .and_then(|expr| sema.type_of_expr(&expr)) + .map(|ty| if ty.original.is_never() { ty.adjusted() } else { ty.original() }); 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(); @@ -1316,6 +1321,7 @@ fn classify_name_ref<'db>( after_amp, is_func_update, innermost_ret_ty, + innermost_breakable_ty, self_param, in_value, incomplete_let, @@ -1865,24 +1871,22 @@ fn is_in_token_of_for_loop(path: &ast::Path) -> bool { .unwrap_or(false) } -fn is_in_breakable(node: &SyntaxNode) -> BreakableKind { +fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> { node.ancestors() .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR) .find_map(|it| { let (breakable, loop_body) = match_ast! { match it { - ast::ForExpr(it) => (BreakableKind::For, it.loop_body()), - ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()), - ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()), - ast::BlockExpr(it) => return it.label().map(|_| BreakableKind::Block), + ast::ForExpr(it) => (BreakableKind::For, it.loop_body()?), + ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()?), + ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()?), + ast::BlockExpr(it) => return it.label().map(|_| (BreakableKind::Block, it.syntax().clone())), _ => return None, } }; - loop_body - .filter(|it| it.syntax().text_range().contains_range(node.text_range())) - .map(|_| breakable) + loop_body.syntax().text_range().contains_range(node.text_range()) + .then_some((breakable, it)) }) - .unwrap_or(BreakableKind::None) } fn is_in_block(node: &SyntaxNode) -> bool { 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 98a6f95f334a6..5363a68af7237 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 @@ -1090,6 +1090,45 @@ fn return_value_no_block() { ); } +#[test] +fn break_unit_block() { + check_edit("break", r#"fn f() { loop { break; $0 } }"#, r#"fn f() { loop { break; break; } }"#); + check_edit("break", r#"fn f() { loop { $0 } }"#, r#"fn f() { loop { break; } }"#); +} + +#[test] +fn break_unit_no_block() { + check_edit( + "break", + r#"fn f() { loop { break; match () { () => $0 } } }"#, + r#"fn f() { loop { break; match () { () => break } } }"#, + ); + + check_edit( + "break", + r#"fn f() { loop { match () { () => $0 } } }"#, + r#"fn f() { loop { match () { () => break } } }"#, + ); +} + +#[test] +fn break_value_block() { + check_edit( + "break", + r#"fn f() -> i32 { loop { $0 } }"#, + r#"fn f() -> i32 { loop { break $0; } }"#, + ); +} + +#[test] +fn break_value_no_block() { + check_edit( + "break", + r#"fn f() -> i32 { loop { match () { () => $0 } } }"#, + r#"fn f() -> i32 { loop { match () { () => break $0 } } }"#, + ); +} + #[test] fn else_completion_after_if() { check( From 78bbc598b86414b927cff71bb4d9cf6998ac1cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 14 Oct 2025 13:27:01 +0300 Subject: [PATCH 56/59] Prepare for merging from rust-lang/rust This updates the rust-version file to fb24b04b096a980bffd80154f6aba22fd07cb3d9. --- 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 5e2e5d7d335d0..c9529fde2363e 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -3369e82c6bc03c5cdb66f730dba6f738b74c8e1d +fb24b04b096a980bffd80154f6aba22fd07cb3d9 From cd101ef80ec9502906e7fa475d12861be95b8915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 14 Oct 2025 13:34:47 +0300 Subject: [PATCH 57/59] Bump rustc crates a little --- src/tools/rust-analyzer/Cargo.lock | 44 +++++++++++++++--------------- src/tools/rust-analyzer/Cargo.toml | 16 +++++------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 6625403572b0b..37cadeed9f129 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1842,9 +1842,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597bb303548ddcca3a2eb05af254508aaf39cf334d4350bb5da51de1eb728859" +checksum = "26dbfcf847c69bcb0c8adcebefdd35ee28ff16b1cb4fa8784f65aa6170d9dd91" dependencies = [ "bitflags 2.9.4", "ra-ap-rustc_hashes", @@ -1854,24 +1854,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78982b4e4432ee4b938e47bb5c8f1a5a5a88c27c782f193aefcc12a3250bd2e2" +checksum = "cf0ce9892d2004018c2d9a3b533031c67d5923b6b7abe67e06e384b56a41254f" [[package]] name = "ra-ap-rustc_hashes" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7f33a422f724cc1ab43972cdd76a556b17fc256f301d23be620adfc8351df7" +checksum = "be2f85649737b83c679bcafa69694a0a0dcd69eaece83443734655ebbb422a57" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6006023c8be18c3ac225d69c1b42f55b3f597f3db03fb40764b4cf1454fd13" +checksum = "3c07f764f87b3c8b5b777f25f04ae9aae11aa9496d470c64eff0ea2e8b137854" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1879,9 +1879,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9217c29f7fcc30d07ed13a62262144f665410ef1460202599ae924f9ae47ad78" +checksum = "a1ff78ecd915242249ad3ac4550ae078062d6ba49aeae683208cc5f9fb77891a" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1890,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573ad4f5da620e8ba1849d8862866abd7bc765c3d81cb2488c3ecbef33ce2c69" +checksum = "e308242408d1be72be340ba6471cd648be11d95b35bfa4a36ab43b86ab8ca180" dependencies = [ "memchr", "unicode-properties", @@ -1901,9 +1901,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d42b095b99e988aeb94622ae62ebda4b7de55d7d98846eec352b8a5a2b8a858" +checksum = "c5c4518700f9f2eb723235ecd5bb2e1177d440ad366a34b81fbabcefcd9dae2d" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1914,9 +1914,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21b4e95cb45f840c172493c05f5b9471cf44adb2eccf95d76a0d76e88007870" +checksum = "91256e24fcafc1124831a658906d200db0afecac5d037b3ae3d17795c5cbc25c" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1924,9 +1924,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aeacef1248066f7b67e7296ef135eeab6446d5d2a5c7f02b8d7b747b41e39b" +checksum = "59e2e227c6297bfd7966bbe1a36c1d28de14acc14cbb78f21ab79c33505459f9" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1937,9 +1937,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e35ee9e052406035016b8e6d54ca202bc39ccba1702780b33b2d5fb10d1da8" +checksum = "31b221f4055328870cbe52a487f7dfa3c801f99756c68c3bc33ee1c352db9be3" dependencies = [ "arrayvec", "bitflags 2.9.4", @@ -1957,9 +1957,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.132.0" +version = "0.134.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b934c956b0c88df8176803416b69d85d2c392a69c8aa794a4c338f22c527d38" +checksum = "f2654d56a28339d6c445762b78cba400d5e528808ede1c779aeae23b4c6f17ff" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 6702bfed872c9..f94fd37e52a76 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -88,14 +88,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.132", default-features = false } -ra-ap-rustc_parse_format = { version = "0.132", default-features = false } -ra-ap-rustc_index = { version = "0.132", default-features = false } -ra-ap-rustc_abi = { version = "0.132", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.132", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.132", default-features = false } -ra-ap-rustc_type_ir = { version = "0.132", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.132", default-features = false } +ra-ap-rustc_lexer = { version = "0.133", default-features = false } +ra-ap-rustc_parse_format = { version = "0.133", default-features = false } +ra-ap-rustc_index = { version = "0.133", default-features = false } +ra-ap-rustc_abi = { version = "0.133", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.133", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.133", default-features = false } +ra-ap-rustc_type_ir = { version = "0.133", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.133", default-features = false } # local crates that aren't published to crates.io. These should not have versions. From 0634661796c224325aa0c2e7cc2e9488a920ee0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 14 Oct 2025 14:34:14 +0300 Subject: [PATCH 58/59] Fix lockfile --- src/tools/rust-analyzer/Cargo.lock | 44 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 37cadeed9f129..267b516210958 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1842,9 +1842,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26dbfcf847c69bcb0c8adcebefdd35ee28ff16b1cb4fa8784f65aa6170d9dd91" +checksum = "c063a7fef3c49d03837ee9a5d988aad83630c3460b03b32355c279d3fafa7d07" dependencies = [ "bitflags 2.9.4", "ra-ap-rustc_hashes", @@ -1854,24 +1854,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf0ce9892d2004018c2d9a3b533031c67d5923b6b7abe67e06e384b56a41254f" +checksum = "a210dbd77e794b33ff17d2d15750dee44eeabd1330685d69a6bad272d515892a" [[package]] name = "ra-ap-rustc_hashes" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2f85649737b83c679bcafa69694a0a0dcd69eaece83443734655ebbb422a57" +checksum = "dea031ea45bb92cd346ed222b35c812e355f304183096ee91bb437b3813c6348" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c07f764f87b3c8b5b777f25f04ae9aae11aa9496d470c64eff0ea2e8b137854" +checksum = "db0114f842b20cba9beb2d9002ca31ae706b47f28ba2d6a49cbf9fd65fa72b9d" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1879,9 +1879,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ff78ecd915242249ad3ac4550ae078062d6ba49aeae683208cc5f9fb77891a" +checksum = "bc738a5bb06fb3893725fbeb3640ff1822bb2aae3f416c4a49f0a706ba89d1cc" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1890,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e308242408d1be72be340ba6471cd648be11d95b35bfa4a36ab43b86ab8ca180" +checksum = "31c35b3d812cfc101d3f534640c13f24c0ec50ee2249685e4c20b2868609c9ee" dependencies = [ "memchr", "unicode-properties", @@ -1901,9 +1901,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c4518700f9f2eb723235ecd5bb2e1177d440ad366a34b81fbabcefcd9dae2d" +checksum = "e7b0fa6fb8e0717ebd0836f8de4a6efc954fca1a8652980fd2584dbe448c7d95" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1914,9 +1914,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91256e24fcafc1124831a658906d200db0afecac5d037b3ae3d17795c5cbc25c" +checksum = "33d01bad23470cc749ef607476890aabcc8993ca3ef87d4241d0f6a08c6f9402" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1924,9 +1924,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e2e227c6297bfd7966bbe1a36c1d28de14acc14cbb78f21ab79c33505459f9" +checksum = "8a181cf7943dc16e888046584d6172be95818811b25d695dbacbb4dd71973cc3" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1937,9 +1937,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b221f4055328870cbe52a487f7dfa3c801f99756c68c3bc33ee1c352db9be3" +checksum = "87c99f33be18d9e50cefef5442822da1f0b416e9a17a483879a9704e08a6a6e6" dependencies = [ "arrayvec", "bitflags 2.9.4", @@ -1957,9 +1957,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.134.0" +version = "0.133.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2654d56a28339d6c445762b78cba400d5e528808ede1c779aeae23b4c6f17ff" +checksum = "77b162d65e058abfc058e6b67ae68156cc282fbd78da148c1a7ec77b4230661e" dependencies = [ "proc-macro2", "quote", From 7d93599fb13060cd1a57d53133b5962106849a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 14 Oct 2025 16:15:59 +0300 Subject: [PATCH 59/59] Add new_zeroed_alloc to rust-analyzer ALLOW_FEATURES --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 819e903020c8e..79df9d3a49da2 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1021,7 +1021,7 @@ impl RustAnalyzer { } impl RustAnalyzer { - pub const ALLOW_FEATURES: &'static str = "rustc_private,proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink,proc_macro_def_site"; + pub const ALLOW_FEATURES: &'static str = "rustc_private,proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink,proc_macro_def_site,new_zeroed_alloc"; } impl Step for RustAnalyzer {