From 70177c220497603eb2d8568727d416e26ec81be3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 18 Aug 2026 15:05:28 +0300 Subject: [PATCH] Break hir-ty up, step 1 According to the plan outlined [in Zulip](https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Breaking.20up.20hir-ty/near/617085080). This first step extracts the `hir-ide` crate, containing extra diagnostics, display, and tests. Tests must be in the leaf crate because they need access to the full database (some can go with a dummy impl for some methods, but it'll be more complicated than just moving them here). We had to make some compromises; pretty-printing MIR and MIR errors requires display, so we need it to be in `hir-ide`, but then it can't be an inherent method, so we made it an extension trait and also made a proc macro to make that easier (copied from rustc). --- Cargo.lock | 42 +- Cargo.toml | 1 + crates/hir-def/src/lib.rs | 1 + crates/{hir-ty => hir-def}/src/upvars.rs | 106 ++-- crates/hir-ide/Cargo.toml | 56 ++ crates/{hir-ty => hir-ide}/src/diagnostics.rs | 0 .../src/diagnostics/decl_check.rs | 0 .../src/diagnostics/decl_check/case_conv.rs | 0 .../src/diagnostics/expr.rs | 0 .../src/diagnostics/match_check.rs | 3 +- .../diagnostics/match_check/pat_analysis.rs | 0 .../src/diagnostics/match_check/pat_util.rs | 0 .../src/diagnostics/unsafe_check.rs | 0 crates/{hir-ty => hir-ide}/src/display.rs | 5 +- crates/hir-ide/src/impl_db_macro.rs | 34 + crates/hir-ide/src/lib.rs | 44 ++ .../pretty.rs => hir-ide/src/mir_pretty.rs} | 19 +- crates/hir-ide/src/mir_pretty/errors.rs | 271 ++++++++ crates/{hir-ty => hir-ide}/src/test_db.rs | 2 + crates/{hir-ty => hir-ide}/src/tests.rs | 9 +- crates/hir-ide/src/tests/builtin_derives.rs | 266 ++++++++ .../src/tests/closure_captures.rs | 0 .../{hir-ty => hir-ide}/src/tests/coercion.rs | 0 .../src/tests/consteval.rs} | 7 +- .../src/tests/consteval}/intrinsics.rs | 0 .../src/tests/diagnostics.rs | 0 .../src/tests/display_source_code.rs | 0 .../src/tests/dyn_compatibility.rs} | 12 +- .../src/tests/incremental.rs | 0 .../tests.rs => hir-ide/src/tests/layout.rs} | 4 +- .../src/tests/layout}/closure.rs | 0 .../{hir-ty => hir-ide}/src/tests/macros.rs | 0 .../src/tests/method_resolution.rs | 0 crates/hir-ide/src/tests/mir.rs | 2 + .../src/tests/mir/eval.rs} | 3 +- .../src/tests/mir/lower.rs} | 0 .../src/tests/never_type.rs | 0 .../src/tests/opaque_types.rs | 0 .../{hir-ty => hir-ide}/src/tests/patterns.rs | 0 .../src/tests/regression.rs | 0 .../src/tests/regression/new_solver.rs | 0 .../{hir-ty => hir-ide}/src/tests/simple.rs | 0 .../src/tests/trait_aliases.rs | 0 .../{hir-ty => hir-ide}/src/tests/traits.rs | 0 crates/hir-ide/src/tests/variance.rs | 576 +++++++++++++++++ crates/hir-ty/Cargo.toml | 13 +- crates/hir-ty/src/builtin_derive.rs | 271 -------- crates/hir-ty/src/consteval.rs | 23 - crates/hir-ty/src/db.rs | 8 +- crates/hir-ty/src/dyn_compatibility.rs | 3 - crates/hir-ty/src/generics.rs | 20 +- crates/hir-ty/src/infer.rs | 20 +- crates/hir-ty/src/infer/closure/analysis.rs | 4 +- .../closure/analysis/expr_use_visitor.rs | 2 +- crates/hir-ty/src/infer/coerce.rs | 2 +- crates/hir-ty/src/inhabitedness.rs | 4 +- crates/hir-ty/src/layout.rs | 3 - crates/hir-ty/src/lib.rs | 38 +- crates/hir-ty/src/mir.rs | 5 +- crates/hir-ty/src/mir/eval.rs | 152 +---- crates/hir-ty/src/mir/eval/shim.rs | 17 +- crates/hir-ty/src/mir/lower.rs | 151 +---- .../hir-ty/src/mir/lower/pattern_matching.rs | 11 +- crates/hir-ty/src/next_solver/interner.rs | 2 +- crates/hir-ty/src/utils.rs | 4 +- crates/hir-ty/src/variance.rs | 580 ------------------ crates/hir/Cargo.toml | 2 +- crates/hir/src/attrs.rs | 10 +- crates/hir/src/db.rs | 2 +- crates/hir/src/diagnostics.rs | 16 +- crates/hir/src/display.rs | 4 +- crates/hir/src/from_id.rs | 4 +- crates/hir/src/has_source.rs | 2 +- crates/hir/src/lib.rs | 167 ++--- crates/hir/src/semantics.rs | 24 +- crates/hir/src/source_analyzer.rs | 20 +- crates/hir/src/symbols.rs | 2 +- crates/hir/src/term_search.rs | 2 +- crates/hir/src/term_search/expr.rs | 2 +- crates/hir/src/term_search/tactics.rs | 2 +- crates/ide-db/src/lib.rs | 2 + crates/ide/src/interpret.rs | 2 +- crates/macros/src/extension.rs | 158 +++++ crates/macros/src/lib.rs | 22 + 84 files changed, 1754 insertions(+), 1485 deletions(-) rename crates/{hir-ty => hir-def}/src/upvars.rs (81%) create mode 100644 crates/hir-ide/Cargo.toml rename crates/{hir-ty => hir-ide}/src/diagnostics.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/decl_check.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/decl_check/case_conv.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/expr.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/match_check.rs (99%) rename crates/{hir-ty => hir-ide}/src/diagnostics/match_check/pat_analysis.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/match_check/pat_util.rs (100%) rename crates/{hir-ty => hir-ide}/src/diagnostics/unsafe_check.rs (100%) rename crates/{hir-ty => hir-ide}/src/display.rs (99%) create mode 100644 crates/hir-ide/src/impl_db_macro.rs create mode 100644 crates/hir-ide/src/lib.rs rename crates/{hir-ty/src/mir/pretty.rs => hir-ide/src/mir_pretty.rs} (97%) create mode 100644 crates/hir-ide/src/mir_pretty/errors.rs rename crates/{hir-ty => hir-ide}/src/test_db.rs (99%) rename crates/{hir-ty => hir-ide}/src/tests.rs (99%) create mode 100644 crates/hir-ide/src/tests/builtin_derives.rs rename crates/{hir-ty => hir-ide}/src/tests/closure_captures.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/coercion.rs (100%) rename crates/{hir-ty/src/consteval/tests.rs => hir-ide/src/tests/consteval.rs} (99%) rename crates/{hir-ty/src/consteval/tests => hir-ide/src/tests/consteval}/intrinsics.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/diagnostics.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/display_source_code.rs (100%) rename crates/{hir-ty/src/dyn_compatibility/tests.rs => hir-ide/src/tests/dyn_compatibility.rs} (97%) rename crates/{hir-ty => hir-ide}/src/tests/incremental.rs (100%) rename crates/{hir-ty/src/layout/tests.rs => hir-ide/src/tests/layout.rs} (99%) rename crates/{hir-ty/src/layout/tests => hir-ide/src/tests/layout}/closure.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/macros.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/method_resolution.rs (100%) create mode 100644 crates/hir-ide/src/tests/mir.rs rename crates/{hir-ty/src/mir/eval/tests.rs => hir-ide/src/tests/mir/eval.rs} (99%) rename crates/{hir-ty/src/mir/lower/tests.rs => hir-ide/src/tests/mir/lower.rs} (100%) rename crates/{hir-ty => hir-ide}/src/tests/never_type.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/opaque_types.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/patterns.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/regression.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/regression/new_solver.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/simple.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/trait_aliases.rs (100%) rename crates/{hir-ty => hir-ide}/src/tests/traits.rs (100%) create mode 100644 crates/hir-ide/src/tests/variance.rs create mode 100644 crates/macros/src/extension.rs diff --git a/Cargo.lock b/Cargo.lock index 5835ed9e552e..99dccc9c2e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -817,7 +817,7 @@ dependencies = [ "expect-test", "hir-def", "hir-expand", - "hir-ty", + "hir-ide", "intern", "itertools 0.15.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -901,6 +901,40 @@ dependencies = [ "tt", ] +[[package]] +name = "hir-ide" +version = "0.0.0" +dependencies = [ + "base-db", + "cov-mark", + "either", + "expect-test", + "hir-def", + "hir-expand", + "hir-ty", + "intern", + "itertools 0.15.0", + "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "macros", + "project-model", + "ra-ap-rustc_abi", + "ra-ap-rustc_ast_ir", + "ra-ap-rustc_pattern_analysis", + "ra-ap-rustc_type_ir", + "rustc-hash 2.1.2", + "rustc_apfloat", + "salsa", + "smallvec", + "span", + "stdx", + "syntax", + "test-fixture", + "test-utils", + "tracing", + "triomphe", + "typed-arena", +] + [[package]] name = "hir-ty" version = "0.0.0" @@ -911,7 +945,6 @@ dependencies = [ "cov-mark", "either", "ena", - "expect-test", "hir-def", "hir-expand", "indexmap", @@ -921,12 +954,10 @@ dependencies = [ "macros", "oorandom", "petgraph", - "project-model", "ra-ap-rustc_abi", "ra-ap-rustc_ast_ir", "ra-ap-rustc_index", "ra-ap-rustc_next_trait_solver", - "ra-ap-rustc_pattern_analysis", "ra-ap-rustc_type_ir", "rustc-hash 2.1.2", "rustc_apfloat", @@ -937,14 +968,11 @@ dependencies = [ "span", "stdx", "syntax", - "test-fixture", - "test-utils", "thin-vec", "tracing", "tracing-subscriber", "tracing-tree", "triomphe", - "typed-arena", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d77e89df45e4..09194526cda4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ hir = { path = "./crates/hir", version = "0.0.0" } hir-def = { path = "./crates/hir-def", version = "0.0.0" } hir-expand = { path = "./crates/hir-expand", version = "0.0.0" } hir-ty = { path = "./crates/hir-ty", version = "0.0.0" } +hir-ide = { path = "./crates/hir-ide", version = "0.0.0" } ide = { path = "./crates/ide", version = "0.0.0" } ide-assists = { path = "./crates/ide-assists", version = "0.0.0" } ide-completion = { path = "./crates/ide-completion", version = "0.0.0" } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 0712a025b49c..99b2d116354d 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -36,6 +36,7 @@ pub mod unstable_features; pub mod expr_store; pub mod hir; pub mod resolver; +pub mod upvars; pub mod nameres; diff --git a/crates/hir-ty/src/upvars.rs b/crates/hir-def/src/upvars.rs similarity index 81% rename from crates/hir-ty/src/upvars.rs rename to crates/hir-def/src/upvars.rs index ee5854865a44..d1b039c230de 100644 --- a/crates/hir-ty/src/upvars.rs +++ b/crates/hir-def/src/upvars.rs @@ -1,16 +1,16 @@ //! A simple query to collect tall locals (upvars) a closure use. -use hir_def::{ +use base_db::SourceDatabase; +use hir_expand::mod_path::PathKind; +use rustc_hash::{FxHashMap, FxHashSet}; + +use crate::{ DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, expr_store::{ExpressionStore, StoreVisitor, StoreVisitorExt, path::Path}, hir::{BindingId, Expr, ExprId, PatId}, resolver::{HasResolver, Resolver, ValueNs}, type_ref::TypeRefId, }; -use hir_expand::mod_path::PathKind; -use rustc_hash::{FxHashMap, FxHashSet}; - -use crate::db::HirDatabase; #[derive(Debug, Clone, PartialEq, Eq, Hash)] // Kept sorted. @@ -72,7 +72,7 @@ impl UpvarsRef<'_> { /// Returns a map from `Expr::Closure` to its upvars. pub fn upvars_mentioned( - db: &dyn HirDatabase, + db: &dyn SourceDatabase, owner: ExpressionStoreOwnerId, ) -> Option<&FxHashMap> { return match owner { @@ -83,7 +83,7 @@ pub fn upvars_mentioned( #[salsa::tracked(returns(as_deref))] pub fn signature_upvars_mentioned( - db: &dyn HirDatabase, + db: &dyn SourceDatabase, owner: GenericDefId, ) -> Option>> { upvars_mentioned_impl(db, owner.into()) @@ -91,7 +91,7 @@ pub fn upvars_mentioned( #[salsa::tracked(returns(as_deref))] pub fn body_upvars_mentioned( - db: &dyn HirDatabase, + db: &dyn SourceDatabase, owner: DefWithBodyId, ) -> Option>> { upvars_mentioned_impl(db, owner.into()) @@ -99,7 +99,7 @@ pub fn upvars_mentioned( #[salsa::tracked(returns(as_deref))] pub fn variant_fields_upvars_mentioned( - db: &dyn HirDatabase, + db: &dyn SourceDatabase, owner: VariantId, ) -> Option>> { upvars_mentioned_impl(db, owner.into()) @@ -107,7 +107,7 @@ pub fn upvars_mentioned( } pub fn upvars_mentioned_impl( - db: &dyn HirDatabase, + db: &dyn SourceDatabase, owner: ExpressionStoreOwnerId, ) -> Option>> { let store = ExpressionStore::of(db, owner); @@ -132,7 +132,7 @@ pub fn upvars_mentioned_impl( } struct UpvarsMentionedVisitor<'db> { - db: &'db dyn HirDatabase, + db: &'db dyn SourceDatabase, resolver: Resolver<'db>, owner: ExpressionStoreOwnerId, store: &'db ExpressionStore, @@ -226,58 +226,54 @@ impl StoreVisitor for UpvarsMentionedVisitor<'_> { #[cfg(test)] mod tests { use expect_test::{Expect, expect}; - use hir_def::{ - AssocItemId, DefWithBodyId, ModuleDefId, expr_store::Body, nameres::crate_def_map, - }; use itertools::Itertools; use span::Edition; use test_fixture::WithFixture; - use crate::{test_db::TestDB, upvars::upvars_mentioned}; + use crate::{ + AssocItemId, DefWithBodyId, ModuleDefId, expr_store::Body, nameres::crate_def_map, + test_db::TestDB, upvars::upvars_mentioned, + }; #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { let db = TestDB::with_files(ra_fixture); - crate::attach_db(&db, || { - let def_map = crate_def_map(&db, db.test_crate()); - let func = def_map - .modules() - .flat_map(|(_, module)| module.scope.declarations()) - .filter_map(|decl| match decl { - ModuleDefId::FunctionId(func) => Some(func), - _ => None, - }) - .chain(def_map.modules().flat_map(|(_, module)| { - module.scope.impls().flat_map(|impl_| &*impl_.impl_items(&db).items).filter_map( - |&(_, item)| match item { - AssocItemId::FunctionId(it) => Some(it), - _ => None, - }, - ) - })) - .exactly_one() - .unwrap_or_else(|_| panic!("expected one function")); - let (body, source_map) = Body::with_source_map(&db, func.into()); - let Some(upvars) = upvars_mentioned(&db, DefWithBodyId::from(func).into()) else { - expectation.assert_eq(""); - return; - }; - let mut closures = Vec::new(); - for (&closure, upvars) in upvars { - let closure_range = source_map.expr_syntax(closure).unwrap().value.text_range(); - let upvars = upvars - .iter() - .map(|local| body[local].name.display(&db, Edition::CURRENT)) - .join(", "); - closures.push((closure_range, upvars)); - } - closures.sort_unstable_by_key(|(range, _)| (range.start(), range.end())); - let closures = closures - .into_iter() - .map(|(range, upvars)| format!("{range:?}: {upvars}")) - .join("\n"); - expectation.assert_eq(&closures); - }); + let def_map = crate_def_map(&db, db.test_crate()); + let func = def_map + .modules() + .flat_map(|(_, module)| module.scope.declarations()) + .filter_map(|decl| match decl { + ModuleDefId::FunctionId(func) => Some(func), + _ => None, + }) + .chain(def_map.modules().flat_map(|(_, module)| { + module.scope.impls().flat_map(|impl_| &*impl_.impl_items(&db).items).filter_map( + |&(_, item)| match item { + AssocItemId::FunctionId(it) => Some(it), + _ => None, + }, + ) + })) + .exactly_one() + .unwrap_or_else(|_| panic!("expected one function")); + let (body, source_map) = Body::with_source_map(&db, func.into()); + let Some(upvars) = upvars_mentioned(&db, DefWithBodyId::from(func).into()) else { + expectation.assert_eq(""); + return; + }; + let mut closures = Vec::new(); + for (&closure, upvars) in upvars { + let closure_range = source_map.expr_syntax(closure).unwrap().value.text_range(); + let upvars = upvars + .iter() + .map(|local| body[local].name.display(&db, Edition::CURRENT)) + .join(", "); + closures.push((closure_range, upvars)); + } + closures.sort_unstable_by_key(|(range, _)| (range.start(), range.end())); + let closures = + closures.into_iter().map(|(range, upvars)| format!("{range:?}: {upvars}")).join("\n"); + expectation.assert_eq(&closures); } #[test] diff --git a/crates/hir-ide/Cargo.toml b/crates/hir-ide/Cargo.toml new file mode 100644 index 000000000000..e1754a991418 --- /dev/null +++ b/crates/hir-ide/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "hir-ide" +version = "0.0.0" +repository.workspace = true +description = "The final bits of analysis; Display, extra diagnostics, and tests." + +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true + +[lib] +doctest = false + +[dependencies] +cov-mark = "2.0.0" +itertools.workspace = true +smallvec.workspace = true +either.workspace = true +tracing = { workspace = true, features = ["attributes"] } +rustc-hash.workspace = true +la-arena.workspace = true +triomphe.workspace = true +typed-arena = "2.0.2" +rustc_apfloat = "0.2.3" +salsa.workspace = true + +ra-ap-rustc_abi.workspace = true +ra-ap-rustc_pattern_analysis.workspace = true +ra-ap-rustc_ast_ir.workspace = true +ra-ap-rustc_type_ir.workspace = true + +# local deps +stdx.workspace = true +macros.workspace = true +intern.workspace = true +hir-def.workspace = true +hir-expand.workspace = true +base-db.workspace = true +syntax.workspace = true +span.workspace = true +hir-ty.workspace = true + +[dev-dependencies] +expect-test = "1.5.1" +project-model.workspace = true + +# local deps +test-utils.workspace = true +test-fixture.workspace = true + +[features] +in-rust-tree = ["hir-expand/in-rust-tree"] + +[lints] +workspace = true diff --git a/crates/hir-ty/src/diagnostics.rs b/crates/hir-ide/src/diagnostics.rs similarity index 100% rename from crates/hir-ty/src/diagnostics.rs rename to crates/hir-ide/src/diagnostics.rs diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ide/src/diagnostics/decl_check.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/decl_check.rs rename to crates/hir-ide/src/diagnostics/decl_check.rs diff --git a/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir-ide/src/diagnostics/decl_check/case_conv.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/decl_check/case_conv.rs rename to crates/hir-ide/src/diagnostics/decl_check/case_conv.rs diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ide/src/diagnostics/expr.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/expr.rs rename to crates/hir-ide/src/diagnostics/expr.rs diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ide/src/diagnostics/match_check.rs similarity index 99% rename from crates/hir-ty/src/diagnostics/match_check.rs rename to crates/hir-ide/src/diagnostics/match_check.rs index 613912e0901b..1b74e4d24c98 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ide/src/diagnostics/match_check.rs @@ -22,10 +22,9 @@ use span::Edition; use stdx::{always, never, variance::PhantomCovariantLifetime}; use crate::{ - ByRef, InferenceResult, + BindingMode, ByRef, InferenceResult, db::HirDatabase, display::{HirDisplay, HirDisplayError, HirFormatter}, - infer::BindingMode, next_solver::{GenericArgs, Mutability, Ty, TyKind}, }; diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ide/src/diagnostics/match_check/pat_analysis.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs rename to crates/hir-ide/src/diagnostics/match_check/pat_analysis.rs diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_util.rs b/crates/hir-ide/src/diagnostics/match_check/pat_util.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/match_check/pat_util.rs rename to crates/hir-ide/src/diagnostics/match_check/pat_util.rs diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ide/src/diagnostics/unsafe_check.rs similarity index 100% rename from crates/hir-ty/src/diagnostics/unsafe_check.rs rename to crates/hir-ide/src/diagnostics/unsafe_check.rs diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ide/src/display.rs similarity index 99% rename from crates/hir-ty/src/display.rs rename to crates/hir-ide/src/display.rs index dfa088830543..7019a188e40c 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ide/src/display.rs @@ -10,7 +10,7 @@ use std::{ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, + CallableDefId, ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, TypeAliasId, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -51,11 +51,10 @@ use span::Edition; use stdx::never; use crate::{ - CallableDefId, FieldType, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval, + FieldType, GenericPredicates, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval, db::{GeneralConstId, HirDatabase}, generics::{ProvenanceSplit, generics}, layout::Layout, - lower::GenericPredicates, mir::{IsSigned, pad16}, next_solver::{ AliasTy, Allocation, Clause, ClauseKind, Const, ConstKind, DbInterner, diff --git a/crates/hir-ide/src/impl_db_macro.rs b/crates/hir-ide/src/impl_db_macro.rs new file mode 100644 index 000000000000..2fc1271fc5a1 --- /dev/null +++ b/crates/hir-ide/src/impl_db_macro.rs @@ -0,0 +1,34 @@ +//! A macro to implement `HirDatabase` for any (`Sized`) type implementing `SourceDatabase`. + +#[macro_export] +macro_rules! impl_hir_database { + ($ty:ty) => { + const _: () = { + use $crate::{ + __private::{hir_def::ModuleId, salsa}, + db::HirDatabase, + display::{DisplayTarget, HirDisplay}, + next_solver::Ty, + }; + + #[salsa::db] + impl $crate::db::HirDatabase for $ty { + fn as_dyn(&self) -> &dyn HirDatabase { + self + } + + fn type_name<'db>(&'db self, ty: Ty<'db>, module: ModuleId) -> String { + match ty.display_source_code(self, module, true) { + Ok(ty_name) => ty_name, + // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to + // render full paths. + Err(_) => { + let krate = module.krate(self); + ty.display(self, DisplayTarget::from_crate(self, krate)).to_string() + } + } + } + } + }; + }; +} diff --git a/crates/hir-ide/src/lib.rs b/crates/hir-ide/src/lib.rs new file mode 100644 index 000000000000..cad1c5b9e381 --- /dev/null +++ b/crates/hir-ide/src/lib.rs @@ -0,0 +1,44 @@ +//! The final bits of analysis; Display, extra diagnostics, and tests. + +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] +// It's useful to refer to code that is private in doc comments. +#![allow(rustdoc::private_intra_doc_links)] + +extern crate ra_ap_rustc_abi as rustc_abi; +extern crate ra_ap_rustc_ast_ir as rustc_ast_ir; +extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; +extern crate ra_ap_rustc_type_ir as rustc_type_ir; + +pub mod diagnostics; +pub mod display; +mod impl_db_macro; +pub mod mir_pretty; + +#[doc(hidden)] +pub mod __private { + pub use hir_def; + pub use salsa; +} + +#[cfg(test)] +mod test_db; +#[cfg(test)] +mod tests; + +use hir_def::ModuleId; +use hir_ty::{db::HirDatabase, next_solver::Const}; +use syntax::ast::{ConstArg, make}; + +pub use hir_ty::*; + +use crate::display::HirDisplay; + +pub fn known_const_to_ast<'db>( + konst: Const<'db>, + db: &'db dyn HirDatabase, + target_module: ModuleId, +) -> Option { + Some(make::expr_const_value( + &konst.display_source_code(db, target_module, true).unwrap_or_else(|_| "_".to_owned()), + )) +} diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ide/src/mir_pretty.rs similarity index 97% rename from crates/hir-ty/src/mir/pretty.rs rename to crates/hir-ide/src/mir_pretty.rs index 4a51b5113a43..2174d492c19d 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ide/src/mir_pretty.rs @@ -1,5 +1,7 @@ //! A pretty-printer for MIR. +mod errors; + use std::{ fmt::{Debug, Display, Write}, mem, @@ -13,20 +15,22 @@ use hir_def::{ }; use hir_expand::{Lookup, name::Name}; use la_arena::ArenaMap; +use macros::extension; use rustc_type_ir::inherent::IntoKind; use crate::{ InferBodyId, db::{HirDatabase, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, - mir::{PlaceElem, PlaceTy, ProjectionElem, StatementKind, TerminatorKind}, + mir::{ + AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, + OperandKind, Place, PlaceElem, PlaceTy, ProjectionElem, Rvalue, StatementKind, + TerminatorKind, UnOp, + }, next_solver::{DbInterner, TyKind, infer::DbInternerInferExt}, }; -use super::{ - AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, OperandKind, - Place, Rvalue, UnOp, -}; +pub use self::errors::{ConstEvalErrorPretty, MirEvalErrorPretty, MirLowerErrorPretty}; macro_rules! w { ($dst:expr, $($arg:tt)*) => { @@ -43,8 +47,9 @@ macro_rules! wln { }; } +#[extension(pub trait MirBodyPretty)] impl MirBody<'_> { - pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { + fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { let hir_body = ExpressionStore::of(db, self.owner.expression_store_owner(db)); let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); ctx.for_body(|this| match ctx.body.owner { @@ -88,7 +93,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 { + fn dbg(&self, 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 { diff --git a/crates/hir-ide/src/mir_pretty/errors.rs b/crates/hir-ide/src/mir_pretty/errors.rs new file mode 100644 index 000000000000..b22179ea0cb9 --- /dev/null +++ b/crates/hir-ide/src/mir_pretty/errors.rs @@ -0,0 +1,271 @@ +//! Pretty-printing MIR and consteval errors. + +use std::fmt::Write; + +use either::Either; +use hir_def::{ + GenericParamId, ItemContainerId, Lookup, + expr_store::{Body, ExpressionStore}, + hir::generics::GenericParams, + signatures::{FunctionSignature, TraitSignature}, +}; +use hir_expand::{InFile, name::Name}; +use hir_ty::{ + InferBodyId, + consteval::ConstEvalError, + db::HirDatabase, + mir::{MirEvalError, MirLowerError, MirSpan}, +}; +use macros::extension; +use span::{FileId, TextRange}; +use syntax::SyntaxNodePtr; + +use crate::display::{ClosureStyle, DisplayTarget, HirDisplay}; + +#[extension(pub trait MirLowerErrorPretty)] +impl MirLowerError<'_> { + fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + display_target: DisplayTarget, + ) -> std::result::Result<(), std::fmt::Error> { + match self { + MirLowerError::ConstEvalError(name, e) => { + writeln!(f, "In evaluating constant {name}")?; + match &**e { + ConstEvalError::MirLowerError(e) => { + e.pretty_print(f, db, span_formatter, display_target)? + } + ConstEvalError::MirEvalError(e) => { + e.pretty_print(f, db, span_formatter, display_target)? + } + } + } + MirLowerError::MissingFunctionDefinition(owner, it) => { + let owner = owner.expression_store_owner(db); + let store = ExpressionStore::of(db, owner); + writeln!( + f, + "Missing function definition for {}", + hir_def::expr_store::pretty::print_expr_hir( + db, + store, + owner, + *it, + display_target.edition + ) + )?; + } + MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?, + MirLowerError::GenericArgNotProvided(id, subst) => { + let param_name = match *id { + GenericParamId::TypeParamId(id) => { + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() + } + GenericParamId::ConstParamId(id) => { + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() + } + GenericParamId::LifetimeParamId(id) => { + Some(GenericParams::of(db, 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) + )?; + writeln!(f, "Provided args: [")?; + for g in subst.as_ref() { + write!(f, " {},", g.display(db, display_target))?; + } + writeln!(f, "]")?; + } + MirLowerError::LayoutError(_) + | MirLowerError::UnsizedTemporary(_) + | MirLowerError::IncompleteExpr + | MirLowerError::IncompletePattern + | MirLowerError::InaccessibleLocal + | MirLowerError::TraitFunctionDefinition(_, _) + | MirLowerError::UnresolvedName { .. } + | MirLowerError::RecordLiteralWithoutPath + | MirLowerError::UnresolvedMethod(_) + | MirLowerError::UnresolvedField + | MirLowerError::TypeError(_) + | MirLowerError::NotSupported(_) + | MirLowerError::ContinueWithoutLoop + | MirLowerError::BreakWithoutLoop + | MirLowerError::Loop + | MirLowerError::ImplementationError(_) + | MirLowerError::LangItemNotFound + | MirLowerError::MutatingRvalue + | MirLowerError::UnresolvedLabel + | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?, + } + Ok(()) + } +} + +#[extension(pub trait MirEvalErrorPretty)] +impl MirEvalError<'_> { + fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + display_target: DisplayTarget, + ) -> std::result::Result<(), std::fmt::Error> { + writeln!(f, "Mir eval error:")?; + let mut err = self; + while let MirEvalError::InFunction(e, stack) = err { + err = e; + for (func, span, def) in stack.iter().take(30).rev() { + match func { + Either::Left(func) => { + let function_name = FunctionSignature::of(db, *func); + writeln!( + f, + "In function {} ({:?})", + function_name.name.display(db, display_target.edition), + func + )?; + } + Either::Right(closure) => { + writeln!(f, "In {closure:?}")?; + } + } + let (source_map, self_param_syntax) = match *def { + InferBodyId::DefWithBodyId(def) => { + let body = &Body::with_source_map(db, def).1; + (&**body, body.self_param_syntax()) + } + InferBodyId::AnonConstId(def) => { + let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1; + (store, None) + } + }; + let span: InFile = match *span { + MirSpan::ExprId(e) => match source_map.expr_syntax(e) { + Ok(s) => s.map(|it| it.into()), + Err(_) => continue, + }, + MirSpan::PatId(p) => match source_map.pat_syntax(p) { + Ok(s) => s.map(|it| it.syntax_node_ptr()), + Err(_) => continue, + }, + MirSpan::BindingId(b) => { + match source_map + .patterns_for_binding(b) + .iter() + .find_map(|p| source_map.pat_syntax(*p).ok()) + { + Some(s) => s.map(|it| it.syntax_node_ptr()), + None => continue, + } + } + MirSpan::SelfParam => match self_param_syntax { + Some(s) => s.map(|it| it.syntax_node_ptr()), + None => continue, + }, + MirSpan::Unknown => continue, + }; + let file_id = span.file_id.original_file(db); + let text_range = span.value.text_range(); + writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?; + } + } + match err { + MirEvalError::InFunction(..) => unreachable!(), + MirEvalError::LayoutError(err, ty) => { + write!( + f, + "Layout for type `{}` is not available due {err:?}", + ty.as_ref() + .display(db, display_target) + .with_closure_style(ClosureStyle::ClosureWithId) + )?; + } + MirEvalError::MirLowerError(func, err) => { + let function_name = FunctionSignature::of(db, *func); + let self_ = match func.lookup(db).container { + ItemContainerId::ImplId(impl_id) => Some({ + db.impl_self_ty(impl_id) + .instantiate_identity() + .skip_norm_wip() + .display(db, display_target) + .to_string() + }), + ItemContainerId::TraitId(it) => Some( + TraitSignature::of(db, it) + .name + .display(db, display_target.edition) + .to_string(), + ), + _ => None, + }; + writeln!( + f, + "MIR lowering for function `{}{}{}` ({:?}) failed due:", + self_.as_deref().unwrap_or_default(), + if self_.is_some() { "::" } else { "" }, + function_name.name.display(db, display_target.edition), + func + )?; + err.pretty_print(f, db, span_formatter, display_target)?; + } + MirEvalError::ConstEvalError(name, err) => { + MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print( + f, + db, + span_formatter, + display_target, + )?; + } + MirEvalError::UndefinedBehavior(_) + | MirEvalError::TargetDataLayoutNotAvailable(_) + | MirEvalError::Panic(_) + | MirEvalError::MirLowerErrorForClosure(_, _) + | MirEvalError::TypeIsUnsized(_, _) + | MirEvalError::NotSupported(_) + | MirEvalError::InvalidConst + | MirEvalError::ExecutionLimitExceeded + | MirEvalError::StackOverflow + | MirEvalError::CoerceUnsizedError(_) + | MirEvalError::InternalError(_) + | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?, + } + Ok(()) + } + + fn is_panic(&self) -> Option<&str> { + let mut err = self; + while let MirEvalError::InFunction(e, _) = err { + err = e; + } + match err { + MirEvalError::Panic(msg) => Some(msg), + _ => None, + } + } +} + +#[extension(pub trait ConstEvalErrorPretty)] +impl ConstEvalError<'_> { + fn pretty_print( + &self, + f: &mut String, + db: &dyn HirDatabase, + span_formatter: impl Fn(span::FileId, span::TextRange) -> String, + display_target: DisplayTarget, + ) -> std::result::Result<(), std::fmt::Error> { + match self { + ConstEvalError::MirLowerError(e) => { + e.pretty_print(f, db, span_formatter, display_target) + } + ConstEvalError::MirEvalError(e) => { + e.pretty_print(f, db, span_formatter, display_target) + } + } + } +} diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ide/src/test_db.rs similarity index 99% rename from crates/hir-ty/src/test_db.rs rename to crates/hir-ide/src/test_db.rs index 59fda51781d2..63355e8f63dc 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ide/src/test_db.rs @@ -186,6 +186,8 @@ impl TestDB { } } +crate::impl_hir_database!(TestDB); + impl TestDB { pub(crate) fn log(&self, f: impl FnOnce()) -> Vec { *self.events.lock().unwrap() = Some(Vec::new()); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ide/src/tests.rs similarity index 99% rename from crates/hir-ty/src/tests.rs rename to crates/hir-ide/src/tests.rs index c19a1f27af96..28df2234b748 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ide/src/tests.rs @@ -1,10 +1,15 @@ +mod builtin_derives; mod closure_captures; mod coercion; +mod consteval; mod diagnostics; mod display_source_code; +mod dyn_compatibility; mod incremental; +mod layout; mod macros; mod method_resolution; +mod mir; mod never_type; mod opaque_types; mod patterns; @@ -12,6 +17,7 @@ mod regression; mod simple; mod trait_aliases; mod traits; +mod variance; use base_db::{Crate, SourceDatabase}; use expect_test::Expect; @@ -36,10 +42,9 @@ use syntax::{ use test_fixture::WithFixture; use crate::{ - InferenceDiagnostic, InferenceResult, + Adjustment, InferenceDiagnostic, InferenceResult, db::{AnonConstId, HirDatabase}, display::{DisplayTarget, HirDisplay}, - infer::Adjustment, next_solver::Ty, setup_tracing, test_db::TestDB, diff --git a/crates/hir-ide/src/tests/builtin_derives.rs b/crates/hir-ide/src/tests/builtin_derives.rs new file mode 100644 index 000000000000..70987bb9faa7 --- /dev/null +++ b/crates/hir-ide/src/tests/builtin_derives.rs @@ -0,0 +1,266 @@ +use expect_test::{Expect, expect}; +use hir_def::nameres::crate_def_map; +use itertools::Itertools; +use stdx::format_to; +use test_fixture::WithFixture; + +use crate::{builtin_derive::impl_trait, next_solver::DbInterner, test_db::TestDB}; + +fn check_trait_refs(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { + let db = TestDB::with_files(ra_fixture); + let def_map = crate_def_map(&db, db.test_crate()); + + let interner = DbInterner::new_with(&db, db.test_crate()); + crate::attach_db(&db, || { + let mut trait_refs = Vec::new(); + for (_, module) in def_map.modules() { + for derive in module.scope.builtin_derive_impls() { + let trait_ref = impl_trait(interner, derive).skip_binder(); + trait_refs.push(format!("{trait_ref:?}")); + } + } + + expectation.assert_eq(&trait_refs.join("\n")); + }); +} + +fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { + let db = TestDB::with_files(ra_fixture); + let def_map = crate_def_map(&db, db.test_crate()); + + crate::attach_db(&db, || { + let mut predicates = String::new(); + for (_, module) in def_map.modules() { + for derive in module.scope.builtin_derive_impls() { + let preds = + crate::builtin_derive::predicates(&db, derive).all_predicates().skip_binder(); + format_to!( + predicates, + "{}\n\n", + preds.format_with("\n", |pred, formatter| formatter(&format_args!("{pred:?}"))), + ); + } + } + + expectation.assert_eq(&predicates); + }); +} + +#[test] +fn simple_macros_trait_ref() { + check_trait_refs( + r#" +//- minicore: derive, clone, copy, eq, ord, hash, fmt + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct Simple; + +trait Trait {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]); + "#, + expect![[r#" + Simple: Debug + Simple: Clone + Simple: Copy + Simple: PartialEq<[Simple]> + Simple: Eq + Simple: PartialOrd<[Simple]> + Simple: Ord + Simple: Hash + WithGenerics<#0, #1, #2>: Debug + WithGenerics<#0, #1, #2>: Clone + WithGenerics<#0, #1, #2>: Copy + WithGenerics<#0, #1, #2>: PartialEq<[WithGenerics<#0, #1, #2>]> + WithGenerics<#0, #1, #2>: Eq + WithGenerics<#0, #1, #2>: PartialOrd<[WithGenerics<#0, #1, #2>]> + WithGenerics<#0, #1, #2>: Ord + WithGenerics<#0, #1, #2>: Hash"#]], + ); +} + +#[test] +fn coerce_pointee_trait_ref() { + check_trait_refs( + r#" +//- minicore: derive, coerce_pointee +use core::marker::CoercePointee; + +#[derive(CoercePointee)] +struct Simple(*const T); + +#[derive(CoercePointee)] +struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U); + "#, + expect![[r#" + Simple<#0>: CoerceUnsized<[Simple<#1>]> + Simple<#0>: DispatchFromDyn<[Simple<#1>]> + MultiGenericParams<#0, #1, #2, #3>: CoerceUnsized<[MultiGenericParams<#0, #1, #4, #3>]> + MultiGenericParams<#0, #1, #2, #3>: DispatchFromDyn<[MultiGenericParams<#0, #1, #4, #3>]>"#]], + ); +} + +#[test] +fn reborrow_trait_ref() { + check_trait_refs( + r#" +//- minicore: reborrow +use core::marker::Reborrow; + +#[derive(Reborrow)] +struct Marker<'a, T>(&'a mut T); + "#, + expect![[r#" + Marker<#0, #1>: Reborrow"#]], + ); +} + +#[test] +fn simple_macros_predicates() { + check_predicates( + r#" +//- minicore: derive, clone, copy, eq, ord, hash, fmt + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct Simple; + +trait Trait { + type Assoc; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N], T::Assoc); + "#, + expect![[r#" + + + + + + + + + + + + + + + + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Debug, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Debug, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Clone, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Clone, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Copy, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Copy, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: PartialEq<[#1]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): PartialEq<[Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. })]>, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Eq, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Eq, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: PartialOrd<[#1]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): PartialOrd<[Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. })]>, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Ord, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Ord, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Hash, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Hash, polarity:Positive), bound_vars: [] }) + + "#]], + ); +} + +#[test] +fn reborrow_predicates() { + check_predicates( + r#" +//- minicore: reborrow +use core::marker::Reborrow; + +trait Trait {} + +#[derive(Reborrow)] +struct Marker<'a, T: Trait, const N: usize>(&'a mut [T; N]); + "#, + expect![[r#" + Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + + "#]], + ); +} + +#[test] +fn coerce_pointee_predicates() { + check_predicates( + r#" +//- minicore: derive, coerce_pointee +use core::marker::CoercePointee; + +#[derive(CoercePointee)] +struct Simple(*const T); + +trait Trait {} + +#[derive(CoercePointee)] +struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U) +where + T: Trait, + U: Trait; + "#, + expect![[r#" + Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] }) + + Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] }) + Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] }) + + "#]], + ); +} diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ide/src/tests/closure_captures.rs similarity index 100% rename from crates/hir-ty/src/tests/closure_captures.rs rename to crates/hir-ide/src/tests/closure_captures.rs diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ide/src/tests/coercion.rs similarity index 100% rename from crates/hir-ty/src/tests/coercion.rs rename to crates/hir-ide/src/tests/coercion.rs diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ide/src/tests/consteval.rs similarity index 99% rename from crates/hir-ty/src/consteval/tests.rs rename to crates/hir-ide/src/tests/consteval.rs index 6ea8376e4874..1ee5af13b860 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ide/src/tests/consteval.rs @@ -14,14 +14,15 @@ use crate::{ db::HirDatabase, display::DisplayTarget, mir::{IsSigned, pad16}, + mir_pretty::{MirEvalErrorPretty as _, MirLowerErrorPretty as _}, next_solver::{Allocation, DbInterner, GenericArgs}, setup_tracing, test_db::TestDB, }; -use super::{ - super::mir::{MirEvalError, MirLowerError}, - ConstEvalError, +use crate::{ + consteval::ConstEvalError, + mir::{MirEvalError, MirLowerError}, }; mod intrinsics; diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ide/src/tests/consteval/intrinsics.rs similarity index 100% rename from crates/hir-ty/src/consteval/tests/intrinsics.rs rename to crates/hir-ide/src/tests/consteval/intrinsics.rs diff --git a/crates/hir-ty/src/tests/diagnostics.rs b/crates/hir-ide/src/tests/diagnostics.rs similarity index 100% rename from crates/hir-ty/src/tests/diagnostics.rs rename to crates/hir-ide/src/tests/diagnostics.rs diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ide/src/tests/display_source_code.rs similarity index 100% rename from crates/hir-ty/src/tests/display_source_code.rs rename to crates/hir-ide/src/tests/display_source_code.rs diff --git a/crates/hir-ty/src/dyn_compatibility/tests.rs b/crates/hir-ide/src/tests/dyn_compatibility.rs similarity index 97% rename from crates/hir-ty/src/dyn_compatibility/tests.rs rename to crates/hir-ide/src/tests/dyn_compatibility.rs index a70f98a0fe7b..84360b7a3f2f 100644 --- a/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/crates/hir-ide/src/tests/dyn_compatibility.rs @@ -5,11 +5,13 @@ use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ToSmolStr; use test_fixture::WithFixture; -use crate::{dyn_compatibility::dyn_compatibility_with_callback, test_db::TestDB}; - -use super::{ - DynCompatibilityViolation, - MethodViolationCode::{self, *}, +use crate::{ + dyn_compatibility::{ + DynCompatibilityViolation, + MethodViolationCode::{self, *}, + dyn_compatibility_with_callback, + }, + test_db::TestDB, }; use DynCompatibilityViolationKind::*; diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ide/src/tests/incremental.rs similarity index 100% rename from crates/hir-ty/src/tests/incremental.rs rename to crates/hir-ide/src/tests/incremental.rs diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ide/src/tests/layout.rs similarity index 99% rename from crates/hir-ty/src/layout/tests.rs rename to crates/hir-ide/src/tests/layout.rs index 5098b38c4380..dfe08268f342 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ide/src/tests/layout.rs @@ -217,7 +217,7 @@ macro_rules! size_and_align_expr { { $($s)* let val = { $($t)* }; - $crate::layout::tests::check_size_and_align_expr( + $crate::tests::layout::check_size_and_align_expr( &format!("{{ {} let val = {{ {} }}; val }}", stringify!($($s)*), stringify!($($t)*)), &format!("//- minicore: {}\n", stringify!($($x),*)), ::std::mem::size_of_val(&val) as u64, @@ -231,7 +231,7 @@ macro_rules! size_and_align_expr { #[allow(dead_code)] { let val = { $($t)* }; - $crate::layout::tests::check_size_and_align_expr( + $crate::tests::layout::check_size_and_align_expr( stringify!($($t)*), "", ::std::mem::size_of_val(&val) as u64, diff --git a/crates/hir-ty/src/layout/tests/closure.rs b/crates/hir-ide/src/tests/layout/closure.rs similarity index 100% rename from crates/hir-ty/src/layout/tests/closure.rs rename to crates/hir-ide/src/tests/layout/closure.rs diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ide/src/tests/macros.rs similarity index 100% rename from crates/hir-ty/src/tests/macros.rs rename to crates/hir-ide/src/tests/macros.rs diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ide/src/tests/method_resolution.rs similarity index 100% rename from crates/hir-ty/src/tests/method_resolution.rs rename to crates/hir-ide/src/tests/method_resolution.rs diff --git a/crates/hir-ide/src/tests/mir.rs b/crates/hir-ide/src/tests/mir.rs new file mode 100644 index 000000000000..f1d792a17871 --- /dev/null +++ b/crates/hir-ide/src/tests/mir.rs @@ -0,0 +1,2 @@ +mod eval; +mod lower; diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ide/src/tests/mir/eval.rs similarity index 99% rename from crates/hir-ty/src/mir/eval/tests.rs rename to crates/hir-ide/src/tests/mir/eval.rs index f09ac6f20d27..5b0444602297 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ide/src/tests/mir/eval.rs @@ -8,12 +8,13 @@ use crate::{ db::HirDatabase, display::DisplayTarget, mir::MirLowerError, + mir_pretty::MirEvalErrorPretty as _, next_solver::{DbInterner, GenericArgs}, setup_tracing, test_db::TestDB, }; -use super::{MirEvalError, interpret_mir}; +use crate::mir::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { diff --git a/crates/hir-ty/src/mir/lower/tests.rs b/crates/hir-ide/src/tests/mir/lower.rs similarity index 100% rename from crates/hir-ty/src/mir/lower/tests.rs rename to crates/hir-ide/src/tests/mir/lower.rs diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ide/src/tests/never_type.rs similarity index 100% rename from crates/hir-ty/src/tests/never_type.rs rename to crates/hir-ide/src/tests/never_type.rs diff --git a/crates/hir-ty/src/tests/opaque_types.rs b/crates/hir-ide/src/tests/opaque_types.rs similarity index 100% rename from crates/hir-ty/src/tests/opaque_types.rs rename to crates/hir-ide/src/tests/opaque_types.rs diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ide/src/tests/patterns.rs similarity index 100% rename from crates/hir-ty/src/tests/patterns.rs rename to crates/hir-ide/src/tests/patterns.rs diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ide/src/tests/regression.rs similarity index 100% rename from crates/hir-ty/src/tests/regression.rs rename to crates/hir-ide/src/tests/regression.rs diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ide/src/tests/regression/new_solver.rs similarity index 100% rename from crates/hir-ty/src/tests/regression/new_solver.rs rename to crates/hir-ide/src/tests/regression/new_solver.rs diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ide/src/tests/simple.rs similarity index 100% rename from crates/hir-ty/src/tests/simple.rs rename to crates/hir-ide/src/tests/simple.rs diff --git a/crates/hir-ty/src/tests/trait_aliases.rs b/crates/hir-ide/src/tests/trait_aliases.rs similarity index 100% rename from crates/hir-ty/src/tests/trait_aliases.rs rename to crates/hir-ide/src/tests/trait_aliases.rs diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ide/src/tests/traits.rs similarity index 100% rename from crates/hir-ty/src/tests/traits.rs rename to crates/hir-ide/src/tests/traits.rs diff --git a/crates/hir-ide/src/tests/variance.rs b/crates/hir-ide/src/tests/variance.rs new file mode 100644 index 000000000000..4dff4da147a4 --- /dev/null +++ b/crates/hir-ide/src/tests/variance.rs @@ -0,0 +1,576 @@ +use expect_test::{Expect, expect}; +use hir_def::{ + AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource, +}; +use itertools::Itertools; +use rustc_type_ir::Variance; +use stdx::format_to; +use syntax::{AstNode, ast::HasName}; +use test_fixture::WithFixture; + +use hir_def::Lookup; + +use crate::{db::HirDatabase, generics::generics, test_db::TestDB}; + +#[test] +fn phantom_data() { + check( + r#" +//- minicore: phantom_data + +struct Covariant { + t: core::marker::PhantomData +} +"#, + expect![[r#" + Covariant[A: covariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_types() { + check( + r#" +//- minicore: cell +#![feature(lang_items)] + +use core::cell::UnsafeCell; + +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR ['a: +, A: o, B: o] + t: &'a mut (A,B) +} + +struct InvariantCell { //~ ERROR [A: o] + t: UnsafeCell +} + +struct InvariantIndirect { //~ ERROR [A: o] + t: InvariantCell +} + +struct Covariant { //~ ERROR [A: +] + t: A, u: fn() -> A +} + +struct Contravariant { //~ ERROR [A: -] + t: fn(A) +} + +enum Enum { //~ ERROR [A: +, B: -, C: o] + Foo(Covariant), + Bar(Contravariant),` + Zed(Covariant,Contravariant) +} + +#[repr(transparent)] +#[lang = "covariant_unsafe_cell"] +pub struct CovariantUnsafeCell(UnsafeCell); //~ ERROR [T: +] +"#, + expect![[r#" + InvariantMut['a: covariant, A: invariant, B: invariant] + InvariantCell[A: invariant] + InvariantIndirect[A: invariant] + Covariant[A: covariant] + Contravariant[A: contravariant] + Enum[A: covariant, B: contravariant, C: invariant] + CovariantUnsafeCell[T: covariant] + "#]], + ); +} + +#[test] +fn type_resolve_error_two_structs_deep() { + check( + r#" +struct Hello<'a> { + missing: Missing<'a>, +} + +struct Other<'a> { + hello: Hello<'a>, +} +"#, + expect![[r#" + Hello['a: bivariant] + Other['a: bivariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_associated_consts() { + check( + r#" +trait Trait { + const Const: usize; +} + +struct Foo { //~ ERROR [T: o] + field: [u8; ::Const] +} +"#, + expect![[r#" + Foo[T: invariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_associated_types() { + check( + r#" +trait Trait<'a> { + type Type; + + fn method(&'a self) { } +} + +struct Foo<'a, T : Trait<'a>> { //~ ERROR ['a: +, T: +] + field: (T, &'a ()) +} + +struct Bar<'a, T : Trait<'a>> { //~ ERROR ['a: o, T: o] + field: >::Type +} + +"#, + expect![[r#" + method[Self: contravariant, 'a: contravariant] + Foo['a: covariant, T: covariant] + Bar['a: invariant, T: invariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_associated_types2() { + // FIXME: RPITs have variance, but we can't treat them as their own thing right now + check( + r#" +trait Foo { + type Bar; +} + +fn make() -> *const dyn Foo {} +"#, + expect![""], + ); +} + +#[test] +fn rustc_test_variance_trait_bounds() { + check( + r#" +trait Getter { + fn get(&self) -> T; +} + +trait Setter { + fn get(&self, _: T); +} + +struct TestStruct> { //~ ERROR [U: +, T: +] + t: T, u: U +} + +enum TestEnum> { //~ ERROR [U: *, T: +] + //~^ ERROR: `U` is never used + Foo(T) +} + +struct TestContraStruct> { //~ ERROR [U: *, T: +] + //~^ ERROR: `U` is never used + t: T +} + +struct TestBox+Setter> { //~ ERROR [U: *, T: +] + //~^ ERROR: `U` is never used + t: T +} +"#, + expect![[r#" + get[Self: contravariant, T: covariant] + get[Self: contravariant, T: contravariant] + TestStruct[U: covariant, T: covariant] + TestEnum[U: bivariant, T: covariant] + TestContraStruct[U: bivariant, T: covariant] + TestBox[U: bivariant, T: covariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_trait_matching() { + check( + r#" + +trait Get { + fn get(&self) -> T; +} + +struct Cloner { + t: T +} + +impl Get for Cloner { + fn get(&self) -> T {} +} + +fn get<'a, G>(get: &G) -> i32 + where G : Get<&'a i32> +{} + +fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32 + where G : Get<&'b i32> +{} +"#, + expect![[r#" + get[Self: contravariant, T: covariant] + Cloner[T: covariant] + get[T: invariant] + get['a: invariant, G: contravariant] + pick['b: contravariant, G: contravariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_trait_object_bound() { + check( + r#" +enum Option { + Some(T), + None +} +trait T { fn foo(&self); } + +struct TOption<'a> { //~ ERROR ['a: +] + v: Option<*const (dyn T + 'a)>, +} +"#, + expect![[r#" + Option[T: covariant] + foo[Self: contravariant] + TOption['a: covariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_types_bounds() { + check( + r#" +//- minicore: send +struct TestImm { //~ ERROR [A: +, B: +] + x: A, + y: B, +} + +struct TestMut { //~ ERROR [A: +, B: o] + x: A, + y: &'static mut B, +} + +struct TestIndirect { //~ ERROR [A: +, B: o] + m: TestMut +} + +struct TestIndirect2 { //~ ERROR [A: o, B: o] + n: TestMut, + m: TestMut +} + +trait Getter { + fn get(&self) -> A; +} + +trait Setter { + fn set(&mut self, a: A); +} + +struct TestObject { //~ ERROR [A: o, R: o] + n: *const (dyn Setter + Send), + m: *const (dyn Getter + Send), +} +"#, + expect![[r#" + TestImm[A: covariant, B: covariant] + TestMut[A: covariant, B: invariant] + TestIndirect[A: covariant, B: invariant] + TestIndirect2[A: invariant, B: invariant] + get[Self: contravariant, A: covariant] + set[Self: invariant, A: contravariant] + TestObject[A: invariant, R: invariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_unused_region_param() { + check( + r#" +struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used +enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used +trait SomeTrait<'a> { fn foo(&self); } // OK on traits. +"#, + expect![[r#" + SomeStruct['a: bivariant] + SomeEnum['a: bivariant] + foo[Self: contravariant, 'a: invariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_unused_type_param() { + check( + r#" +//- minicore: sized +struct SomeStruct { x: u32 } +enum SomeEnum { Nothing } +enum ListCell { + Cons(*const ListCell), + Nil +} + +struct SelfTyAlias(*const Self); +struct WithBounds {} +struct WithWhereBounds where T: Sized {} +struct WithOutlivesBounds {} +struct DoubleNothing { + s: SomeStruct, +} + +"#, + expect![[r#" + SomeStruct[A: bivariant] + SomeEnum[A: bivariant] + ListCell[T: bivariant] + SelfTyAlias[T: bivariant] + WithBounds[T: bivariant] + WithWhereBounds[T: bivariant] + WithOutlivesBounds[T: bivariant] + DoubleNothing[T: bivariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_use_contravariant_struct1() { + check( + r#" +struct SomeStruct(fn(T)); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{} +"#, + expect![[r#" + SomeStruct[T: contravariant] + foo['min: contravariant, 'max: covariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_use_contravariant_struct2() { + check( + r#" +struct SomeStruct(fn(T)); + +fn bar<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{} +"#, + expect![[r#" + SomeStruct[T: contravariant] + bar['min: covariant, 'max: contravariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_use_covariant_struct1() { + check( + r#" +struct SomeStruct(T); + +fn foo<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{} +"#, + expect![[r#" + SomeStruct[T: covariant] + foo['min: contravariant, 'max: covariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_use_covariant_struct2() { + check( + r#" +struct SomeStruct(T); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{} +"#, + expect![[r#" + SomeStruct[T: covariant] + foo['min: covariant, 'max: contravariant] + "#]], + ); +} + +#[test] +fn rustc_test_variance_use_invariant_struct1() { + check( + r#" +struct SomeStruct(*mut T); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{} + +fn bar<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{} +"#, + expect![[r#" + SomeStruct[T: invariant] + foo['min: invariant, 'max: invariant] + bar['min: invariant, 'max: invariant] + "#]], + ); +} + +#[test] +fn invalid_arg_counts() { + check( + r#" +struct S(T); +struct S2(S<>); +struct S3(S); +"#, + expect![[r#" + S[T: covariant] + S2[T: bivariant] + S3[T: covariant] + "#]], + ); +} + +#[test] +fn prove_fixedpoint() { + check( + r#" +struct FixedPoint(&'static FixedPoint<(), T, U>, V); +"#, + expect![[r#" + FixedPoint[T: covariant, U: covariant, V: covariant] + "#]], + ); +} + +#[track_caller] +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) { + // use tracing_subscriber::{layer::SubscriberExt, Layer}; + // let my_layer = tracing_subscriber::fmt::layer(); + // let _g = tracing::subscriber::set_default(tracing_subscriber::registry().with( + // my_layer.with_filter(tracing_subscriber::filter::filter_fn(|metadata| { + // metadata.target().starts_with("hir_ty::variance") + // })), + // )); + let (db, file_id) = TestDB::with_single_file(ra_fixture); + + 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, &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(_) + | GenericDefId::TypeAliasId(_) + | GenericDefId::ImplId(_) + | GenericDefId::ConstId(_) + | GenericDefId::StaticId(_) => return None, + }, + )) + }) + .sorted_by_key(|(_, n)| n.syntax().text_range().start()); + let mut res = String::new(); + for (def, name) in defs { + let variances = db.variances_of(def); + if variances.is_empty() { + continue; + } + format_to!( + res, + "{name}[{}]\n", + generics(&db, def) + .iter(false) + .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!( + "{}: {}", + name.as_str(), + match var { + Variance::Covariant => "covariant", + Variance::Invariant => "invariant", + Variance::Contravariant => "contravariant", + Variance::Bivariant => "bivariant", + }, + ))) + ); + } + + expected.assert_eq(&res); + }) +} diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index c55ad5bacfe9..427f2b5cfb24 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -26,7 +26,6 @@ tracing = { workspace = true, features = ["attributes"] } rustc-hash.workspace = true la-arena.workspace = true triomphe.workspace = true -typed-arena = "2.0.2" indexmap.workspace = true rustc_apfloat = "0.2.3" salsa.workspace = true @@ -35,7 +34,6 @@ bitflags.workspace = true ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true -ra-ap-rustc_pattern_analysis.workspace = true ra-ap-rustc_ast_ir.workspace = true ra-ap-rustc_type_ir.workspace = true ra-ap-rustc_next_trait_solver.workspace = true @@ -56,16 +54,11 @@ syntax.workspace = true span.workspace = true thin-vec = "0.2.16" -[dev-dependencies] -expect-test = "1.5.1" -project-model.workspace = true - -# local deps -test-utils.workspace = true -test-fixture.workspace = true - [features] in-rust-tree = ["hir-expand/in-rust-tree"] [lints] workspace = true + +[package.metadata.cargo-machete] +ignored = ["serde"] diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs index baa7b87e457f..ffe568979b06 100644 --- a/crates/hir-ty/src/builtin_derive.rs +++ b/crates/hir-ty/src/builtin_derive.rs @@ -419,274 +419,3 @@ fn coerce_pointee_params<'db>( let new_param_ty = Ty::new_param(interner, new_param_id, new_param_idx); Some((pointee_param_idx, pointee_param_id, new_param_ty)) } - -#[cfg(test)] -mod tests { - use expect_test::{Expect, expect}; - use hir_def::nameres::crate_def_map; - use itertools::Itertools; - use stdx::format_to; - use test_fixture::WithFixture; - - use crate::{builtin_derive::impl_trait, next_solver::DbInterner, test_db::TestDB}; - - fn check_trait_refs(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { - let db = TestDB::with_files(ra_fixture); - let def_map = crate_def_map(&db, db.test_crate()); - - let interner = DbInterner::new_with(&db, db.test_crate()); - crate::attach_db(&db, || { - let mut trait_refs = Vec::new(); - for (_, module) in def_map.modules() { - for derive in module.scope.builtin_derive_impls() { - let trait_ref = impl_trait(interner, derive).skip_binder(); - trait_refs.push(format!("{trait_ref:?}")); - } - } - - expectation.assert_eq(&trait_refs.join("\n")); - }); - } - - fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { - let db = TestDB::with_files(ra_fixture); - let def_map = crate_def_map(&db, db.test_crate()); - - crate::attach_db(&db, || { - let mut predicates = String::new(); - for (_, module) in def_map.modules() { - for derive in module.scope.builtin_derive_impls() { - let preds = super::predicates(&db, derive).all_predicates().skip_binder(); - format_to!( - predicates, - "{}\n\n", - preds.format_with("\n", |pred, formatter| formatter(&format_args!( - "{pred:?}" - ))), - ); - } - } - - expectation.assert_eq(&predicates); - }); - } - - #[test] - fn simple_macros_trait_ref() { - check_trait_refs( - r#" -//- minicore: derive, clone, copy, eq, ord, hash, fmt - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct Simple; - -trait Trait {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]); - "#, - expect![[r#" - Simple: Debug - Simple: Clone - Simple: Copy - Simple: PartialEq<[Simple]> - Simple: Eq - Simple: PartialOrd<[Simple]> - Simple: Ord - Simple: Hash - WithGenerics<#0, #1, #2>: Debug - WithGenerics<#0, #1, #2>: Clone - WithGenerics<#0, #1, #2>: Copy - WithGenerics<#0, #1, #2>: PartialEq<[WithGenerics<#0, #1, #2>]> - WithGenerics<#0, #1, #2>: Eq - WithGenerics<#0, #1, #2>: PartialOrd<[WithGenerics<#0, #1, #2>]> - WithGenerics<#0, #1, #2>: Ord - WithGenerics<#0, #1, #2>: Hash"#]], - ); - } - - #[test] - fn coerce_pointee_trait_ref() { - check_trait_refs( - r#" -//- minicore: derive, coerce_pointee -use core::marker::CoercePointee; - -#[derive(CoercePointee)] -struct Simple(*const T); - -#[derive(CoercePointee)] -struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U); - "#, - expect![[r#" - Simple<#0>: CoerceUnsized<[Simple<#1>]> - Simple<#0>: DispatchFromDyn<[Simple<#1>]> - MultiGenericParams<#0, #1, #2, #3>: CoerceUnsized<[MultiGenericParams<#0, #1, #4, #3>]> - MultiGenericParams<#0, #1, #2, #3>: DispatchFromDyn<[MultiGenericParams<#0, #1, #4, #3>]>"#]], - ); - } - - #[test] - fn reborrow_trait_ref() { - check_trait_refs( - r#" -//- minicore: reborrow -use core::marker::Reborrow; - -#[derive(Reborrow)] -struct Marker<'a, T>(&'a mut T); - "#, - expect![[r#" - Marker<#0, #1>: Reborrow"#]], - ); - } - - #[test] - fn simple_macros_predicates() { - check_predicates( - r#" -//- minicore: derive, clone, copy, eq, ord, hash, fmt - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct Simple; - -trait Trait { - type Assoc; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N], T::Assoc); - "#, - expect![[r#" - - - - - - - - - - - - - - - - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Debug, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Debug, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Clone, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Clone, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Copy, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Copy, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: PartialEq<[#1]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): PartialEq<[Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. })]>, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Eq, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Eq, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: PartialOrd<[#1]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): PartialOrd<[Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. })]>, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Ord, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Ord, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Hash, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(Alias(AliasTy { args: [#1], kind: Projection { def_id: TypeAliasId("Assoc") }, .. }): Hash, polarity:Positive), bound_vars: [] }) - - "#]], - ); - } - - #[test] - fn reborrow_predicates() { - check_predicates( - r#" -//- minicore: reborrow -use core::marker::Reborrow; - -trait Trait {} - -#[derive(Reborrow)] -struct Marker<'a, T: Trait, const N: usize>(&'a mut [T; N]); - "#, - expect![[r#" - Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - - "#]], - ); - } - - #[test] - fn coerce_pointee_predicates() { - check_predicates( - r#" -//- minicore: derive, coerce_pointee -use core::marker::CoercePointee; - -#[derive(CoercePointee)] -struct Simple(*const T); - -trait Trait {} - -#[derive(CoercePointee)] -struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U) -where - T: Trait, - U: Trait; - "#, - expect![[r#" - Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] }) - - Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] }) - Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] }) - - "#]], - ); - } -} diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index d65f76cdf1ce..f6ce1b8cdcef 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -1,8 +1,5 @@ //! Constant evaluation details -#[cfg(test)] -mod tests; - use base_db::Crate; use hir_def::{ ConstId, EnumVariantId, ExpressionStoreOwnerId, HasModule, StaticId, @@ -21,7 +18,6 @@ use salsa::SalsaValue; use crate::{ ParamEnvAndCrate, Span, db::{AnonConstId, AnonConstLoc, GeneralConstId, HirDatabase}, - display::DisplayTarget, generics::Generics, lower::LoweringMode, mir::{IsSigned, MirEvalError, MirLowerError, pad16}, @@ -41,25 +37,6 @@ pub enum ConstEvalError<'db> { MirEvalError(MirEvalError<'db>), } -impl ConstEvalError<'_> { - pub fn pretty_print( - &self, - f: &mut String, - db: &dyn HirDatabase, - span_formatter: impl Fn(span::FileId, span::TextRange) -> String, - display_target: DisplayTarget, - ) -> std::result::Result<(), std::fmt::Error> { - match self { - ConstEvalError::MirLowerError(e) => { - e.pretty_print(f, db, span_formatter, display_target) - } - ConstEvalError::MirEvalError(e) => { - e.pretty_print(f, db, span_formatter, display_target) - } - } - } -} - impl<'db> From> for ConstEvalError<'db> { fn from(value: MirLowerError<'db>) -> Self { match value { diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index f42a428bbdd2..54ad0da40d8a 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -344,13 +344,9 @@ pub trait HirDatabase: SourceDatabase + 'static { let db = self.as_dyn(); crate::variance::variances_of(db, def) } -} -#[salsa::db] -impl HirDatabase for T { - fn as_dyn(&self) -> &dyn HirDatabase { - self - } + // HACK: We need this for MIR intrinsic `type_name()`, and it can't access the display infra because it is inside `hir-ide`. + fn type_name<'db>(&'db self, ty: Ty<'db>, module: ModuleId) -> String; } #[test] diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index 4fd65398d0ba..4b63fd10d59a 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -527,6 +527,3 @@ fn contains_illegal_impl_trait_in_trait<'db>( None } - -#[cfg(test)] -mod tests; diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index f2ca060bb533..450bf7566062 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -20,7 +20,7 @@ use hir_def::{ }, }; -pub(crate) fn generics(db: &dyn SourceDatabase, def: GenericDefId) -> Generics<'_> { +pub fn generics(db: &dyn SourceDatabase, def: GenericDefId) -> Generics<'_> { let mut chain = ArrayVec::new(); let mut parent_params_len = 0; if let Some(parent_def) = parent_generic_def(db, def) { @@ -232,7 +232,7 @@ impl<'db> Generics<'db> { } /// Iterate over the parent params followed by self params. - pub(crate) fn iter( + pub fn iter( &self, consider_late_bound: bool, ) -> impl Iterator)> { @@ -265,7 +265,7 @@ impl<'db> Generics<'db> { self.owner().len_lifetimes() } - pub(crate) fn provenance_split(&self) -> ProvenanceSplit { + pub fn provenance_split(&self) -> ProvenanceSplit { let parent_total = self.len_parent(); let owner = self.owner(); @@ -375,14 +375,14 @@ impl<'db> Generics<'db> { } } -pub(crate) struct ProvenanceSplit { - pub(crate) parent_total: usize, +pub struct ProvenanceSplit { + pub parent_total: usize, // The rest are about self. - pub(crate) has_self_param: bool, - pub(crate) non_impl_trait_type_params: usize, - pub(crate) const_params: usize, - pub(crate) impl_trait_type_params: usize, - pub(crate) lifetimes: usize, + pub has_self_param: bool, + pub non_impl_trait_type_params: usize, + pub const_params: usize, + pub impl_trait_type_params: usize, + pub lifetimes: usize, } fn parent_generic_def(db: &dyn SourceDatabase, def: GenericDefId) -> Option { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 3fbb02aee94b..3a23bde7b912 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -780,21 +780,21 @@ pub struct InferenceResult<'db> { /// that which allows us to resolve a [`TupleFieldId`]s type. tuple_field_access_types: ThinVec, - pub(crate) type_of_expr: ArenaMap, + pub 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_type_placeholder: FxHashMap, - pub(crate) type_of_opaque: FxHashMap, StoredTy>, + pub type_of_pat: ArenaMap, + pub type_of_binding: ArenaMap, + pub type_of_type_placeholder: FxHashMap, + pub type_of_opaque: FxHashMap, StoredTy>, /// 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, + pub has_errors: bool, /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. diagnostics: ThinVec, // FIXME: Remove this, change it to be in `InferenceContext`: @@ -804,9 +804,9 @@ pub struct InferenceResult<'db> { // FIXME: Remove this. error_ty: StoredTy, - pub(crate) expr_adjustments: FxHashMap>, + pub expr_adjustments: FxHashMap>, /// Stores the types which were implicitly dereferenced in pattern binding modes. - pub(crate) pat_adjustments: FxHashMap>, + pub 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 @@ -820,13 +820,13 @@ pub struct InferenceResult<'db> { /// } /// ``` /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`. - pub(crate) binding_modes: ArenaMap, + pub binding_modes: ArenaMap, /// Set of reference patterns that match against a match-ergonomics inserted reference /// (as opposed to against a reference in the scrutinee type). skipped_ref_pats: FxHashSet, - pub(crate) coercion_casts: FxHashSet, + pub coercion_casts: FxHashSet, pub closures_data: FxHashMap, diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index 0c24b82d1bde..9dbeb6a8a03b 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -39,6 +39,7 @@ use hir_def::{ Pat, PatId, Statement, }, resolver::ValueNs, + upvars::{Upvars, UpvarsRef}, }; use macros::{TypeFoldable, TypeVisitable}; use rustc_abi::ExternAbi; @@ -65,7 +66,6 @@ use crate::{ Binder, BoundRegion, BoundRegionKind, DbInterner, GenericArgs, Region, Ty, TyKind, abi::Safety, infer::traits::ObligationCause, normalize, }, - upvars::{Upvars, UpvarsRef}, }; pub(crate) mod expr_use_visitor; @@ -196,7 +196,7 @@ type InferredCaptureInformation = Vec<(Place, CaptureInfo)>; impl<'db> InferenceContext<'db> { pub(crate) fn closure_analyze(&mut self) { - let upvars = crate::upvars::upvars_mentioned(self.db, self.store_owner) + let upvars = hir_def::upvars::upvars_mentioned(self.db, self.store_owner) .unwrap_or(const { &FxHashMap::with_hasher(FxBuildHasher) }); for root_expr in self.store.expr_roots() { self.analyze_closures_in_expr(root_expr, upvars); diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index 78940783bd9b..15932e995732 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -13,6 +13,7 @@ use hir_def::{ PatId, RecordLitField, RecordSpread, Statement, }, resolver::ValueNs, + upvars::UpvarsRef, }; use macros::{TypeFoldable, TypeVisitable}; use rustc_type_ir::inherent::{IntoKind, Ty as _}; @@ -29,7 +30,6 @@ use crate::{ }, method_resolution::CandidateId, next_solver::{ErrorGuaranteed, StoredTy, Ty, TyKind}, - upvars::UpvarsRef, utils::EnumerateAndAdjustIterator, }; diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 85d8142335dd..132092c4a073 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -39,6 +39,7 @@ use std::ops::ControlFlow; use hir_def::{ CallableDefId, TraitId, attrs::AttrFlags, hir::ExprId, signatures::FunctionSignature, + upvars::upvars_mentioned, }; use rustc_ast_ir::Mutability; use rustc_type_ir::{ @@ -70,7 +71,6 @@ use crate::{ inspect::{InspectGoal, ProofTreeVisitor}, obligation_ctxt::ObligationCtxt, }, - upvars::upvars_mentioned, utils::TargetFeatureIsSafeInTarget, }; diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index bca91d07a74f..69b8e898171e 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -19,7 +19,7 @@ use crate::{ // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. -pub(crate) fn is_ty_uninhabited_from<'db>( +pub fn is_ty_uninhabited_from<'db>( infcx: &InferCtxt<'db>, ty: Ty<'db>, target_mod: ModuleId, @@ -33,7 +33,7 @@ pub(crate) fn is_ty_uninhabited_from<'db>( // FIXME: Turn this into a query, it can be quite slow /// Checks whether a variant is visibly uninhabited from a particular module. -pub(crate) fn is_enum_variant_uninhabited_from<'db>( +pub fn is_enum_variant_uninhabited_from<'db>( infcx: &InferCtxt<'db>, variant: EnumVariantId, subst: GenericArgs<'db>, diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 1fbf15042f54..3aebee25910a 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -37,9 +37,6 @@ pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; pub(crate) mod adt; pub(crate) mod target; -#[cfg(test)] -mod tests; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RustcEnumVariantIdx(pub usize); diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 21e68a6312d3..da656b7260b5 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -11,38 +11,30 @@ // For details, see the zulip discussion below: // https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/relying.20on.20in-tree.20.60rustc_type_ir.60.2F.60rustc_next_trait_solver.60/with/541055689 -extern crate ra_ap_rustc_index as rustc_index; - extern crate ra_ap_rustc_abi as rustc_abi; - -extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; - extern crate ra_ap_rustc_ast_ir as rustc_ast_ir; - -extern crate ra_ap_rustc_type_ir as rustc_type_ir; - +extern crate ra_ap_rustc_index as rustc_index; extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; +extern crate ra_ap_rustc_type_ir as rustc_type_ir; extern crate self as hir_ty; pub mod builtin_derive; -mod generics; +pub mod generics; mod infer; -mod inhabitedness; +pub mod inhabitedness; mod lower; pub mod next_solver; mod opaques; mod representability; mod specialization; mod target_feature; -mod utils; +pub mod utils; mod variance; pub mod autoderef; pub mod consteval; pub mod db; -pub mod diagnostics; -pub mod display; pub mod drop; pub mod dyn_compatibility; pub mod lang_items; @@ -52,12 +44,6 @@ pub mod mir; pub mod primitive; pub mod solver_errors; pub mod traits; -pub mod upvars; - -#[cfg(test)] -mod test_db; -#[cfg(test)] -mod tests; use std::{hash::Hash, ops::ControlFlow}; @@ -83,12 +69,10 @@ use rustc_type_ir::{ }; use salsa::SalsaValue; use stdx::impl_from; -use syntax::ast::{ConstArg, make}; use traits::FnTrait; use crate::{ db::{AnonConstId, HirDatabase}, - display::HirDisplay, lower::SupertraitsInfo, next_solver::{ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, @@ -202,7 +186,7 @@ impl<'db> MemoryMap<'db> { } } - fn get(&self, addr: usize, size: usize) -> Option<&[u8]> { + pub fn get(&self, addr: usize, size: usize) -> Option<&[u8]> { if size == 0 { Some(&[]) } else { @@ -506,16 +490,6 @@ where Vec::from_iter(collector.params) } -pub fn known_const_to_ast<'db>( - konst: Const<'db>, - db: &'db dyn HirDatabase, - target_module: ModuleId, -) -> Option { - Some(make::expr_const_value( - &konst.display_source_code(db, target_module, true).unwrap_or_else(|_| "_".to_owned()), - )) -} - /// A `Span` represents some location in lowered code - a type, expression or pattern. /// /// It has no meaning outside its body therefore it should not exit the pass it was created in diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index fc71e716d90f..8bef5b7e5506 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -35,7 +35,6 @@ use crate::{ mod eval; mod lower; mod monomorphization; -mod pretty; pub use eval::{ Evaluator, IsSigned, MirEvalError, VTableMap, interpret_mir, pad16, @@ -81,7 +80,7 @@ pub struct Local { /// validator. #[derive(Debug, PartialEq, Eq, Clone)] pub struct Operand { - kind: OperandKind, + pub kind: OperandKind, // FIXME : This should actually just be of type `MirSpan`. span: Option, } @@ -214,7 +213,7 @@ impl ProjectionElem { } } -type PlaceElem = ProjectionElem; +pub type PlaceElem = ProjectionElem; impl GenericTypeVisitable for PlaceElem { fn generic_visit_with(&self, _: &mut W) {} diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index e513f13ed85a..8e48b3532a4e 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1,6 +1,6 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; +use std::{borrow::Cow, cell::RefCell, iter, mem, ops::Range}; use base_db::{Crate, target::TargetLoadError}; use either::Either; @@ -12,10 +12,7 @@ use hir_def::{ lang_item::LangItems, layout::{TagEncoding, Variants}, resolver::{HasResolver, ValueNs}, - signatures::{ - EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags, - StructSignature, TraitSignature, - }, + signatures::{EnumSignature, StaticFlags, StaticSignature, StructFlags, StructSignature}, }; use hir_expand::{InFile, mod_path::path}; use la_arena::ArenaMap; @@ -41,7 +38,6 @@ use crate::{ CallableDefId, ComplexMemoryMap, InferBodyId, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval::{self, ConstEvalError, try_const_usize}, db::{GeneralConstId, HirDatabase, InternedClosureId}, - display::{ClosureStyle, DisplayTarget, HirDisplay}, infer::PointerCast, layout::{Layout, LayoutError, RustcEnumVariantIdx}, method_resolution::{is_dyn_method, lookup_impl_const}, @@ -62,8 +58,6 @@ use super::{ }; mod shim; -#[cfg(test)] -mod tests; macro_rules! from_bytes { ($ty:tt, $value:expr) => { @@ -378,148 +372,6 @@ pub enum MirEvalError<'db> { InternalError(Box), } -impl MirEvalError<'_> { - pub fn pretty_print( - &self, - f: &mut String, - db: &dyn HirDatabase, - span_formatter: impl Fn(FileId, TextRange) -> String, - display_target: DisplayTarget, - ) -> std::result::Result<(), std::fmt::Error> { - writeln!(f, "Mir eval error:")?; - let mut err = self; - while let MirEvalError::InFunction(e, stack) = err { - err = e; - for (func, span, def) in stack.iter().take(30).rev() { - match func { - Either::Left(func) => { - let function_name = FunctionSignature::of(db, *func); - writeln!( - f, - "In function {} ({:?})", - function_name.name.display(db, display_target.edition), - func - )?; - } - Either::Right(closure) => { - writeln!(f, "In {closure:?}")?; - } - } - let (source_map, self_param_syntax) = match *def { - InferBodyId::DefWithBodyId(def) => { - let body = &Body::with_source_map(db, def).1; - (&**body, body.self_param_syntax()) - } - InferBodyId::AnonConstId(def) => { - let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1; - (store, None) - } - }; - let span: InFile = match *span { - MirSpan::ExprId(e) => match source_map.expr_syntax(e) { - Ok(s) => s.map(|it| it.into()), - Err(_) => continue, - }, - MirSpan::PatId(p) => match source_map.pat_syntax(p) { - Ok(s) => s.map(|it| it.syntax_node_ptr()), - Err(_) => continue, - }, - MirSpan::BindingId(b) => { - match source_map - .patterns_for_binding(b) - .iter() - .find_map(|p| source_map.pat_syntax(*p).ok()) - { - Some(s) => s.map(|it| it.syntax_node_ptr()), - None => continue, - } - } - MirSpan::SelfParam => match self_param_syntax { - Some(s) => s.map(|it| it.syntax_node_ptr()), - None => continue, - }, - MirSpan::Unknown => continue, - }; - let file_id = span.file_id.original_file(db); - let text_range = span.value.text_range(); - writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?; - } - } - match err { - MirEvalError::InFunction(..) => unreachable!(), - MirEvalError::LayoutError(err, ty) => { - write!( - f, - "Layout for type `{}` is not available due {err:?}", - ty.as_ref() - .display(db, display_target) - .with_closure_style(ClosureStyle::ClosureWithId) - )?; - } - MirEvalError::MirLowerError(func, err) => { - let function_name = FunctionSignature::of(db, *func); - let self_ = match func.lookup(db).container { - ItemContainerId::ImplId(impl_id) => Some({ - db.impl_self_ty(impl_id) - .instantiate_identity() - .skip_norm_wip() - .display(db, display_target) - .to_string() - }), - ItemContainerId::TraitId(it) => Some( - TraitSignature::of(db, it) - .name - .display(db, display_target.edition) - .to_string(), - ), - _ => None, - }; - writeln!( - f, - "MIR lowering for function `{}{}{}` ({:?}) failed due:", - self_.as_deref().unwrap_or_default(), - if self_.is_some() { "::" } else { "" }, - function_name.name.display(db, display_target.edition), - func - )?; - err.pretty_print(f, db, span_formatter, display_target)?; - } - MirEvalError::ConstEvalError(name, err) => { - MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print( - f, - db, - span_formatter, - display_target, - )?; - } - MirEvalError::UndefinedBehavior(_) - | MirEvalError::TargetDataLayoutNotAvailable(_) - | MirEvalError::Panic(_) - | MirEvalError::MirLowerErrorForClosure(_, _) - | MirEvalError::TypeIsUnsized(_, _) - | MirEvalError::NotSupported(_) - | MirEvalError::InvalidConst - | MirEvalError::ExecutionLimitExceeded - | MirEvalError::StackOverflow - | MirEvalError::CoerceUnsizedError(_) - | MirEvalError::InternalError(_) - | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?, - } - Ok(()) - } - - pub fn is_panic(&self) -> Option<&str> { - let mut err = self; - while let MirEvalError::InFunction(e, _) = err { - err = e; - } - match err { - MirEvalError::Panic(msg) => Some(msg), - _ => None, - } - } -} - impl std::fmt::Debug for MirEvalError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 5a4369623307..0a73389aea5e 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -9,10 +9,9 @@ use rustc_type_ir::inherent::{GenericArgs as _, IntoKind, SliceLike, Ty as _}; use stdx::never; use crate::{ - display::DisplayTarget, drop::{DropGlue, has_drop_glue}, mir::eval::{ - Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay, Interval, + Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, Interval, IntervalAndTy, IntervalOrOwned, IsSigned, ItemContainerId, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported, pad16, }, @@ -786,19 +785,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { "type_name generic arg is not provided".into(), )); }; - let ty_name = match ty.display_source_code( - self.db, - locals.body.owner.module(self.db), - true, - ) { - Ok(ty_name) => ty_name, - // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to - // render full paths. - Err(_) => { - let krate = locals.body.owner.krate(self.db); - ty.display(self.db, DisplayTarget::from_crate(self.db, krate)).to_string() - } - }; + let ty_name = self.db.type_name(ty, locals.body.owner.module(self.db)); let len = ty_name.len(); let addr = self.heap_allocate(len, 1)?; self.write_memory(addr, ty_name.as_bytes())?; diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index ab0c25201a92..b69c877de42b 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1,6 +1,6 @@ //! This module generates a polymorphic MIR from a hir body -use std::{fmt::Write, iter, mem}; +use std::{iter, mem}; use base_db::Crate; use hir_def::{ @@ -10,7 +10,6 @@ use hir_def::{ hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ClosureKind, ExprId, ExprOrPatId, LabelId, Literal, MatchArm, Pat, PatId, RecordLitField, RecordSpread, - generics::GenericParams, }, item_tree::FieldsShape, lang_item::LangItems, @@ -24,14 +23,12 @@ use rustc_apfloat::Float; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; use salsa::SalsaValue; -use span::{Edition, FileId}; -use syntax::TextRange; +use span::Edition; use crate::{ Adjust, Adjustment, AutoBorrow, CallableDefId, InferBodyId, ParamEnvAndCrate, consteval::ConstEvalError, db::{GeneralConstId, HirDatabase, InternedClosure, InternedClosureId}, - display::{DisplayTarget, HirDisplay, hir_display_with_store}, generics::generics, infer::{ CaptureSourceStack, CapturedPlace, UpvarCapture, @@ -61,8 +58,6 @@ use super::{OperandKind, PlaceRef}; mod as_place; mod pattern_matching; -#[cfg(test)] -mod tests; #[derive(Debug, Clone)] struct LoopBlocks { @@ -105,7 +100,10 @@ pub enum MirLowerError<'db> { IncompletePattern, /// Trying to lower a trait function, instead of an implementation TraitFunctionDefinition(TraitId, Name), - UnresolvedName(String), + UnresolvedName { + owner: ExpressionStoreOwnerId, + path: Path, + }, RecordLiteralWithoutPath, UnresolvedMethod(String), UnresolvedField, @@ -168,90 +166,6 @@ impl Drop for DropScopeToken { // } // } -impl MirLowerError<'_> { - pub fn pretty_print( - &self, - f: &mut String, - db: &dyn HirDatabase, - span_formatter: impl Fn(FileId, TextRange) -> String, - display_target: DisplayTarget, - ) -> std::result::Result<(), std::fmt::Error> { - match self { - MirLowerError::ConstEvalError(name, e) => { - writeln!(f, "In evaluating constant {name}")?; - match &**e { - ConstEvalError::MirLowerError(e) => { - e.pretty_print(f, db, span_formatter, display_target)? - } - ConstEvalError::MirEvalError(e) => { - e.pretty_print(f, db, span_formatter, display_target)? - } - } - } - MirLowerError::MissingFunctionDefinition(owner, it) => { - let owner = owner.expression_store_owner(db); - let store = ExpressionStore::of(db, owner); - writeln!( - f, - "Missing function definition for {}", - hir_def::expr_store::pretty::print_expr_hir( - db, - store, - owner, - *it, - display_target.edition - ) - )?; - } - MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?, - MirLowerError::GenericArgNotProvided(id, subst) => { - let param_name = match *id { - GenericParamId::TypeParamId(id) => { - GenericParams::of(db, id.parent())[id.local_id()].name().cloned() - } - GenericParamId::ConstParamId(id) => { - GenericParams::of(db, id.parent())[id.local_id()].name().cloned() - } - GenericParamId::LifetimeParamId(id) => { - Some(GenericParams::of(db, 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) - )?; - writeln!(f, "Provided args: [")?; - for g in subst.as_ref() { - write!(f, " {},", g.display(db, display_target))?; - } - writeln!(f, "]")?; - } - MirLowerError::LayoutError(_) - | MirLowerError::UnsizedTemporary(_) - | MirLowerError::IncompleteExpr - | MirLowerError::IncompletePattern - | MirLowerError::InaccessibleLocal - | MirLowerError::TraitFunctionDefinition(_, _) - | MirLowerError::UnresolvedName(_) - | MirLowerError::RecordLiteralWithoutPath - | MirLowerError::UnresolvedMethod(_) - | MirLowerError::UnresolvedField - | MirLowerError::TypeError(_) - | MirLowerError::NotSupported(_) - | MirLowerError::ContinueWithoutLoop - | MirLowerError::BreakWithoutLoop - | MirLowerError::Loop - | MirLowerError::ImplementationError(_) - | MirLowerError::LangItemNotFound - | MirLowerError::MutatingRvalue - | MirLowerError::UnresolvedLabel - | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?, - } - Ok(()) - } -} - macro_rules! not_supported { ($it: expr) => { return Err(MirLowerError::NotSupported(format!($it))) @@ -271,20 +185,6 @@ impl From for MirLowerError<'_> { } } -impl MirLowerError<'_> { - fn unresolved_path( - db: &dyn HirDatabase, - p: &Path, - display_target: DisplayTarget, - owner: ExpressionStoreOwnerId, - store: &ExpressionStore, - ) -> Self { - Self::UnresolvedName( - hir_display_with_store(p, owner, store).display(db, display_target).to_string(), - ) - } -} - type Result<'db, T> = std::result::Result>; impl<'a, 'db> MirLowerCtx<'a, 'db> { @@ -515,14 +415,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let result = self .resolver .resolve_path_in_value_ns_fully(self.db, p, hygiene) - .ok_or_else(|| { - MirLowerError::unresolved_path( - self.db, - p, - DisplayTarget::from_crate(self.db, self.krate()), - self.owner.expression_store_owner(self.db), - self.store, - ) + .ok_or_else(|| MirLowerError::UnresolvedName { + owner: self.owner.expression_store_owner(self.db), + path: p.clone(), })?; self.resolver.reset_to_guard(resolver_guard); result @@ -890,13 +785,10 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| { - MirLowerError::unresolved_path( - self.db, - path, - self.display_target(), - self.owner.expression_store_owner(self.db), - self.store, - ) + MirLowerError::UnresolvedName { + owner: self.owner.expression_store_owner(self.db), + path: path.clone(), + } })?; let subst = match self.expr_ty_without_adjust(expr_id).kind() { TyKind::Adt(_, s) => s, @@ -1362,16 +1254,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { match &self.store[*loc] { Expr::Literal(l) => self.lower_literal_to_operand(ty, l), Expr::Path(c) => { - let owner = self.owner; - let db = self.db; - let unresolved_name = || { - MirLowerError::unresolved_path( - self.db, - c, - DisplayTarget::from_crate(db, owner.krate(db)), - self.owner.expression_store_owner(self.db), - self.store, - ) + let unresolved_name = || MirLowerError::UnresolvedName { + owner: self.owner.expression_store_owner(self.db), + path: c.clone(), }; let pr = self .resolver @@ -1940,10 +1825,6 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.owner.krate(self.db) } - fn display_target(&self) -> DisplayTarget { - DisplayTarget::from_crate(self.db, self.krate()) - } - fn drop_until_scope( &mut self, scope_index: usize, diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 44f410408a40..9631d1905b45 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -370,14 +370,9 @@ impl<'db> MirLowerCtx<'_, 'db> { mode, )?, None => { - let unresolved_name = || { - MirLowerError::unresolved_path( - self.db, - p, - self.display_target(), - self.owner.expression_store_owner(self.db), - self.store, - ) + let unresolved_name = || MirLowerError::UnresolvedName { + owner: self.owner.expression_store_owner(self.db), + path: p.clone(), }; let hygiene = self.store.pat_path_hygiene(pattern); let pr = self diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 7b2a811a01af..b159865557af 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -340,7 +340,7 @@ pub trait WorldExposer { #[derive(Debug, Copy, Clone)] pub struct DbInterner<'db> { - pub(crate) db: &'db dyn HirDatabase, + pub db: &'db dyn HirDatabase, krate: Option, lang_items: Option<&'db LangItems>, } diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 3765c8c218bc..1f2fae803e5c 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -19,7 +19,7 @@ use crate::{ mir::{IsSigned, pad16}, }; -pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator + '_ { +pub fn fn_traits(lang_items: &LangItems) -> impl Iterator + '_ { [lang_items.Fn, lang_items.FnMut, lang_items.FnOnce].into_iter().flatten() } @@ -93,7 +93,7 @@ pub fn is_fn_unsafe_to_call( } } -pub(crate) fn detect_variant_from_bytes<'a>( +pub fn detect_variant_from_bytes<'a>( layout: &'a Layout, db: &dyn HirDatabase, target_data_layout: &TargetDataLayout, diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index 269029728398..983c39a564b8 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -397,583 +397,3 @@ impl<'db> Context<'db> { self.variances[index] = glb(self.variances[index], variance); } } - -#[cfg(test)] -mod tests { - use expect_test::{Expect, expect}; - use hir_def::{ - AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource, - }; - use itertools::Itertools; - use rustc_type_ir::Variance; - use stdx::format_to; - use syntax::{AstNode, ast::HasName}; - use test_fixture::WithFixture; - - use hir_def::Lookup; - - use crate::{db::HirDatabase, test_db::TestDB, variance::generics}; - - #[test] - fn phantom_data() { - check( - r#" -//- minicore: phantom_data - -struct Covariant { - t: core::marker::PhantomData -} -"#, - expect![[r#" - Covariant[A: covariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_types() { - check( - r#" -//- minicore: cell -#![feature(lang_items)] - -use core::cell::UnsafeCell; - -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR ['a: +, A: o, B: o] - t: &'a mut (A,B) -} - -struct InvariantCell { //~ ERROR [A: o] - t: UnsafeCell -} - -struct InvariantIndirect { //~ ERROR [A: o] - t: InvariantCell -} - -struct Covariant { //~ ERROR [A: +] - t: A, u: fn() -> A -} - -struct Contravariant { //~ ERROR [A: -] - t: fn(A) -} - -enum Enum { //~ ERROR [A: +, B: -, C: o] - Foo(Covariant), - Bar(Contravariant),` - Zed(Covariant,Contravariant) -} - -#[repr(transparent)] -#[lang = "covariant_unsafe_cell"] -pub struct CovariantUnsafeCell(UnsafeCell); //~ ERROR [T: +] -"#, - expect![[r#" - InvariantMut['a: covariant, A: invariant, B: invariant] - InvariantCell[A: invariant] - InvariantIndirect[A: invariant] - Covariant[A: covariant] - Contravariant[A: contravariant] - Enum[A: covariant, B: contravariant, C: invariant] - CovariantUnsafeCell[T: covariant] - "#]], - ); - } - - #[test] - fn type_resolve_error_two_structs_deep() { - check( - r#" -struct Hello<'a> { - missing: Missing<'a>, -} - -struct Other<'a> { - hello: Hello<'a>, -} -"#, - expect![[r#" - Hello['a: bivariant] - Other['a: bivariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_associated_consts() { - check( - r#" -trait Trait { - const Const: usize; -} - -struct Foo { //~ ERROR [T: o] - field: [u8; ::Const] -} -"#, - expect![[r#" - Foo[T: invariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_associated_types() { - check( - r#" -trait Trait<'a> { - type Type; - - fn method(&'a self) { } -} - -struct Foo<'a, T : Trait<'a>> { //~ ERROR ['a: +, T: +] - field: (T, &'a ()) -} - -struct Bar<'a, T : Trait<'a>> { //~ ERROR ['a: o, T: o] - field: >::Type -} - -"#, - expect![[r#" - method[Self: contravariant, 'a: contravariant] - Foo['a: covariant, T: covariant] - Bar['a: invariant, T: invariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_associated_types2() { - // FIXME: RPITs have variance, but we can't treat them as their own thing right now - check( - r#" -trait Foo { - type Bar; -} - -fn make() -> *const dyn Foo {} -"#, - expect![""], - ); - } - - #[test] - fn rustc_test_variance_trait_bounds() { - check( - r#" -trait Getter { - fn get(&self) -> T; -} - -trait Setter { - fn get(&self, _: T); -} - -struct TestStruct> { //~ ERROR [U: +, T: +] - t: T, u: U -} - -enum TestEnum> { //~ ERROR [U: *, T: +] - //~^ ERROR: `U` is never used - Foo(T) -} - -struct TestContraStruct> { //~ ERROR [U: *, T: +] - //~^ ERROR: `U` is never used - t: T -} - -struct TestBox+Setter> { //~ ERROR [U: *, T: +] - //~^ ERROR: `U` is never used - t: T -} -"#, - expect![[r#" - get[Self: contravariant, T: covariant] - get[Self: contravariant, T: contravariant] - TestStruct[U: covariant, T: covariant] - TestEnum[U: bivariant, T: covariant] - TestContraStruct[U: bivariant, T: covariant] - TestBox[U: bivariant, T: covariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_trait_matching() { - check( - r#" - -trait Get { - fn get(&self) -> T; -} - -struct Cloner { - t: T -} - -impl Get for Cloner { - fn get(&self) -> T {} -} - -fn get<'a, G>(get: &G) -> i32 - where G : Get<&'a i32> -{} - -fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32 - where G : Get<&'b i32> -{} -"#, - expect![[r#" - get[Self: contravariant, T: covariant] - Cloner[T: covariant] - get[T: invariant] - get['a: invariant, G: contravariant] - pick['b: contravariant, G: contravariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_trait_object_bound() { - check( - r#" -enum Option { - Some(T), - None -} -trait T { fn foo(&self); } - -struct TOption<'a> { //~ ERROR ['a: +] - v: Option<*const (dyn T + 'a)>, -} -"#, - expect![[r#" - Option[T: covariant] - foo[Self: contravariant] - TOption['a: covariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_types_bounds() { - check( - r#" -//- minicore: send -struct TestImm { //~ ERROR [A: +, B: +] - x: A, - y: B, -} - -struct TestMut { //~ ERROR [A: +, B: o] - x: A, - y: &'static mut B, -} - -struct TestIndirect { //~ ERROR [A: +, B: o] - m: TestMut -} - -struct TestIndirect2 { //~ ERROR [A: o, B: o] - n: TestMut, - m: TestMut -} - -trait Getter { - fn get(&self) -> A; -} - -trait Setter { - fn set(&mut self, a: A); -} - -struct TestObject { //~ ERROR [A: o, R: o] - n: *const (dyn Setter + Send), - m: *const (dyn Getter + Send), -} -"#, - expect![[r#" - TestImm[A: covariant, B: covariant] - TestMut[A: covariant, B: invariant] - TestIndirect[A: covariant, B: invariant] - TestIndirect2[A: invariant, B: invariant] - get[Self: contravariant, A: covariant] - set[Self: invariant, A: contravariant] - TestObject[A: invariant, R: invariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_unused_region_param() { - check( - r#" -struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used -enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used -trait SomeTrait<'a> { fn foo(&self); } // OK on traits. -"#, - expect![[r#" - SomeStruct['a: bivariant] - SomeEnum['a: bivariant] - foo[Self: contravariant, 'a: invariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_unused_type_param() { - check( - r#" -//- minicore: sized -struct SomeStruct { x: u32 } -enum SomeEnum { Nothing } -enum ListCell { - Cons(*const ListCell), - Nil -} - -struct SelfTyAlias(*const Self); -struct WithBounds {} -struct WithWhereBounds where T: Sized {} -struct WithOutlivesBounds {} -struct DoubleNothing { - s: SomeStruct, -} - -"#, - expect![[r#" - SomeStruct[A: bivariant] - SomeEnum[A: bivariant] - ListCell[T: bivariant] - SelfTyAlias[T: bivariant] - WithBounds[T: bivariant] - WithWhereBounds[T: bivariant] - WithOutlivesBounds[T: bivariant] - DoubleNothing[T: bivariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_use_contravariant_struct1() { - check( - r#" -struct SomeStruct(fn(T)); - -fn foo<'min,'max>(v: SomeStruct<&'max ()>) - -> SomeStruct<&'min ()> - where 'max : 'min -{} -"#, - expect![[r#" - SomeStruct[T: contravariant] - foo['min: contravariant, 'max: covariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_use_contravariant_struct2() { - check( - r#" -struct SomeStruct(fn(T)); - -fn bar<'min,'max>(v: SomeStruct<&'min ()>) - -> SomeStruct<&'max ()> - where 'max : 'min -{} -"#, - expect![[r#" - SomeStruct[T: contravariant] - bar['min: covariant, 'max: contravariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_use_covariant_struct1() { - check( - r#" -struct SomeStruct(T); - -fn foo<'min,'max>(v: SomeStruct<&'min ()>) - -> SomeStruct<&'max ()> - where 'max : 'min -{} -"#, - expect![[r#" - SomeStruct[T: covariant] - foo['min: contravariant, 'max: covariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_use_covariant_struct2() { - check( - r#" -struct SomeStruct(T); - -fn foo<'min,'max>(v: SomeStruct<&'max ()>) - -> SomeStruct<&'min ()> - where 'max : 'min -{} -"#, - expect![[r#" - SomeStruct[T: covariant] - foo['min: covariant, 'max: contravariant] - "#]], - ); - } - - #[test] - fn rustc_test_variance_use_invariant_struct1() { - check( - r#" -struct SomeStruct(*mut T); - -fn foo<'min,'max>(v: SomeStruct<&'max ()>) - -> SomeStruct<&'min ()> - where 'max : 'min -{} - -fn bar<'min,'max>(v: SomeStruct<&'min ()>) - -> SomeStruct<&'max ()> - where 'max : 'min -{} -"#, - expect![[r#" - SomeStruct[T: invariant] - foo['min: invariant, 'max: invariant] - bar['min: invariant, 'max: invariant] - "#]], - ); - } - - #[test] - fn invalid_arg_counts() { - check( - r#" -struct S(T); -struct S2(S<>); -struct S3(S); -"#, - expect![[r#" - S[T: covariant] - S2[T: bivariant] - S3[T: covariant] - "#]], - ); - } - - #[test] - fn prove_fixedpoint() { - check( - r#" -struct FixedPoint(&'static FixedPoint<(), T, U>, V); -"#, - expect![[r#" - FixedPoint[T: covariant, U: covariant, V: covariant] - "#]], - ); - } - - #[track_caller] - fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) { - // use tracing_subscriber::{layer::SubscriberExt, Layer}; - // let my_layer = tracing_subscriber::fmt::layer(); - // let _g = tracing::subscriber::set_default(tracing_subscriber::registry().with( - // my_layer.with_filter(tracing_subscriber::filter::filter_fn(|metadata| { - // metadata.target().starts_with("hir_ty::variance") - // })), - // )); - let (db, file_id) = TestDB::with_single_file(ra_fixture); - - 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, &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(_) - | GenericDefId::TypeAliasId(_) - | GenericDefId::ImplId(_) - | GenericDefId::ConstId(_) - | GenericDefId::StaticId(_) => return None, - }, - )) - }) - .sorted_by_key(|(_, n)| n.syntax().text_range().start()); - let mut res = String::new(); - for (def, name) in defs { - let variances = db.variances_of(def); - if variances.is_empty() { - continue; - } - format_to!( - res, - "{name}[{}]\n", - generics(&db, def) - .iter(false) - .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!( - "{}: {}", - name.as_str(), - match var { - Variance::Covariant => "covariant", - Variance::Invariant => "invariant", - Variance::Contravariant => "contravariant", - Variance::Bivariant => "bivariant", - }, - ))) - ); - } - - expected.assert_eq(&res); - }) - } -} diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index a9575a93dbee..876c142edec4 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -31,7 +31,7 @@ base-db.workspace = true cfg.workspace = true hir-def.workspace = true hir-expand.workspace = true -hir-ty.workspace = true +hir-ide.workspace = true intern.workspace = true stdx.workspace = true syntax.workspace = true diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index c58b4ba66810..c25e565b3c23 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -16,7 +16,7 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::Name, }; -use hir_ty::{ +use hir_ide::{ db::HirDatabase, method_resolution::{self, CandidateId, MethodError, MethodResolutionContext}, next_solver::{DbInterner, TypingMode, infer::DbInternerInferExt}, @@ -239,8 +239,8 @@ impl HasAttrs for Function { impl HasAttrs for Impl { fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner { match self.id { - hir_ty::next_solver::AnyImplId::ImplId(id) => AttrsOwner::AttrDef(id.into()), - hir_ty::next_solver::AnyImplId::BuiltinDeriveImplId(..) => AttrsOwner::Dummy, + hir_ide::next_solver::AnyImplId::ImplId(id) => AttrsOwner::AttrDef(id.into()), + hir_ide::next_solver::AnyImplId::BuiltinDeriveImplId(..) => AttrsOwner::Dummy, } } } @@ -506,8 +506,8 @@ fn resolve_impl_trait_item<'db>( traits_in_scope: &traits_in_scope, edition: krate.data(db).edition, features, - call_span: hir_ty::Span::Dummy, - receiver_span: hir_ty::Span::Dummy, + call_span: hir_ide::Span::Dummy, + receiver_span: hir_ide::Span::Dummy, }; let resolution = ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty.ty.skip_binder()); diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 28af06a0ec9c..fbee49d1bb0a 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs @@ -4,4 +4,4 @@ //! //! But we need this for at least LRU caching at the query level. pub use hir_def::{file_item_tree, set_expand_proc_attr_macros}; -pub use hir_ty::db::HirDatabase; +pub use hir_ide::db::HirDatabase; diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 9a2f1fd11d6a..ddcd117a274e 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -15,7 +15,7 @@ use hir_def::{ type_ref::TypeRefId, }; use hir_expand::{HirFileId, InFile, mod_path::ModPath, name::Name}; -use hir_ty::{ +use hir_ide::{ CastError, ExplicitDropMethodUseKind, InferenceDiagnostic, InferenceTyDiagnosticSource, PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic, db::HirDatabase, @@ -35,7 +35,7 @@ use triomphe::Arc; use crate::{AssocItem, Field, Function, GenericDef, Trait, Type, TypeOwnerId, Variant}; pub use hir_def::VariantId; -pub use hir_ty::{ +pub use hir_ide::{ GenericArgsProhibitedReason, IncorrectGenericsLenKind, ReturnKind, diagnostics::{CaseType, IncorrectCase}, }; @@ -1345,20 +1345,20 @@ impl<'db> AnyDiagnostic<'db> { } fn span_syntax( - span: hir_ty::Span, + span: hir_ide::Span, source_map: &ExpressionStoreSourceMap, ) -> Option>> { Some(match span { - hir_ty::Span::ExprId(idx) => Self::expr_syntax(idx, source_map)?.map(|it| it.upcast()), - hir_ty::Span::PatId(idx) => Self::pat_syntax(idx, source_map)?.map(|it| it.upcast()), - hir_ty::Span::TypeRefId(idx) => { + hir_ide::Span::ExprId(idx) => Self::expr_syntax(idx, source_map)?.map(|it| it.upcast()), + hir_ide::Span::PatId(idx) => Self::pat_syntax(idx, source_map)?.map(|it| it.upcast()), + hir_ide::Span::TypeRefId(idx) => { Self::type_syntax(idx, source_map)?.map(|it| it.upcast()) } - hir_ty::Span::BindingId(idx) => { + hir_ide::Span::BindingId(idx) => { let &pat = source_map.patterns_for_binding(idx).first()?; Self::pat_syntax(pat, source_map)?.map(|it| it.upcast()) } - hir_ty::Span::Dummy => { + hir_ide::Span::Dummy => { never!("should never create a diagnostic for dummy spans"); return None; } diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 61eda80fb487..a07a869458d9 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -17,7 +17,7 @@ use hir_def::{ visibility::Visibility, }; use hir_expand::name::Name; -use hir_ty::{ +use hir_ide::{ GenericPredicates, db::HirDatabase, display::{ @@ -78,7 +78,7 @@ fn write_builtin_derive_impl_method<'db>( write!(f, "\n // Bounds from impl:")?; let predicates = - hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder(); + hir_ide::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder(); write_params_bounds(f, &Vec::from_iter(predicates))?; } diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 9b07aa494e44..c9f8517a36c4 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -9,7 +9,7 @@ use hir_def::{ hir::{BindingId, LabelId}, item_scope::ItemInNs as ItemInNsId, }; -use hir_ty::next_solver::AnyImplId; +use hir_ide::next_solver::AnyImplId; use stdx::impl_from; use crate::{ @@ -43,7 +43,7 @@ from_id![ (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), (crate::AnyFunctionId, crate::Function), - (hir_ty::next_solver::AnyImplId, crate::Impl), + (hir_ide::next_solver::AnyImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), (hir_def::TypeParamId, crate::TypeParam), (hir_def::ConstParamId, crate::ConstParam), diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 3a6e19636a0b..0ade6ba69367 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -8,7 +8,7 @@ use hir_def::{ src::{HasChildSource, HasSource as _}, }; use hir_expand::{EditionedFileId, HirFileId, InFile}; -use hir_ty::{db::InternedClosure, next_solver::AnyImplId}; +use hir_ide::{db::InternedClosure, next_solver::AnyImplId}; use syntax::{AstNode, ast}; use tt::TextRange; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8f747e397c87..23cf14d95f6f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -83,7 +83,7 @@ use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, builtin::BuiltinDeriveExpander, proc_macro::ProcMacroKind, }; -use hir_ty::{ +use hir_ide::{ GenericPredicates, InferBodyId, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, @@ -96,6 +96,7 @@ use hir_ty::{ layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution::{self, InherentImpls, MethodResolutionContext}, mir::interpret_mir, + mir_pretty::{MirBodyPretty as _, MirEvalErrorPretty as _}, next_solver::{ AliasTy, AnyImplId, ClauseKind, DbInterner, EarlyBinder, ErrorGuaranteed, FnSig, GenericArg, GenericArgs, ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, @@ -205,22 +206,24 @@ pub use { tt, }, // FIXME: Properly encapsulate mir - hir_ty::mir, - hir_ty::{ + hir_ide::mir, + hir_ide::{ CastError, PointerCast, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, drop::DropGlue, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, + impl_hir_database, layout::LayoutError, mir::{MirEvalError, MirLowerError}, + mir_pretty::ConstEvalErrorPretty, next_solver::abi::Safety, next_solver::{clear_tls_solver_cache, collect_ty_garbage}, setup_tracing, }, // FIXME: These are needed for import assets, properly encapsulate them. - hir_ty::{method_resolution::TraitImpls, next_solver::SimplifiedType}, + hir_ide::{method_resolution::TraitImpls, next_solver::SimplifiedType}, intern::{Symbol, sym}, }; @@ -233,7 +236,7 @@ use { name::AsName, span_map::{ExpansionSpanMap, RealSpanMap, SpanMap}, }, - hir_ty::next_solver, + hir_ide::next_solver, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -497,7 +500,7 @@ impl ModuleDef { def.diagnostics(db, &mut acc, style_lints); } None => { - for diag in hir_ty::diagnostics::incorrect_case(db, id) { + for diag in hir_ide::diagnostics::incorrect_case(db, id) { acc.push(diag.into()) } } @@ -1012,7 +1015,7 @@ impl Module { AssocItem::Const(it) => it.id.into(), AssocItem::TypeAlias(it) => it.id.into(), }; - !hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item) + !hir_ide::dyn_compatibility::generics_require_sized_self(db, assoc_item) }); } } @@ -2063,7 +2066,7 @@ impl DefWithBody { )); } - let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, id); + let missing_unsafe = hir_ide::diagnostics::missing_unsafe(db, id); for (node, reason) in missing_unsafe.unsafe_exprs { match source_map.expr_or_pat_syntax(node) { Ok(node) => acc.push( @@ -2102,7 +2105,7 @@ impl DefWithBody { acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, source_map)); } - for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) { + for diag in hir_ide::diagnostics::incorrect_case(db, id.into()) { acc.push(diag.into()) } } @@ -2480,30 +2483,30 @@ impl Function { let (target_features, target_feature_is_safe_in_target) = caller .map(|caller| { let target_features = match caller.id { - AnyFunctionId::FunctionId(id) => hir_ty::TargetFeatures::from_fn(db, id), + AnyFunctionId::FunctionId(id) => hir_ide::TargetFeatures::from_fn(db, id), AnyFunctionId::BuiltinDeriveImplMethod { .. } => { - hir_ty::TargetFeatures::default() + hir_ide::TargetFeatures::default() } }; let target_feature_is_safe_in_target = match &caller.krate(db).id.workspace_data(db).target { - Ok(target) => hir_ty::target_feature_is_safe_in_target(target), - Err(_) => hir_ty::TargetFeatureIsSafeInTarget::No, + Ok(target) => hir_ide::target_feature_is_safe_in_target(target), + Err(_) => hir_ide::TargetFeatureIsSafeInTarget::No, }; (target_features, target_feature_is_safe_in_target) }) .unwrap_or_else(|| { - (hir_ty::TargetFeatures::default(), hir_ty::TargetFeatureIsSafeInTarget::No) + (hir_ide::TargetFeatures::default(), hir_ide::TargetFeatureIsSafeInTarget::No) }); matches!( - hir_ty::is_fn_unsafe_to_call( + hir_ide::is_fn_unsafe_to_call( db, id, &target_features, call_edition, target_feature_is_safe_in_target ), - hir_ty::Unsafety::Unsafe + hir_ide::Unsafety::Unsafe ) } @@ -2573,7 +2576,7 @@ impl Function { } } -// Note: logically, this belongs to `hir_ty`, but we are not using it there yet. +// Note: logically, this belongs to `hir_ide`, but we are not using it there yet. #[derive(Clone, Copy, PartialEq, Eq)] pub enum Access { Shared, @@ -2581,11 +2584,11 @@ pub enum Access { Owned, } -impl From for Access { - fn from(mutability: hir_ty::next_solver::Mutability) -> Access { +impl From for Access { + fn from(mutability: hir_ide::next_solver::Mutability) -> Access { match mutability { - hir_ty::next_solver::Mutability::Not => Access::Shared, - hir_ty::next_solver::Mutability::Mut => Access::Exclusive, + hir_ide::next_solver::Mutability::Not => Access::Shared, + hir_ide::next_solver::Mutability::Mut => Access::Exclusive, } } } @@ -2835,7 +2838,7 @@ impl HasVisibility for Const { pub struct EvaluatedConst<'db> { def: InferBodyId<'db>, - allocation: hir_ty::next_solver::Allocation<'db>, + allocation: hir_ide::next_solver::Allocation<'db>, ty: Ty<'db>, } @@ -2985,7 +2988,7 @@ impl Trait { } pub fn dyn_compatibility(&self, db: &dyn HirDatabase) -> Option { - hir_ty::dyn_compatibility::dyn_compatibility(db, self.id) + hir_ide::dyn_compatibility::dyn_compatibility(db, self.id) } pub fn dyn_compatibility_all_violations( @@ -2993,7 +2996,7 @@ impl Trait { db: &dyn HirDatabase, ) -> Option> { let mut violations = vec![]; - _ = hir_ty::dyn_compatibility::dyn_compatibility_with_callback( + _ = hir_ide::dyn_compatibility::dyn_compatibility_with_callback( db, self.id, &mut |violation| { @@ -3105,7 +3108,7 @@ impl BuiltinType { pub fn i32() -> BuiltinType { BuiltinType { - inner: hir_def::builtin_type::BuiltinType::Int(hir_ty::primitive::BuiltinInt::I32), + inner: hir_def::builtin_type::BuiltinType::Int(hir_ide::primitive::BuiltinInt::I32), } } @@ -3715,7 +3718,7 @@ impl AssocItem { db.type_for_type_alias_with_diagnostics(type_alias.id).diagnostics(), &TypeAliasSignature::with_source_map(db, type_alias.id).1, ); - for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { + for diag in hir_ide::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); } } @@ -4315,9 +4318,9 @@ impl GenericParam { GenericParam::LifetimeParam(it) => it.id.parent, }; let index = match self { - GenericParam::TypeParam(it) => hir_ty::type_or_const_param_idx(db, it.id.into()), + GenericParam::TypeParam(it) => hir_ide::type_or_const_param_idx(db, it.id.into()), GenericParam::ConstParam(_) => return None, - GenericParam::LifetimeParam(it) => hir_ty::lifetime_param_idx(db, it.id), + GenericParam::LifetimeParam(it) => hir_ide::lifetime_param_idx(db, it.id), }; db.variances_of(parent).get(index as usize).map(Into::into) } @@ -4390,7 +4393,7 @@ impl TypeParam { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let interner = DbInterner::new_no_crate(db); - let index = hir_ty::type_or_const_param_idx(db, self.id.into()); + let index = hir_ide::type_or_const_param_idx(db, self.id.into()); let ty = Ty::new_param(interner, self.id, index); Type::new(self.id.parent(), ty) } @@ -4495,7 +4498,7 @@ impl ConstParam { } fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option> { - let local_idx = hir_ty::type_or_const_param_idx(db, id); + let local_idx = hir_ide::type_or_const_param_idx(db, id); let defaults = db.generic_defaults(id.parent); let ty = defaults.get(local_idx as usize)?; // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. @@ -4686,7 +4689,7 @@ impl Impl { let loc = id.loc(db); let krate = loc.module(db).krate(db); let interner = DbInterner::new_with(db, krate); - let trait_ref = hir_ty::builtin_derive::impl_trait(interner, id) + let trait_ref = hir_ide::builtin_derive::impl_trait(interner, id) .instantiate_identity() .skip_norm_wip(); Some(TraitRef { owner: TypeOwnerId::BuiltinDeriveImplId(id), trait_ref }) @@ -4705,7 +4708,7 @@ impl Impl { let krate = loc.module(db).krate(db); let interner = DbInterner::new_with(db, krate); let ty = - hir_ty::builtin_derive::impl_trait(interner, id).map_bound(|it| it.self_ty()); + hir_ide::builtin_derive::impl_trait(interner, id).map_bound(|it| it.self_ty()); Type { owner: TypeOwnerId::BuiltinDeriveImplId(id), ty } } } @@ -4769,11 +4772,11 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { owner: TypeOwnerId<'db>, - trait_ref: hir_ty::next_solver::TraitRef<'db>, + trait_ref: hir_ide::next_solver::TraitRef<'db>, } impl<'db> TraitRef<'db> { - fn new(owner: GenericDefId, trait_ref: hir_ty::next_solver::TraitRef<'db>) -> Self { + fn new(owner: GenericDefId, trait_ref: hir_ide::next_solver::TraitRef<'db>) -> Self { Self { owner: TypeOwnerId::GenericDefId(owner), trait_ref } } @@ -4958,7 +4961,7 @@ pub struct ClosureCapture<'db> { owner: ExpressionStoreOwnerId, infer_owner: InferBodyId<'db>, closure: ExprId, - capture: &'db hir_ty::closure_analysis::CapturedPlace, + capture: &'db hir_ide::closure_analysis::CapturedPlace, } impl<'db> ClosureCapture<'db> { @@ -4972,11 +4975,9 @@ impl<'db> ClosureCapture<'db> { /// Returns whether this place has any field (aka. non-deref) projections. pub fn has_field_projections(&self) -> bool { - self.capture - .place - .projections - .iter() - .any(|proj| matches!(proj.kind, hir_ty::closure_analysis::ProjectionKind::Field { .. })) + self.capture.place.projections.iter().any(|proj| { + matches!(proj.kind, hir_ide::closure_analysis::ProjectionKind::Field { .. }) + }) } pub fn usages(&self) -> CaptureUsages<'db> { @@ -4985,16 +4986,16 @@ impl<'db> ClosureCapture<'db> { pub fn kind(&self) -> CaptureKind { match self.capture.info.capture_kind { - hir_ty::closure_analysis::UpvarCapture::ByValue => CaptureKind::Move, - hir_ty::closure_analysis::UpvarCapture::ByUse => CaptureKind::SharedRef, // Good enough? - hir_ty::closure_analysis::UpvarCapture::ByRef( - hir_ty::closure_analysis::BorrowKind::Immutable, + hir_ide::closure_analysis::UpvarCapture::ByValue => CaptureKind::Move, + hir_ide::closure_analysis::UpvarCapture::ByUse => CaptureKind::SharedRef, // Good enough? + hir_ide::closure_analysis::UpvarCapture::ByRef( + hir_ide::closure_analysis::BorrowKind::Immutable, ) => CaptureKind::SharedRef, - hir_ty::closure_analysis::UpvarCapture::ByRef( - hir_ty::closure_analysis::BorrowKind::UniqueImmutable, + hir_ide::closure_analysis::UpvarCapture::ByRef( + hir_ide::closure_analysis::BorrowKind::UniqueImmutable, ) => CaptureKind::UniqueSharedRef, - hir_ty::closure_analysis::UpvarCapture::ByRef( - hir_ty::closure_analysis::BorrowKind::Mutable, + hir_ide::closure_analysis::UpvarCapture::ByRef( + hir_ide::closure_analysis::BorrowKind::Mutable, ) => CaptureKind::MutableRef, } } @@ -5004,8 +5005,8 @@ impl<'db> ClosureCapture<'db> { let mut result = self.local().name(db).display(db, edition).to_string(); for (i, proj) in self.capture.place.projections.iter().enumerate() { match proj.kind { - hir_ty::closure_analysis::ProjectionKind::Deref => {} - hir_ty::closure_analysis::ProjectionKind::Field { field_idx, variant_idx } => { + hir_ide::closure_analysis::ProjectionKind::Deref => {} + hir_ide::closure_analysis::ProjectionKind::Field { field_idx, variant_idx } => { let ty = self.capture.place.ty_before_projection(i); match ty.kind() { TyKind::Tuple(_) => format_to!(result, "_{field_idx}"), @@ -5036,8 +5037,8 @@ impl<'db> ClosureCapture<'db> { let mut last_derefs = 0; for (i, proj) in self.capture.place.projections.iter().enumerate() { match proj.kind { - hir_ty::closure_analysis::ProjectionKind::Deref => last_derefs += 1, - hir_ty::closure_analysis::ProjectionKind::Field { field_idx, variant_idx } => { + hir_ide::closure_analysis::ProjectionKind::Deref => last_derefs += 1, + hir_ide::closure_analysis::ProjectionKind::Field { field_idx, variant_idx } => { last_derefs = 0; let ty = self.capture.place.ty_before_projection(i); @@ -5088,7 +5089,7 @@ pub enum CaptureKind { #[derive(Debug, Clone)] pub struct CaptureUsages<'db> { parent: ExpressionStoreOwnerId, - sources: &'db [hir_ty::closure_analysis::CaptureSourceStack], + sources: &'db [hir_ide::closure_analysis::CaptureSourceStack], } impl CaptureUsages<'_> { @@ -5249,7 +5250,7 @@ impl<'db> PartialEq for Type<'db> { if self.ty != other.ty { return false; } - hir_ty::with_attached_db(|db| { + hir_ide::with_attached_db(|db| { self.owner.can_rebase_into(db, other.owner, self.ty) || other.owner.can_rebase_into(db, self.owner, other.ty) }) @@ -5355,7 +5356,7 @@ impl<'db> Type<'db> { let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _, _| { *var_for_param .entry(param) - .or_insert_with(|| infcx.var_for_def(param, hir_ty::Span::Dummy)) + .or_insert_with(|| infcx.var_for_def(param, hir_ide::Span::Dummy)) }); ty.ty.instantiate(infcx.interner, args).skip_norm_wip() @@ -5470,7 +5471,7 @@ impl<'db> Type<'db> { pub fn is_mutable_reference(&self) -> bool { matches!( self.ty.skip_binder().kind(), - TyKind::Ref(.., hir_ty::next_solver::Mutability::Mut) + TyKind::Ref(.., hir_ide::next_solver::Mutability::Mut) ) } @@ -5564,7 +5565,7 @@ impl<'db> Type<'db> { pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> { let TyKind::Ref(_lt, ty, m) = self.ty.skip_binder().kind() else { return None }; - let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); + let m = Mutability::from_mutable(matches!(m, hir_ide::next_solver::Mutability::Mut)); Some((self.derived(ty), m)) } @@ -5575,8 +5576,8 @@ impl<'db> Type<'db> { pub fn add_reference(&self, db: &'db dyn HirDatabase, mutability: Mutability) -> Self { let interner = DbInterner::new_no_crate(db); let ty_mutability = match mutability { - Mutability::Shared => hir_ty::next_solver::Mutability::Not, - Mutability::Mut => hir_ty::next_solver::Mutability::Mut, + Mutability::Shared => hir_ide::next_solver::Mutability::Not, + Mutability::Mut => hir_ide::next_solver::Mutability::Mut, }; self.derived(Ty::new_ref( interner, @@ -5656,7 +5657,7 @@ impl<'db> Type<'db> { ParamEnvAndCrate { param_env: db.trait_environment(def), krate } } TypeOwnerId::BuiltinDeriveImplId(def) => ParamEnvAndCrate { - param_env: hir_ty::builtin_derive::param_env(interner, def), + param_env: hir_ide::builtin_derive::param_env(interner, def), krate, }, TypeOwnerId::AnonConstId(def) => ParamEnvAndCrate { @@ -5799,7 +5800,7 @@ impl<'db> Type<'db> { { arg.into() } else { - infcx.var_for_def(param, hir_ty::Span::Dummy) + infcx.var_for_def(param, hir_ide::Span::Dummy) } }) }) @@ -5851,7 +5852,7 @@ impl<'db> Type<'db> { _ => { let env = self.param_env(db); let (fn_trait, sig) = - hir_ty::callable_sig_from_fn_trait(self.ty.skip_binder(), env, db)?; + hir_ide::callable_sig_from_fn_trait(self.ty.skip_binder(), env, db)?; return Some(Callable { ty: self.clone(), sig, @@ -5914,14 +5915,14 @@ impl<'db> Type<'db> { // Used outside of rust-analyzer (e.g. by `ra_ap_hir` consumers). matches!( self.ty.skip_binder().kind(), - TyKind::RawPtr(.., hir_ty::next_solver::Mutability::Mut) + TyKind::RawPtr(.., hir_ide::next_solver::Mutability::Mut) ) } pub fn as_raw_ptr(&self) -> Option<(Type<'db>, Mutability)> { // Used outside of rust-analyzer (e.g. by `ra_ap_hir` consumers). let TyKind::RawPtr(ty, m) = self.ty.skip_binder().kind() else { return None }; - let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); + let m = Mutability::from_mutable(matches!(m, hir_ide::next_solver::Mutability::Mut)); Some((self.derived(ty), m)) } @@ -6002,7 +6003,7 @@ impl<'db> Type<'db> { let interner = DbInterner::new_no_crate(db); let env = self.param_env(db); // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty.skip_binder()); + let canonical = hir_ide::replace_errors_with_variables(interner, &self.ty.skip_binder()); autoderef(db, env, canonical) } @@ -6216,8 +6217,8 @@ impl<'db> Type<'db> { traits_in_scope, edition: resolver.krate().data(db).edition, features, - call_span: hir_ty::Span::Dummy, - receiver_span: hir_ty::Span::Dummy, + call_span: hir_ide::Span::Dummy, + receiver_span: hir_ide::Span::Dummy, }; f(&ctx) } @@ -6244,8 +6245,8 @@ impl<'db> Type<'db> { self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { // There should be no inference vars in types passed here let canonical = - hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); - let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); + hir_ide::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); + let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ide::Span::Dummy, &canonical); match name { Some(name) => { @@ -6353,8 +6354,8 @@ impl<'db> Type<'db> { self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { // There should be no inference vars in types passed here let canonical = - hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); - let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); + hir_ide::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); + let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ide::Span::Dummy, &canonical); match name { Some(name) => { @@ -6430,7 +6431,7 @@ impl<'db> Type<'db> { let _p = tracing::info_span!("applicable_inherent_traits").entered(); self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) - .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db, dyn_trait_id)) + .flat_map(move |dyn_trait_id| hir_ide::all_super_traits(db, dyn_trait_id)) .copied() .map(Trait::from) } @@ -6448,7 +6449,7 @@ impl<'db> Type<'db> { ClauseKind::Trait(tr) if tr.self_ty() == ty => Some(tr.def_id().0), _ => None, }) - .flat_map(|t| hir_ty::all_super_traits(db, t)) + .flat_map(|t| hir_ide::all_super_traits(db, t)) .copied() }) .map(Trait::from) @@ -6521,11 +6522,11 @@ impl<'db> Type<'db> { self.owner.must_unify(other.owner); let env = self.param_env(db); let interner = DbInterner::new_no_crate(db); - let tys = hir_ty::replace_errors_with_variables( + let tys = hir_ide::replace_errors_with_variables( interner, &(self.ty.skip_binder(), other.ty.skip_binder()), ); - hir_ty::could_unify(db, env, &tys) + hir_ide::could_unify(db, env, &tys) } /// Check if type unifies with another type eagerly making sure there are no unresolved goals. @@ -6536,22 +6537,22 @@ impl<'db> Type<'db> { self.owner.must_unify(other.owner); let env = self.param_env(db); let interner = DbInterner::new_no_crate(db); - let tys = hir_ty::replace_errors_with_variables( + let tys = hir_ide::replace_errors_with_variables( interner, &(self.ty.skip_binder(), other.ty.skip_binder()), ); - hir_ty::could_unify_deeply(db, env, &tys) + hir_ide::could_unify_deeply(db, env, &tys) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { self.owner.must_unify(to.owner); let env = self.param_env(db); let interner = DbInterner::new_no_crate(db); - let tys = hir_ty::replace_errors_with_variables( + let tys = hir_ide::replace_errors_with_variables( interner, &(self.ty.skip_binder(), to.ty.skip_binder()), ); - hir_ty::could_coerce(db, env, &tys) + hir_ide::could_coerce(db, env, &tys) } pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option { @@ -6563,7 +6564,7 @@ impl<'db> Type<'db> { /// Returns unique `GenericParam`s contained in this type. pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet { - hir_ty::collect_params(&self.ty.skip_binder()) + hir_ide::collect_params(&self.ty.skip_binder()) .into_iter() .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() @@ -6579,7 +6580,7 @@ impl<'db> Type<'db> { let env = self.param_env(db); let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - hir_ty::drop::has_drop_glue(&infcx, self.ty.skip_binder(), env.param_env) + hir_ide::drop::has_drop_glue(&infcx, self.ty.skip_binder(), env.param_env) } } @@ -6946,7 +6947,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { - inner: hir_ty::next_solver::TraitPredicate<'db>, + inner: hir_ide::next_solver::TraitPredicate<'db>, owner: TypeOwnerId<'db>, } @@ -7397,7 +7398,7 @@ fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) .filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_))) .map(|(local_id, _)| TypeOrConstParamId { parent: generic_def, local_id }) .any(|param| { - let param = hir_ty::type_or_const_param_idx(db, param); + let param = hir_ide::type_or_const_param_idx(db, param); defaults.get(param as usize).is_none() }) } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index f298e25489a5..46d12be5f228 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -30,7 +30,7 @@ use hir_expand::{ mod_path::{ModPath, PathKind}, name::AsName, }; -use hir_ty::{ +use hir_ide::{ InferBodyId, InferenceResult, LoweringMode, db::AnonConstId, diagnostics::unsafe_operations, @@ -1724,8 +1724,8 @@ impl<'db> SemanticsImpl<'db> { pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option>> { let mutability = |m| match m { - hir_ty::next_solver::Mutability::Not => Mutability::Shared, - hir_ty::next_solver::Mutability::Mut => Mutability::Mut, + hir_ide::next_solver::Mutability::Not => Mutability::Shared, + hir_ide::next_solver::Mutability::Mut => Mutability::Mut, }; let analyzer = self.analyze(expr.syntax())?; @@ -1737,20 +1737,20 @@ impl<'db> SemanticsImpl<'db> { .map(|adjust| { let target = analyzer.ty(adjust.target.as_ref()); let kind = match adjust.kind { - hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, - hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { + hir_ide::Adjust::NeverToAny => Adjust::NeverToAny, + hir_ide::Adjust::Deref(Some(hir_ide::OverloadedDeref(m))) => { // FIXME: Should we handle unknown mutability better? Adjust::Deref(Some(OverloadedDeref(mutability(m)))) } - hir_ty::Adjust::Deref(None) => Adjust::Deref(None), - hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { + hir_ide::Adjust::Deref(None) => Adjust::Deref(None), + hir_ide::Adjust::Borrow(hir_ide::AutoBorrow::RawPtr(m)) => { Adjust::Borrow(AutoBorrow::RawPtr(mutability(m))) } - hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => { + hir_ide::Adjust::Borrow(hir_ide::AutoBorrow::Ref(m)) => { // FIXME: Handle lifetimes here Adjust::Borrow(AutoBorrow::Ref(mutability(m.into()))) } - hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc), + hir_ide::Adjust::Pointer(pc) => Adjust::Pointer(pc), }; // Update `source_ty` for the next adjustment @@ -1827,7 +1827,7 @@ impl<'db> SemanticsImpl<'db> { let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) }; let interner = DbInterner::new_no_crate(self.db); let mut subst = subst.into_iter(); - let substs = hir_ty::next_solver::GenericArgs::for_item( + let substs = hir_ide::next_solver::GenericArgs::for_item( interner, trait_.id.into(), |_, id, _, _| { @@ -2589,7 +2589,7 @@ impl<'db> SemanticsImpl<'db> { && let Some(tree) = proof_tree { let data = - dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt); + dump_proof_tree_structured(tree, hir_ide::Span::Dummy, infer_ctxt); RESULT.with(|ctx| ctx.borrow_mut().push(data)); } }), @@ -2849,7 +2849,7 @@ impl<'db> SemanticsScope<'db> { else { return; }; - hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| { + hir_ide::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| { cb(id.into()); false }); diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 907193fe1d7f..db314add090b 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -33,7 +33,7 @@ use hir_expand::{ mod_path::{ModPath, PathKind, path}, name::{AsName, Name}, }; -use hir_ty::{ +use hir_ide::{ Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, LifetimeLoweringMode, ParamEnvAndCrate, TyLoweringContext, TyLoweringInferVarsCtx, diagnostics::{ @@ -482,8 +482,8 @@ impl<'db> SourceAnalyzer<'db> { } impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> { - fn next_ty_var(&mut self, span: hir_ty::Span) -> Ty<'db> { - if let hir_ty::Span::TypeRefId(type_ref) = span + fn next_ty_var(&mut self, span: hir_ide::Span) -> Ty<'db> { + if let hir_ide::Span::TypeRefId(type_ref) = span && let Some(ty) = self.infer.and_then(|infer| infer.type_of_type_placeholder(type_ref)) { @@ -492,10 +492,10 @@ impl<'db> SourceAnalyzer<'db> { self.types.types.error } } - fn next_const_var(&mut self, _span: hir_ty::Span) -> hir_ty::next_solver::Const<'db> { + fn next_const_var(&mut self, _span: hir_ide::Span) -> hir_ide::next_solver::Const<'db> { self.types.consts.error } - fn next_region_var(&mut self, _span: hir_ty::Span) -> Region<'db> { + fn next_region_var(&mut self, _span: hir_ide::Span) -> Region<'db> { self.types.regions.error } } @@ -604,11 +604,11 @@ impl<'db> SourceAnalyzer<'db> { let id = self.pat_id(&pat.clone().into())?; let infer = self.infer()?; Some(match infer.binding_mode(id.as_pat()?)? { - hir_ty::BindingMode(hir_ty::ByRef::No, _) => BindingMode::Move, - hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Mut), _) => { + hir_ide::BindingMode(hir_ide::ByRef::No, _) => BindingMode::Move, + hir_ide::BindingMode(hir_ide::ByRef::Yes(hir_ide::next_solver::Mutability::Mut), _) => { BindingMode::Ref(Mutability::Mut) } - hir_ty::BindingMode(hir_ty::ByRef::Yes(hir_ty::next_solver::Mutability::Not), _) => { + hir_ide::BindingMode(hir_ide::ByRef::Yes(hir_ide::next_solver::Mutability::Not), _) => { BindingMode::Ref(Mutability::Shared) } }) @@ -1943,7 +1943,7 @@ fn resolve_hir_path_<'db>( Some(unresolved) => resolver .generic_def() .and_then(|def| { - hir_ty::associated_type_shorthand_candidates( + hir_ide::associated_type_shorthand_candidates( db, def, res.in_type_ns()?, @@ -2143,7 +2143,7 @@ fn resolve_hir_path_qualifier<'db>( Some(unresolved) => resolver .generic_def() .and_then(|def| { - hir_ty::associated_type_shorthand_candidates( + hir_ide::associated_type_shorthand_candidates( db, def, res.in_type_ns()?, diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index b458dc0f1046..4fc95f369240 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -16,7 +16,7 @@ use hir_def::{ visibility::{Visibility, VisibilityExplicitness}, }; use hir_expand::{HirFileId, name::Name}; -use hir_ty::{ +use hir_ide::{ db::HirDatabase, display::{HirDisplay, hir_display_with_store}, }; diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs index 0a5d95d6136b..2166d9ef9e71 100644 --- a/crates/hir/src/term_search.rs +++ b/crates/hir/src/term_search.rs @@ -1,7 +1,7 @@ //! Term search use hir_def::type_ref::Mutability; -use hir_ty::db::HirDatabase; +use hir_ide::db::HirDatabase; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; diff --git a/crates/hir/src/term_search/expr.rs b/crates/hir/src/term_search/expr.rs index 07994268696e..dc6a6b269744 100644 --- a/crates/hir/src/term_search/expr.rs +++ b/crates/hir/src/term_search/expr.rs @@ -2,7 +2,7 @@ use hir_def::FindPathConfig; use hir_expand::mod_path::ModPath; -use hir_ty::{ +use hir_ide::{ db::HirDatabase, display::{DisplaySourceCodeError, DisplayTarget, HirDisplay}, }; diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index b89921d8000c..dab80c28c4c3 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -10,7 +10,7 @@ use std::iter; -use hir_ty::db::HirDatabase; +use hir_ide::db::HirDatabase; use itertools::Itertools; use rustc_hash::FxHashSet; diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index e37c2f084560..db414d6c3356 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -183,6 +183,8 @@ impl SourceDatabase for RootDatabase { } } +hir::impl_hir_database!(RootDatabase); + impl Default for RootDatabase { fn default() -> RootDatabase { RootDatabase::new(None) diff --git a/crates/ide/src/interpret.rs b/crates/ide/src/interpret.rs index f8e8d874492c..53175fe2f110 100644 --- a/crates/ide/src/interpret.rs +++ b/crates/ide/src/interpret.rs @@ -1,4 +1,4 @@ -use hir::{ConstEvalError, DefWithBody, DisplayTarget, Semantics}; +use hir::{ConstEvalError, ConstEvalErrorPretty as _, DefWithBody, DisplayTarget, Semantics}; use ide_db::{FilePosition, RootDatabase, base_db::SourceDatabase, line_index}; use std::time::{Duration, Instant}; use stdx::format_to; diff --git a/crates/macros/src/extension.rs b/crates/macros/src/extension.rs new file mode 100644 index 000000000000..96f4e92825d1 --- /dev/null +++ b/crates/macros/src/extension.rs @@ -0,0 +1,158 @@ +//! A macro to implement extension traits conveniently. + +use proc_macro2::Ident; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::{ + Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, Token, TraitItem, + TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, WhereClause, + braced, parse_macro_input, +}; + +pub(crate) fn extension( + attr: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); + let Impl { attrs, generics, self_ty, items, wc } = parse_macro_input!(input as Impl); + let headers: Vec<_> = items + .iter() + .map(|item| match item { + ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn { + attrs: scrub_attrs(&f.attrs), + sig: scrub_header(f.sig.clone()), + default: None, + semi_token: Some(Token![;](f.block.span())), + }), + ImplItem::Const(ct) => TraitItem::Const(TraitItemConst { + attrs: scrub_attrs(&ct.attrs), + const_token: ct.const_token, + ident: ct.ident.clone(), + generics: ct.generics.clone(), + colon_token: ct.colon_token, + ty: ct.ty.clone(), + default: None, + semi_token: ct.semi_token, + }), + ImplItem::Type(ty) => TraitItem::Type(TraitItemType { + attrs: scrub_attrs(&ty.attrs), + type_token: ty.type_token, + ident: ty.ident.clone(), + generics: ty.generics.clone(), + colon_token: None, + bounds: Punctuated::new(), + default: None, + semi_token: ty.semi_token, + }), + ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro { + attrs: scrub_attrs(&mac.attrs), + mac: mac.mac.clone(), + semi_token: mac.semi_token, + }), + ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()), + _ => unimplemented!(), + }) + .collect(); + + quote! { + #(#attrs)* + #[rust_analyzer::prefer_underscore_import] + #vis trait #trait_ { + #(#headers)* + } + + impl #generics #trait_ for #self_ty #wc { + #(#items)* + } + } + .into() +} + +/// Only keep `#[doc]` attrs. +fn scrub_attrs(attrs: &[Attribute]) -> Vec { + attrs + .iter() + .filter(|attr| { + let ident = &attr.path().segments[0].ident; + ident == "doc" || ident == "must_use" + }) + .cloned() + .collect() +} + +/// Scrub arguments so that they're valid for trait signatures. +fn scrub_header(mut sig: Signature) -> Signature { + for (idx, input) in sig.inputs.iter_mut().enumerate() { + match input { + syn::FnArg::Receiver(rcvr) => { + // `mut self` -> `self` + if rcvr.reference.is_none() { + rcvr.mutability.take(); + } + } + syn::FnArg::Typed(arg) => match &mut *arg.pat { + Pat::Ident(arg) => { + // `ref mut ident @ pat` -> `ident` + arg.by_ref.take(); + arg.mutability.take(); + arg.subpat.take(); + } + _ => { + // `pat` -> `__arg0` + *arg.pat = PatIdent { + attrs: vec![], + by_ref: None, + mutability: None, + ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()), + subpat: None, + } + .into(); + } + }, + } + } + sig +} + +struct ExtensionAttr { + vis: Visibility, + trait_: Path, +} + +impl Parse for ExtensionAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + let vis = input.parse()?; + let _: Token![trait] = input.parse()?; + let trait_ = input.parse()?; + Ok(ExtensionAttr { vis, trait_ }) + } +} + +struct Impl { + attrs: Vec, + generics: Generics, + self_ty: Type, + items: Vec, + wc: Option, +} + +impl Parse for Impl { + fn parse(input: ParseStream<'_>) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + let _: Token![impl] = input.parse()?; + let generics = input.parse()?; + let self_ty = input.parse()?; + let wc = input.parse()?; + + let content; + let _brace_token = braced!(content in input); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(Impl { attrs, generics, self_ty, items, wc }) + } +} diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index 9088efeca4fb..10d4282cbf7b 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -1,5 +1,8 @@ //! Proc macros for rust-analyzer. +mod extension; + +use proc_macro::TokenStream; use quote::{ToTokens, quote}; use syn::parse_quote; use synstructure::decl_derive; @@ -235,3 +238,22 @@ fn upmap_from_ra_fixture(mut s: synstructure::Structure<'_>) -> proc_macro2::Tok }, ) } + +/// Derive an extension trait for a given impl block. The trait name +/// goes into the parenthesized args of the macro, for greppability. +/// For example: +/// ``` +/// use macros::extension; +/// #[extension(pub trait Foo)] +/// impl i32 { fn hello() {} } +/// ``` +/// +/// expands to: +/// ``` +/// pub trait Foo { fn hello(); } +/// impl Foo for i32 { fn hello() {} } +/// ``` +#[proc_macro_attribute] +pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { + extension::extension(attr, input) +}