Unnamed repository; edit this file 'description' to name the repository.
Merge ref '2dc30247c5d8' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref: 2dc30247c5d8293aaa31e1d7dae2ed2fde908ada Filtered ref: dab12aee0f52f7b83cc62ae565855c731bed502f Upstream diff: https://github.com/rust-lang/rust/compare/47cd7120d9b4e1b64eb27c87522a07888197fae8...2dc30247c5d8293aaa31e1d7dae2ed2fde908ada This merge was created using https://github.com/rust-lang/josh-sync.
The rustc-josh-sync Cronjob Bot 4 months ago
parent 7b9cee6 · parent 874a0a1 · commit 11de170
-rw-r--r--.github/workflows/rustdoc.yaml1
-rw-r--r--crates/base-db/Cargo.toml4
-rw-r--r--crates/base-db/src/lib.rs27
-rw-r--r--crates/cfg/Cargo.toml4
-rw-r--r--crates/cfg/src/lib.rs5
-rw-r--r--crates/hir-def/src/attrs.rs16
-rw-r--r--crates/hir-def/src/db.rs23
-rw-r--r--crates/hir-def/src/expr_store.rs2
-rw-r--r--crates/hir-def/src/expr_store/lower.rs914
-rw-r--r--crates/hir-def/src/expr_store/lower/format_args.rs1012
-rw-r--r--crates/hir-def/src/expr_store/tests/body.rs102
-rw-r--r--crates/hir-def/src/expr_store/tests/body/block.rs18
-rw-r--r--crates/hir-def/src/expr_store/tests/signatures.rs12
-rw-r--r--crates/hir-def/src/find_path.rs114
-rw-r--r--crates/hir-def/src/hir/generics.rs2
-rw-r--r--crates/hir-def/src/import_map.rs23
-rw-r--r--crates/hir-def/src/item_scope.rs31
-rw-r--r--crates/hir-def/src/lang_item.rs9
-rw-r--r--crates/hir-def/src/lib.rs180
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe.rs16
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs7
-rw-r--r--crates/hir-def/src/macro_expansion_tests/proc_macros.rs19
-rw-r--r--crates/hir-def/src/nameres.rs237
-rw-r--r--crates/hir-def/src/nameres/assoc.rs18
-rw-r--r--crates/hir-def/src/nameres/attr_resolution.rs4
-rw-r--r--crates/hir-def/src/nameres/collector.rs265
-rw-r--r--crates/hir-def/src/nameres/diagnostics.rs29
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs111
-rw-r--r--crates/hir-def/src/nameres/tests/incremental.rs29
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs10
-rw-r--r--crates/hir-def/src/resolver.rs49
-rw-r--r--crates/hir-def/src/signatures.rs4
-rw-r--r--crates/hir-def/src/src.rs4
-rw-r--r--crates/hir-def/src/test_db.rs12
-rw-r--r--crates/hir-def/src/visibility.rs87
-rw-r--r--crates/hir-expand/src/builtin/attr_macro.rs5
-rw-r--r--crates/hir-expand/src/cfg_process.rs24
-rw-r--r--crates/hir-expand/src/files.rs2
-rw-r--r--crates/hir-expand/src/hygiene.rs8
-rw-r--r--crates/hir-expand/src/lib.rs4
-rw-r--r--crates/hir-ty/src/autoderef.rs37
-rw-r--r--crates/hir-ty/src/consteval.rs27
-rw-r--r--crates/hir-ty/src/consteval/tests.rs2
-rw-r--r--crates/hir-ty/src/db.rs24
-rw-r--r--crates/hir-ty/src/diagnostics/decl_check.rs2
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs12
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs24
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--crates/hir-ty/src/display.rs161
-rw-r--r--crates/hir-ty/src/drop.rs33
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs36
-rw-r--r--crates/hir-ty/src/dyn_compatibility/tests.rs2
-rw-r--r--crates/hir-ty/src/infer.rs25
-rw-r--r--crates/hir-ty/src/infer/autoderef.rs4
-rw-r--r--crates/hir-ty/src/infer/closure.rs17
-rw-r--r--crates/hir-ty/src/infer/closure/analysis.rs8
-rw-r--r--crates/hir-ty/src/infer/coerce.rs49
-rw-r--r--crates/hir-ty/src/infer/expr.rs36
-rw-r--r--crates/hir-ty/src/infer/op.rs2
-rw-r--r--crates/hir-ty/src/infer/opaques.rs2
-rw-r--r--crates/hir-ty/src/infer/path.rs4
-rw-r--r--crates/hir-ty/src/infer/place_op.rs2
-rw-r--r--crates/hir-ty/src/infer/unify.rs41
-rw-r--r--crates/hir-ty/src/inhabitedness.rs18
-rw-r--r--crates/hir-ty/src/layout.rs20
-rw-r--r--crates/hir-ty/src/layout/adt.rs8
-rw-r--r--crates/hir-ty/src/layout/tests.rs28
-rw-r--r--crates/hir-ty/src/lib.rs9
-rw-r--r--crates/hir-ty/src/lower.rs24
-rw-r--r--crates/hir-ty/src/method_resolution.rs54
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs2
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs12
-rw-r--r--crates/hir-ty/src/mir.rs9
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs35
-rw-r--r--crates/hir-ty/src/mir/eval.rs44
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs2
-rw-r--r--crates/hir-ty/src/mir/eval/tests.rs11
-rw-r--r--crates/hir-ty/src/mir/lower.rs18
-rw-r--r--crates/hir-ty/src/mir/lower/tests.rs61
-rw-r--r--crates/hir-ty/src/mir/monomorphization.rs26
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs4
-rw-r--r--crates/hir-ty/src/next_solver/infer/traits.rs4
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs28
-rw-r--r--crates/hir-ty/src/next_solver/predicate.rs4
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs89
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs2
-rw-r--r--crates/hir-ty/src/next_solver/util.rs8
-rw-r--r--crates/hir-ty/src/opaques.rs4
-rw-r--r--crates/hir-ty/src/specialization.rs8
-rw-r--r--crates/hir-ty/src/test_db.rs4
-rw-r--r--crates/hir-ty/src/tests.rs18
-rw-r--r--crates/hir-ty/src/tests/closure_captures.rs4
-rw-r--r--crates/hir-ty/src/tests/incremental.rs28
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs29
-rw-r--r--crates/hir-ty/src/tests/regression/new_solver.rs56
-rw-r--r--crates/hir-ty/src/tests/traits.rs20
-rw-r--r--crates/hir-ty/src/traits.rs73
-rw-r--r--crates/hir-ty/src/variance.rs2
-rw-r--r--crates/hir/src/attrs.rs16
-rw-r--r--crates/hir/src/db.rs37
-rw-r--r--crates/hir/src/display.rs86
-rw-r--r--crates/hir/src/has_source.rs18
-rw-r--r--crates/hir/src/lib.rs336
-rw-r--r--crates/hir/src/semantics.rs78
-rw-r--r--crates/hir/src/semantics/child_by_source.rs5
-rw-r--r--crates/hir/src/semantics/source_to_def.rs10
-rw-r--r--crates/hir/src/source_analyzer.rs26
-rw-r--r--crates/hir/src/symbols.rs32
-rw-r--r--crates/hir/src/term_search/tactics.rs2
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs2
-rw-r--r--crates/ide-assists/src/handlers/add_missing_match_arms.rs35
-rw-r--r--crates/ide-assists/src/handlers/apply_demorgan.rs2
-rw-r--r--crates/ide-assists/src/handlers/auto_import.rs9
-rw-r--r--crates/ide-assists/src/handlers/bind_unused_param.rs14
-rw-r--r--crates/ide-assists/src/handlers/convert_bool_to_enum.rs7
-rw-r--r--crates/ide-assists/src/handlers/convert_for_to_while_let.rs71
-rw-r--r--crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs2
-rw-r--r--crates/ide-assists/src/handlers/convert_into_to_from.rs6
-rw-r--r--crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs22
-rw-r--r--crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs8
-rw-r--r--crates/ide-assists/src/handlers/convert_while_to_loop.rs224
-rw-r--r--crates/ide-assists/src/handlers/destructure_struct_binding.rs7
-rw-r--r--crates/ide-assists/src/handlers/expand_glob_import.rs8
-rw-r--r--crates/ide-assists/src/handlers/extract_function.rs5
-rw-r--r--crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs3
-rw-r--r--crates/ide-assists/src/handlers/fix_visibility.rs4
-rw-r--r--crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs2
-rw-r--r--crates/ide-assists/src/handlers/generate_default_from_new.rs2
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_methods.rs2
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_trait.rs451
-rw-r--r--crates/ide-assists/src/handlers/generate_deref.rs14
-rw-r--r--crates/ide-assists/src/handlers/generate_fn_type_alias.rs32
-rw-r--r--crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs2
-rw-r--r--crates/ide-assists/src/handlers/generate_function.rs17
-rw-r--r--crates/ide-assists/src/handlers/generate_new.rs6
-rw-r--r--crates/ide-assists/src/handlers/generate_single_field_struct_from.rs4
-rw-r--r--crates/ide-assists/src/handlers/inline_call.rs4
-rw-r--r--crates/ide-assists/src/handlers/inline_macro.rs2
-rw-r--r--crates/ide-assists/src/handlers/qualify_method_call.rs4
-rw-r--r--crates/ide-assists/src/handlers/qualify_path.rs2
-rw-r--r--crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs4
-rw-r--r--crates/ide-assists/src/handlers/replace_method_eager_lazy.rs93
-rw-r--r--crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs2
-rw-r--r--crates/ide-assists/src/handlers/term_search.rs2
-rw-r--r--crates/ide-assists/src/handlers/toggle_async_sugar.rs2
-rw-r--r--crates/ide-assists/src/handlers/toggle_ignore.rs35
-rw-r--r--crates/ide-assists/src/lib.rs4
-rw-r--r--crates/ide-assists/src/utils.rs24
-rw-r--r--crates/ide-completion/Cargo.toml4
-rw-r--r--crates/ide-completion/src/completions.rs2
-rw-r--r--crates/ide-completion/src/completions/attribute/derive.rs2
-rw-r--r--crates/ide-completion/src/completions/attribute/macro_use.rs2
-rw-r--r--crates/ide-completion/src/completions/format_string.rs94
-rw-r--r--crates/ide-completion/src/completions/item_list/trait_impl.rs37
-rw-r--r--crates/ide-completion/src/completions/keyword.rs54
-rw-r--r--crates/ide-completion/src/context/analysis.rs12
-rw-r--r--crates/ide-completion/src/item.rs2
-rw-r--r--crates/ide-completion/src/lib.rs9
-rw-r--r--crates/ide-completion/src/render/variant.rs2
-rw-r--r--crates/ide-completion/src/tests/attribute.rs52
-rw-r--r--crates/ide-completion/src/tests/flyimport.rs2
-rw-r--r--crates/ide-db/Cargo.toml4
-rw-r--r--crates/ide-db/src/defs.rs8
-rw-r--r--crates/ide-db/src/famous_defs.rs2
-rw-r--r--crates/ide-db/src/helpers.rs2
-rw-r--r--crates/ide-db/src/imports/import_assets.rs2
-rw-r--r--crates/ide-db/src/lib.rs5
-rw-r--r--crates/ide-db/src/path_transform.rs6
-rw-r--r--crates/ide-db/src/rename.rs2
-rw-r--r--crates/ide-db/src/search.rs20
-rw-r--r--crates/ide-db/src/symbol_index.rs79
-rw-r--r--crates/ide-db/src/test_data/test_doc_alias.txt29
-rw-r--r--crates/ide-db/src/test_data/test_symbol_index_collection.txt137
-rw-r--r--crates/ide-db/src/test_data/test_symbols_exclude_imports.txt3
-rw-r--r--crates/ide-db/src/test_data/test_symbols_with_imports.txt6
-rw-r--r--crates/ide-db/src/traits.rs2
-rw-r--r--crates/ide-diagnostics/Cargo.toml4
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_case.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_fields.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_unsafe.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs6
-rw-r--r--crates/ide-diagnostics/src/handlers/no_such_field.rs31
-rw-r--r--crates/ide-diagnostics/src/handlers/private_field.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/unlinked_file.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/unused_variables.rs55
-rw-r--r--crates/ide-diagnostics/src/lib.rs136
-rw-r--r--crates/ide-ssr/Cargo.toml4
-rw-r--r--crates/ide-ssr/src/lib.rs5
-rw-r--r--crates/ide/src/expand_macro.rs2
-rw-r--r--crates/ide/src/goto_definition.rs4
-rw-r--r--crates/ide/src/goto_implementation.rs2
-rw-r--r--crates/ide/src/hover/render.rs2
-rw-r--r--crates/ide/src/hover/tests.rs57
-rw-r--r--crates/ide/src/inlay_hints.rs4
-rw-r--r--crates/ide/src/inlay_hints/placeholders.rs20
-rw-r--r--crates/ide/src/interpret.rs2
-rw-r--r--crates/ide/src/moniker.rs9
-rw-r--r--crates/ide/src/navigation_target.rs10
-rw-r--r--crates/ide/src/runnables.rs6
-rw-r--r--crates/ide/src/static_index.rs25
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html2
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs2
-rw-r--r--crates/ide/src/test_explorer.rs6
-rw-r--r--crates/intern/src/symbol/symbols.rs1
-rw-r--r--crates/load-cargo/src/lib.rs6
-rw-r--r--crates/parser/src/lib.rs9
-rw-r--r--crates/paths/src/lib.rs4
-rw-r--r--crates/proc-macro-api/Cargo.toml2
-rw-r--r--crates/proc-macro-api/src/legacy_protocol/msg.rs185
-rw-r--r--crates/proc-macro-api/src/legacy_protocol/msg/flat.rs28
-rw-r--r--crates/proc-macro-api/src/lib.rs4
-rw-r--r--crates/proc-macro-api/src/process.rs4
-rw-r--r--crates/proc-macro-srv/src/lib.rs29
-rw-r--r--crates/proc-macro-srv/src/token_stream.rs7
-rw-r--r--crates/project-model/Cargo.toml4
-rw-r--r--crates/project-model/src/cargo_workspace.rs2
-rw-r--r--crates/project-model/src/lib.rs11
-rw-r--r--crates/project-model/src/project_json.rs2
-rw-r--r--crates/project-model/src/workspace.rs2
-rw-r--r--crates/rust-analyzer/Cargo.toml10
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs16
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs10
-rw-r--r--crates/rust-analyzer/src/cli/run_tests.rs2
-rw-r--r--crates/rust-analyzer/src/cli/scip.rs23
-rw-r--r--crates/rust-analyzer/src/cli/unresolved_references.rs10
-rw-r--r--crates/rust-analyzer/src/command.rs18
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/discover.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs26
-rw-r--r--crates/rust-analyzer/src/handlers/notification.rs2
-rw-r--r--crates/rust-analyzer/src/lib.rs5
-rw-r--r--crates/rust-analyzer/src/lsp/capabilities.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop.rs105
-rw-r--r--crates/rust-analyzer/src/reload.rs4
-rw-r--r--crates/rust-analyzer/src/task_pool.rs14
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs4
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs1
-rw-r--r--crates/span/Cargo.toml1
-rw-r--r--crates/span/src/ast_id.rs3
-rw-r--r--crates/span/src/hygiene.rs4
-rw-r--r--crates/span/src/lib.rs33
-rw-r--r--crates/syntax-bridge/src/lib.rs5
-rw-r--r--crates/syntax/Cargo.toml1
-rw-r--r--crates/syntax/src/ast/make.rs99
-rw-r--r--crates/syntax/src/ast/node_ext.rs11
-rw-r--r--crates/syntax/src/ast/syntax_factory/constructors.rs219
-rw-r--r--crates/syntax/src/lib.rs7
-rw-r--r--crates/test-fixture/Cargo.toml4
-rw-r--r--crates/test-fixture/src/lib.rs6
-rw-r--r--crates/test-utils/src/assert_linear.rs2
-rw-r--r--crates/test-utils/src/fixture.rs13
-rw-r--r--crates/test-utils/src/minicore.rs51
-rw-r--r--crates/tt/Cargo.toml1
-rw-r--r--crates/tt/src/lib.rs3
-rw-r--r--docs/book/README.md1
-rw-r--r--docs/book/book.toml5
-rw-r--r--docs/book/src/configuration_generated.md7
-rw-r--r--docs/book/src/contributing/README.md2
-rw-r--r--docs/book/src/contributing/architecture.md2
-rw-r--r--docs/book/src/contributing/guide.md2
-rw-r--r--docs/book/src/contributing/lsp-extensions.md2
-rw-r--r--docs/book/src/other_editors.md2
-rw-r--r--editors/code/package-lock.json38
-rw-r--r--editors/code/package.json10
-rw-r--r--rust-version2
-rw-r--r--triagebot.toml3
269 files changed, 5280 insertions, 3369 deletions
diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml
index f975bbaa51..9cc18fc69e 100644
--- a/.github/workflows/rustdoc.yaml
+++ b/.github/workflows/rustdoc.yaml
@@ -8,6 +8,7 @@ env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUSTFLAGS: "-D warnings -W unreachable-pub"
+ RUSTDOCFLAGS: "-D warnings"
RUSTUP_MAX_RETRIES: 10
jobs:
diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml
index ea06fd9c48..55dfcbc7e5 100644
--- a/crates/base-db/Cargo.toml
+++ b/crates/base-db/Cargo.toml
@@ -31,5 +31,9 @@ vfs.workspace = true
span.workspace = true
intern.workspace = true
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index 9793892410..aa06cdefe6 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -1,5 +1,10 @@
//! base_db defines basic database traits. The concrete DB is defined by ide.
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
pub use salsa;
pub use salsa_macros;
@@ -59,6 +64,28 @@ macro_rules! impl_intern_key {
};
}
+/// # SAFETY
+///
+/// `old_pointer` must be valid for unique writes
+pub unsafe fn unsafe_update_eq<T>(old_pointer: *mut T, new_value: T) -> bool
+where
+ T: PartialEq,
+{
+ // SAFETY: Caller obligation
+ let old_ref: &mut T = unsafe { &mut *old_pointer };
+
+ if *old_ref != new_value {
+ *old_ref = new_value;
+ true
+ } else {
+ // Subtle but important: Eq impls can be buggy or define equality
+ // in surprising ways. If it says that the value has not changed,
+ // we do not modify the existing value, and thus do not have to
+ // update the revision, as downstream code will not see the new value.
+ false
+ }
+}
+
pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16;
pub const DEFAULT_PARSE_LRU_CAP: u16 = 128;
pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024;
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index 9e2a95dbf3..7207cfcf7d 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -33,5 +33,9 @@ syntax.workspace = true
# tt is needed for testing
cfg = { path = ".", default-features = false, features = ["tt"] }
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index b1ec4c273a..3e3d67cb4a 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -1,5 +1,10 @@
//! cfg defines conditional compiling options, `cfg` attribute parser and evaluator
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
mod cfg_expr;
mod dnf;
#[cfg(test)]
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs
index ab36b707f2..febc794b5a 100644
--- a/crates/hir-def/src/attrs.rs
+++ b/crates/hir-def/src/attrs.rs
@@ -45,8 +45,8 @@ use syntax::{
use tt::{TextRange, TextSize};
use crate::{
- AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, InternedModuleId,
- LifetimeParamId, LocalFieldId, MacroId, TypeOrConstParamId, VariantId,
+ AdtId, AstIdLoc, AttrDefId, FieldId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
+ LocalFieldId, MacroId, ModuleId, TypeOrConstParamId, VariantId,
db::DefDatabase,
hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
nameres::ModuleOrigin,
@@ -155,6 +155,9 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal
"rustc_skip_during_method_dispatch" => {
extract_rustc_skip_during_method_dispatch(attr_flags, tt)
}
+ "rustc_deprecated_safe_2024" => {
+ attr_flags.insert(AttrFlags::RUSTC_DEPRECATED_SAFE_2024)
+ }
_ => {}
},
2 => match path.segments[0].text() {
@@ -295,9 +298,8 @@ fn attrs_source(
) -> (InFile<ast::AnyHasAttrs>, Option<InFile<ast::Module>>, Crate) {
let (owner, krate) = match owner {
AttrDefId::ModuleId(id) => {
- let id = id.loc(db);
let def_map = id.def_map(db);
- let (definition, declaration) = match def_map[id.local_id].origin {
+ let (definition, declaration) = match def_map[id].origin {
ModuleOrigin::CrateRoot { definition } => {
let file = db.parse(definition).tree();
(InFile::new(definition.into(), ast::AnyHasAttrs::from(file)), None)
@@ -318,7 +320,7 @@ fn attrs_source(
(block.with_value(definition.into()), None)
}
};
- return (definition, declaration, id.krate);
+ return (definition, declaration, def_map.krate());
}
AttrDefId::AdtId(AdtId::StructId(it)) => attrs_from_ast_id_loc(db, it),
AttrDefId::AdtId(AdtId::UnionId(it)) => attrs_from_ast_id_loc(db, it),
@@ -1201,14 +1203,14 @@ impl AttrFlags {
}
#[inline]
- pub fn doc_keyword(db: &dyn DefDatabase, owner: InternedModuleId) -> Option<Symbol> {
+ pub fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option<Symbol> {
if !AttrFlags::query(db, AttrDefId::ModuleId(owner)).contains(AttrFlags::HAS_DOC_KEYWORD) {
return None;
}
return doc_keyword(db, owner);
#[salsa::tracked]
- fn doc_keyword(db: &dyn DefDatabase, owner: InternedModuleId) -> Option<Symbol> {
+ fn doc_keyword(db: &dyn DefDatabase, owner: ModuleId) -> Option<Symbol> {
collect_attrs(db, AttrDefId::ModuleId(owner), |attr| {
if let Meta::TokenTree { path, tt } = attr
&& path.is1("doc")
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index cc311a41db..ccd4bc9be8 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -8,13 +8,12 @@ use la_arena::ArenaMap;
use triomphe::Arc;
use crate::{
- AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, CrateRootModuleId, DefWithBodyId,
- EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
- ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, HasModule, ImplId, ImplLoc,
- InternedModuleId, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
- MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId,
- StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc,
- VariantId,
+ AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
+ EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
+ FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
+ MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
+ ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
+ TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
attrs::AttrFlags,
expr_store::{
Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
@@ -276,8 +275,8 @@ fn include_macro_invoc(
}
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
- let root_module = CrateRootModuleId::from(crate_id).module(db);
- let attrs = AttrFlags::query(db, AttrDefId::ModuleId(InternedModuleId::new(db, root_module)));
+ let root_module = crate_def_map(db, crate_id).root_module_id();
+ let attrs = AttrFlags::query(db, AttrDefId::ModuleId(root_module));
attrs.contains(AttrFlags::IS_NO_STD)
}
@@ -298,7 +297,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
let loc: Macro2Loc = it.lookup(db);
MacroDefId {
- krate: loc.container.krate,
+ krate: loc.container.krate(db),
kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
local_inner: false,
allow_internal_unsafe: loc.allow_internal_unsafe,
@@ -309,7 +308,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
let loc: MacroRulesLoc = it.lookup(db);
MacroDefId {
- krate: loc.container.krate,
+ krate: loc.container.krate(db),
kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
allow_internal_unsafe: loc
@@ -322,7 +321,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
let loc = it.lookup(db);
MacroDefId {
- krate: loc.container.krate,
+ krate: loc.container.krate(db),
kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
local_inner: false,
allow_internal_unsafe: false,
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 5695ab7ed0..66f7e25ffa 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -43,7 +43,7 @@ pub use self::lower::{
hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment,
};
-/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
+/// A wrapper around [`span::SyntaxContext`] that is intended only for comparisons.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HygieneId(span::SyntaxContext);
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 26a50b5325..42b076abb2 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -2,6 +2,7 @@
//! representation.
mod asm;
+mod format_args;
mod generics;
mod path;
@@ -19,7 +20,7 @@ use intern::{Symbol, sym};
use rustc_hash::FxHashMap;
use stdx::never;
use syntax::{
- AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
+ AstNode, AstPtr, SyntaxNodePtr,
ast::{
self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,
HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem,
@@ -34,7 +35,6 @@ use crate::{
AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,
attrs::AttrFlags,
- builtin_type::BuiltinUint,
db::DefDatabase,
expr_store::{
Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
@@ -47,13 +47,7 @@ use crate::{
hir::{
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId,
- RecordFieldPat, RecordLitField, Statement,
- format_args::{
- self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
- FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
- FormatPlaceholder, FormatSign, FormatTrait,
- },
- generics::GenericParams,
+ RecordFieldPat, RecordLitField, Statement, generics::GenericParams,
},
item_scope::BuiltinShadowMode,
item_tree::FieldsShape,
@@ -434,9 +428,12 @@ pub struct ExprCollector<'db> {
current_try_block_label: Option<LabelId>,
label_ribs: Vec<LabelRib>,
- current_binding_owner: Option<ExprId>,
+ unowned_bindings: Vec<BindingId>,
awaitable_context: Option<Awaitable>,
+ krate: base_db::Crate,
+
+ name_generator_index: usize,
}
#[derive(Clone, Debug)]
@@ -524,9 +521,10 @@ impl<'db> ExprCollector<'db> {
) -> ExprCollector<'_> {
let (def_map, local_def_map) = module.local_def_map(db);
let expander = Expander::new(db, current_file_id, def_map);
+ let krate = module.krate(db);
ExprCollector {
db,
- cfg_options: module.krate().cfg_options(db),
+ cfg_options: krate.cfg_options(db),
module,
def_map,
local_def_map,
@@ -536,16 +534,24 @@ impl<'db> ExprCollector<'db> {
current_try_block_label: None,
is_lowering_coroutine: false,
label_ribs: Vec::new(),
- current_binding_owner: None,
+ unowned_bindings: Vec::new(),
awaitable_context: None,
current_block_legacy_macro_defs_count: FxHashMap::default(),
outer_impl_trait: false,
+ krate,
+ name_generator_index: 0,
}
}
+ fn generate_new_name(&mut self) -> Name {
+ let index = self.name_generator_index;
+ self.name_generator_index += 1;
+ Name::generate_new_name(index)
+ }
+
#[inline]
pub(crate) fn lang_items(&self) -> &'db LangItems {
- self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.module.krate))
+ self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate()))
}
#[inline]
@@ -946,7 +952,8 @@ impl<'db> ExprCollector<'db> {
node: ast::TypeBound,
impl_trait_lower_fn: ImplTraitLowerFn<'_>,
) -> TypeBound {
- match node.kind() {
+ let Some(kind) = node.kind() else { return TypeBound::Error };
+ match kind {
ast::TypeBoundKind::PathType(binder, path_type) => {
let binder = match binder.and_then(|it| it.generic_param_list()) {
Some(gpl) => gpl
@@ -1062,12 +1069,10 @@ impl<'db> ExprCollector<'db> {
Some(ast::BlockModifier::Const(_)) => {
self.with_label_rib(RibKind::Constant, |this| {
this.with_awaitable_block(Awaitable::No("constant block"), |this| {
- let (result_expr_id, prev_binding_owner) =
- this.initialize_binding_owner(syntax_ptr);
- let inner_expr = this.collect_block(e);
- this.store.exprs[result_expr_id] = Expr::Const(inner_expr);
- this.current_binding_owner = prev_binding_owner;
- result_expr_id
+ this.with_binding_owner(|this| {
+ let inner_expr = this.collect_block(e);
+ this.alloc_expr(Expr::Const(inner_expr), syntax_ptr)
+ })
})
})
}
@@ -1278,64 +1283,65 @@ impl<'db> ExprCollector<'db> {
}
}
ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
- let (result_expr_id, prev_binding_owner) =
- this.initialize_binding_owner(syntax_ptr);
- let mut args = Vec::new();
- let mut arg_types = Vec::new();
- if let Some(pl) = e.param_list() {
- let num_params = pl.params().count();
- args.reserve_exact(num_params);
- arg_types.reserve_exact(num_params);
- for param in pl.params() {
- let pat = this.collect_pat_top(param.pat());
- let type_ref =
- param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
- args.push(pat);
- arg_types.push(type_ref);
+ this.with_binding_owner(|this| {
+ let mut args = Vec::new();
+ let mut arg_types = Vec::new();
+ if let Some(pl) = e.param_list() {
+ let num_params = pl.params().count();
+ args.reserve_exact(num_params);
+ arg_types.reserve_exact(num_params);
+ for param in pl.params() {
+ let pat = this.collect_pat_top(param.pat());
+ let type_ref =
+ param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
+ args.push(pat);
+ arg_types.push(type_ref);
+ }
}
- }
- let ret_type = e
- .ret_type()
- .and_then(|r| r.ty())
- .map(|it| this.lower_type_ref_disallow_impl_trait(it));
+ let ret_type = e
+ .ret_type()
+ .and_then(|r| r.ty())
+ .map(|it| this.lower_type_ref_disallow_impl_trait(it));
- let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
- let prev_try_block_label = this.current_try_block_label.take();
+ let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
+ let prev_try_block_label = this.current_try_block_label.take();
- let awaitable = if e.async_token().is_some() {
- Awaitable::Yes
- } else {
- Awaitable::No("non-async closure")
- };
- let body =
- this.with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
+ let awaitable = if e.async_token().is_some() {
+ Awaitable::Yes
+ } else {
+ Awaitable::No("non-async closure")
+ };
+ let body = this
+ .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
- let closure_kind = if this.is_lowering_coroutine {
- let movability = if e.static_token().is_some() {
- Movability::Static
+ let closure_kind = if this.is_lowering_coroutine {
+ let movability = if e.static_token().is_some() {
+ Movability::Static
+ } else {
+ Movability::Movable
+ };
+ ClosureKind::Coroutine(movability)
+ } else if e.async_token().is_some() {
+ ClosureKind::Async
} else {
- Movability::Movable
+ ClosureKind::Closure
};
- ClosureKind::Coroutine(movability)
- } else if e.async_token().is_some() {
- ClosureKind::Async
- } else {
- ClosureKind::Closure
- };
- let capture_by =
- if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
- this.is_lowering_coroutine = prev_is_lowering_coroutine;
- this.current_binding_owner = prev_binding_owner;
- this.current_try_block_label = prev_try_block_label;
- this.store.exprs[result_expr_id] = Expr::Closure {
- args: args.into(),
- arg_types: arg_types.into(),
- ret_type,
- body,
- closure_kind,
- capture_by,
- };
- result_expr_id
+ let capture_by =
+ if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
+ this.is_lowering_coroutine = prev_is_lowering_coroutine;
+ this.current_try_block_label = prev_try_block_label;
+ this.alloc_expr(
+ Expr::Closure {
+ args: args.into(),
+ arg_types: arg_types.into(),
+ ret_type,
+ body,
+ closure_kind,
+ capture_by,
+ },
+ syntax_ptr,
+ )
+ })
}),
ast::Expr::BinExpr(e) => {
let op = e.op_kind();
@@ -1371,11 +1377,7 @@ impl<'db> ExprCollector<'db> {
let initializer = self.collect_expr_opt(initializer);
let repeat = self.with_label_rib(RibKind::Constant, |this| {
if let Some(repeat) = repeat {
- let syntax_ptr = AstPtr::new(&repeat);
- this.collect_as_a_binding_owner_bad(
- |this| this.collect_expr(repeat),
- syntax_ptr,
- )
+ this.with_binding_owner(|this| this.collect_expr(repeat))
} else {
this.missing_expr()
}
@@ -1632,31 +1634,13 @@ impl<'db> ExprCollector<'db> {
}
}
- fn initialize_binding_owner(
- &mut self,
- syntax_ptr: AstPtr<ast::Expr>,
- ) -> (ExprId, Option<ExprId>) {
- let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
- let prev_binding_owner = self.current_binding_owner.take();
- self.current_binding_owner = Some(result_expr_id);
-
- (result_expr_id, prev_binding_owner)
- }
-
- /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently
- /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have
- /// their own body. Don't add more usage for this function so that we can remove this function after
- /// separating those bodies.
- fn collect_as_a_binding_owner_bad(
- &mut self,
- job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId,
- syntax_ptr: AstPtr<ast::Expr>,
- ) -> ExprId {
- let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
- let tmp = job(self);
- self.store.exprs[id] = mem::replace(&mut self.store.exprs[tmp], Expr::Missing);
- self.current_binding_owner = prev_owner;
- id
+ fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
+ let prev_unowned_bindings_len = self.unowned_bindings.len();
+ let expr_id = create_expr(self);
+ for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {
+ self.store.binding_owners.insert(binding, expr_id);
+ }
+ expr_id
}
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -1664,9 +1648,8 @@ impl<'db> ExprCollector<'db> {
/// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
- let label = self.alloc_label_desugared(Label {
- name: Name::generate_new_name(self.store.labels.len()),
- });
+ let label = self.generate_new_name();
+ let label = self.alloc_label_desugared(Label { name: label });
let old_label = self.current_try_block_label.replace(label);
let ptr = AstPtr::new(&e).upcast();
@@ -1794,7 +1777,7 @@ impl<'db> ExprCollector<'db> {
this.collect_expr_opt(e.loop_body().map(|it| it.into()))
}),
};
- let iter_name = Name::generate_new_name(self.store.exprs.len());
+ let iter_name = self.generate_new_name();
let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);
let iter_expr_mut = self.alloc_expr(
Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
@@ -1855,7 +1838,7 @@ impl<'db> ExprCollector<'db> {
let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr);
let expr = self
.alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
- let continue_name = Name::generate_new_name(self.store.bindings.len());
+ let continue_name = self.generate_new_name();
let continue_binding = self.alloc_binding(
continue_name.clone(),
BindingAnnotation::Unannotated,
@@ -1873,7 +1856,7 @@ impl<'db> ExprCollector<'db> {
guard: None,
expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr),
};
- let break_name = Name::generate_new_name(self.store.bindings.len());
+ let break_name = self.generate_new_name();
let break_binding =
self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated, HygieneId::ROOT);
let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
@@ -1915,9 +1898,8 @@ impl<'db> ExprCollector<'db> {
T: ast::AstNode,
{
let macro_call_ptr = self.expander.in_file(syntax_ptr);
- let module = self.module.local_id;
- let block_call = self.def_map.modules[self.module.local_id].scope.macro_invoc(
+ let block_call = self.def_map.modules[self.module].scope.macro_invoc(
self.expander.in_file(self.expander.ast_id_map().ast_id_for_ptr(syntax_ptr)),
);
let res = match block_call {
@@ -1929,7 +1911,7 @@ impl<'db> ExprCollector<'db> {
.resolve_path(
self.local_def_map,
self.db,
- module,
+ self.module,
path,
crate::item_scope::BuiltinShadowMode::Other,
Some(MacroSubNs::Bang),
@@ -1940,7 +1922,7 @@ impl<'db> ExprCollector<'db> {
self.expander.enter_expand(
self.db,
mcall,
- self.module.krate(),
+ self.krate,
resolver,
&mut |ptr, call| {
_ = self.store.expansions.insert(ptr.map(|(it, _)| it), call);
@@ -2058,7 +2040,8 @@ impl<'db> ExprCollector<'db> {
return;
};
let name = name.as_name();
- let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros();
+ let macro_id =
+ self.def_map.modules[self.def_map.root].scope.get(&name).take_macros();
self.collect_macro_def(statements, macro_id);
}
ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
@@ -2072,7 +2055,7 @@ impl<'db> ExprCollector<'db> {
let name = name.as_name();
let macro_defs_count =
self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
- let macro_id = self.def_map.modules[DefMap::ROOT]
+ let macro_id = self.def_map.modules[self.def_map.root]
.scope
.get_legacy_macro(&name)
.and_then(|it| it.get(*macro_defs_count))
@@ -2118,7 +2101,7 @@ impl<'db> ExprCollector<'db> {
match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
Some((def_map, block_id)) => {
self.store.block_scopes.push(block_id);
- (def_map.module_id(DefMap::ROOT), def_map)
+ (def_map.root_module_id(), def_map)
}
None => (self.module, self.def_map),
};
@@ -2201,7 +2184,7 @@ impl<'db> ExprCollector<'db> {
let (resolved, _) = self.def_map.resolve_path(
self.local_def_map,
self.db,
- self.module.local_id,
+ self.module,
&name.clone().into(),
BuiltinShadowMode::Other,
None,
@@ -2368,11 +2351,7 @@ impl<'db> ExprCollector<'db> {
ast::Pat::ConstBlockPat(const_block_pat) => {
if let Some(block) = const_block_pat.block_expr() {
let expr_id = self.with_label_rib(RibKind::Constant, |this| {
- let syntax_ptr = AstPtr::new(&block.clone().into());
- this.collect_as_a_binding_owner_bad(
- |this| this.collect_block(block),
- syntax_ptr,
- )
+ this.with_binding_owner(|this| this.collect_block(block))
});
Pat::ConstBlock(expr_id)
} else {
@@ -2632,7 +2611,6 @@ impl<'db> ExprCollector<'db> {
}
// endregion: labels
- // region: format
fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
let m = match expr {
ast::Expr::MacroExpr(m) => m,
@@ -2652,676 +2630,6 @@ impl<'db> ExprCollector<'db> {
Some((exp, false))
}
- fn collect_format_args(
- &mut self,
- f: ast::FormatArgsExpr,
- syntax_ptr: AstPtr<ast::Expr>,
- ) -> ExprId {
- let mut args = FormatArgumentsCollector::default();
- f.args().for_each(|arg| {
- args.add(FormatArgument {
- kind: match arg.name() {
- Some(name) => FormatArgumentKind::Named(name.as_name()),
- None => FormatArgumentKind::Normal,
- },
- expr: self.collect_expr_opt(arg.expr()),
- });
- });
- let template = f.template();
- let fmt_snippet = template.as_ref().and_then(|it| match it {
- ast::Expr::Literal(literal) => match literal.kind() {
- ast::LiteralKind::String(s) => Some(s.text().to_owned()),
- _ => None,
- },
- _ => None,
- });
- let mut mappings = vec![];
- let (fmt, hygiene) = match template.and_then(|template| {
- self.expand_macros_to_string(template.clone()).map(|it| (it, template))
- }) {
- Some(((s, is_direct_literal), template)) => {
- let call_ctx = self.expander.call_syntax_ctx();
- let hygiene = self.hygiene_id_for(s.syntax().text_range());
- let fmt = format_args::parse(
- &s,
- fmt_snippet,
- args,
- is_direct_literal,
- |name, range| {
- let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
- if let Some(range) = range {
- self.store
- .template_map
- .get_or_insert_with(Default::default)
- .implicit_capture_to_source
- .insert(
- expr_id,
- self.expander.in_file((AstPtr::new(&template), range)),
- );
- }
- if !hygiene.is_root() {
- self.store.ident_hygiene.insert(expr_id.into(), hygiene);
- }
- expr_id
- },
- |name, span| {
- if let Some(span) = span {
- mappings.push((span, name))
- }
- },
- call_ctx,
- );
- (fmt, hygiene)
- }
- None => (
- FormatArgs {
- template: Default::default(),
- arguments: args.finish(),
- orphans: Default::default(),
- },
- HygieneId::ROOT,
- ),
- };
-
- // Create a list of all _unique_ (argument, format trait) combinations.
- // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
- let mut argmap = FxIndexSet::default();
- for piece in fmt.template.iter() {
- let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
- if let Ok(index) = placeholder.argument.index {
- argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
- }
- }
-
- let lit_pieces = fmt
- .template
- .iter()
- .enumerate()
- .filter_map(|(i, piece)| {
- match piece {
- FormatArgsPiece::Literal(s) => {
- Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))))
- }
- &FormatArgsPiece::Placeholder(_) => {
- // Inject empty string before placeholders when not already preceded by a literal piece.
- if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
- {
- Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
- Symbol::empty(),
- ))))
- } else {
- None
- }
- }
- }
- })
- .collect();
- let lit_pieces =
- self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
- let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
- expr: lit_pieces,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- });
- let format_options = {
- // Generate:
- // &[format_spec_0, format_spec_1, format_spec_2]
- let elements = fmt
- .template
- .iter()
- .filter_map(|piece| {
- let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
- Some(self.make_format_spec(placeholder, &mut argmap))
- })
- .collect();
- let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
- self.alloc_expr_desugared(Expr::Ref {
- expr: array,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- })
- };
-
- // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
- // but `format_unsafe_arg` does not
- let lang_items = self.lang_items();
- let fmt_args = lang_items.FormatArguments;
- let fmt_unsafe_arg = lang_items.FormatUnsafeArg;
- let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none();
-
- let idx = if use_format_args_since_1_89_0 {
- self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options)
- } else {
- self.collect_format_args_before_1_89_0_impl(
- syntax_ptr,
- fmt,
- argmap,
- lit_pieces,
- format_options,
- )
- };
-
- self.store
- .template_map
- .get_or_insert_with(Default::default)
- .format_args_to_captures
- .insert(idx, (hygiene, mappings));
- idx
- }
-
- /// `format_args!` expansion implementation for rustc versions < `1.89.0`
- fn collect_format_args_before_1_89_0_impl(
- &mut self,
- syntax_ptr: AstPtr<ast::Expr>,
- fmt: FormatArgs,
- argmap: FxIndexSet<(usize, ArgumentType)>,
- lit_pieces: ExprId,
- format_options: ExprId,
- ) -> ExprId {
- let arguments = &*fmt.arguments.arguments;
-
- let args = if arguments.is_empty() {
- let expr = self
- .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
- self.alloc_expr_desugared(Expr::Ref {
- expr,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- })
- } else {
- // Generate:
- // &match (&arg0, &arg1, &…) {
- // args => [
- // <core::fmt::Argument>::new_display(args.0),
- // <core::fmt::Argument>::new_lower_hex(args.1),
- // <core::fmt::Argument>::new_debug(args.0),
- // …
- // ]
- // }
- let args = argmap
- .iter()
- .map(|&(arg_index, ty)| {
- let arg = self.alloc_expr_desugared(Expr::Ref {
- expr: arguments[arg_index].expr,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- });
- self.make_argument(arg, ty)
- })
- .collect();
- let array =
- self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
- self.alloc_expr_desugared(Expr::Ref {
- expr: array,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- })
- };
-
- // Generate:
- // <core::fmt::Arguments>::new_v1_formatted(
- // lit_pieces,
- // args,
- // format_options,
- // unsafe { ::core::fmt::UnsafeArg::new() }
- // )
-
- let lang_items = self.lang_items();
- let new_v1_formatted = self.ty_rel_lang_path(
- lang_items.FormatArguments,
- Name::new_symbol_root(sym::new_v1_formatted),
- );
- let unsafe_arg_new =
- self.ty_rel_lang_path(lang_items.FormatUnsafeArg, Name::new_symbol_root(sym::new));
- let new_v1_formatted =
- self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
-
- let unsafe_arg_new =
- self.alloc_expr_desugared(unsafe_arg_new.map_or(Expr::Missing, Expr::Path));
- let unsafe_arg_new =
- self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
- let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
- id: None,
- statements: Box::new([]),
- tail: Some(unsafe_arg_new),
- });
- if !fmt.orphans.is_empty() {
- unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
- id: None,
- // We collect the unused expressions here so that we still infer them instead of
- // dropping them out of the expression tree. We cannot store them in the `Unsafe`
- // block because then unsafe blocks within them will get a false "unused unsafe"
- // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
- statements: fmt
- .orphans
- .into_iter()
- .map(|expr| Statement::Expr { expr, has_semi: true })
- .collect(),
- tail: Some(unsafe_arg_new),
- label: None,
- });
- }
-
- self.alloc_expr(
- Expr::Call {
- callee: new_v1_formatted,
- args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
- },
- syntax_ptr,
- )
- }
-
- /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
- /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
- fn collect_format_args_impl(
- &mut self,
- syntax_ptr: AstPtr<ast::Expr>,
- fmt: FormatArgs,
- argmap: FxIndexSet<(usize, ArgumentType)>,
- lit_pieces: ExprId,
- format_options: ExprId,
- ) -> ExprId {
- let arguments = &*fmt.arguments.arguments;
-
- let (let_stmts, args) = if arguments.is_empty() {
- (
- // Generate:
- // []
- vec![],
- self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: Box::default(),
- })),
- )
- } else if argmap.len() == 1 && arguments.len() == 1 {
- // Only one argument, so we don't need to make the `args` tuple.
- //
- // Generate:
- // super let args = [<core::fmt::Arguments>::new_display(&arg)];
- let args = argmap
- .iter()
- .map(|&(arg_index, ty)| {
- let ref_arg = self.alloc_expr_desugared(Expr::Ref {
- expr: arguments[arg_index].expr,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- });
- self.make_argument(ref_arg, ty)
- })
- .collect();
- let args =
- self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
- let args_name = Name::new_symbol_root(sym::args);
- let args_binding = self.alloc_binding(
- args_name.clone(),
- BindingAnnotation::Unannotated,
- HygieneId::ROOT,
- );
- let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
- self.add_definition_to_binding(args_binding, args_pat);
- // TODO: We don't have `super let` yet.
- let let_stmt = Statement::Let {
- pat: args_pat,
- type_ref: None,
- initializer: Some(args),
- else_branch: None,
- };
- (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
- } else {
- // Generate:
- // super let args = (&arg0, &arg1, &...);
- let args_name = Name::new_symbol_root(sym::args);
- let args_binding = self.alloc_binding(
- args_name.clone(),
- BindingAnnotation::Unannotated,
- HygieneId::ROOT,
- );
- let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
- self.add_definition_to_binding(args_binding, args_pat);
- let elements = arguments
- .iter()
- .map(|arg| {
- self.alloc_expr_desugared(Expr::Ref {
- expr: arg.expr,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- })
- })
- .collect();
- let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
- // TODO: We don't have `super let` yet
- let let_stmt1 = Statement::Let {
- pat: args_pat,
- type_ref: None,
- initializer: Some(args_tuple),
- else_branch: None,
- };
-
- // Generate:
- // super let args = [
- // <core::fmt::Argument>::new_display(args.0),
- // <core::fmt::Argument>::new_lower_hex(args.1),
- // <core::fmt::Argument>::new_debug(args.0),
- // …
- // ];
- let args = argmap
- .iter()
- .map(|&(arg_index, ty)| {
- let args_ident_expr =
- self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
- let arg = self.alloc_expr_desugared(Expr::Field {
- expr: args_ident_expr,
- name: Name::new_tuple_field(arg_index),
- });
- self.make_argument(arg, ty)
- })
- .collect();
- let array =
- self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
- let args_binding = self.alloc_binding(
- args_name.clone(),
- BindingAnnotation::Unannotated,
- HygieneId::ROOT,
- );
- let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
- self.add_definition_to_binding(args_binding, args_pat);
- let let_stmt2 = Statement::Let {
- pat: args_pat,
- type_ref: None,
- initializer: Some(array),
- else_branch: None,
- };
- (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
- };
-
- // Generate:
- // &args
- let args = self.alloc_expr_desugared(Expr::Ref {
- expr: args,
- rawness: Rawness::Ref,
- mutability: Mutability::Shared,
- });
-
- let call_block = {
- // Generate:
- // unsafe {
- // <core::fmt::Arguments>::new_v1_formatted(
- // lit_pieces,
- // args,
- // format_options,
- // )
- // }
-
- let new_v1_formatted = self.ty_rel_lang_path(
- self.lang_items().FormatArguments,
- Name::new_symbol_root(sym::new_v1_formatted),
- );
- let new_v1_formatted =
- self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
- let args = [lit_pieces, args, format_options];
- let call = self
- .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
-
- Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
- };
-
- if !let_stmts.is_empty() {
- // Generate:
- // {
- // super let …
- // super let …
- // <core::fmt::Arguments>::new_…(…)
- // }
- let call = self.alloc_expr_desugared(call_block);
- self.alloc_expr(
- Expr::Block {
- id: None,
- statements: let_stmts.into(),
- tail: Some(call),
- label: None,
- },
- syntax_ptr,
- )
- } else {
- self.alloc_expr(call_block, syntax_ptr)
- }
- }
-
- /// Generate a hir expression for a format_args placeholder specification.
- ///
- /// Generates
- ///
- /// ```text
- /// <core::fmt::rt::Placeholder::new(
- /// …usize, // position
- /// '…', // fill
- /// <core::fmt::rt::Alignment>::…, // alignment
- /// …u32, // flags
- /// <core::fmt::rt::Count::…>, // width
- /// <core::fmt::rt::Count::…>, // precision
- /// )
- /// ```
- fn make_format_spec(
- &mut self,
- placeholder: &FormatPlaceholder,
- argmap: &mut FxIndexSet<(usize, ArgumentType)>,
- ) -> ExprId {
- let lang_items = self.lang_items();
- let position = match placeholder.argument.index {
- Ok(arg_index) => {
- let (i, _) =
- argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
- self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- i as u128,
- Some(BuiltinUint::Usize),
- )))
- }
- Err(_) => self.missing_expr(),
- };
- let &FormatOptions {
- ref width,
- ref precision,
- alignment,
- fill,
- sign,
- alternate,
- zero_pad,
- debug_hex,
- } = &placeholder.format_options;
-
- let precision_expr = self.make_count(precision, argmap);
- let width_expr = self.make_count(width, argmap);
-
- if self.module.krate().workspace_data(self.db).is_atleast_187() {
- // These need to match the constants in library/core/src/fmt/rt.rs.
- let align = match alignment {
- Some(FormatAlignment::Left) => 0,
- Some(FormatAlignment::Right) => 1,
- Some(FormatAlignment::Center) => 2,
- None => 3,
- };
- // This needs to match `Flag` in library/core/src/fmt/rt.rs.
- let flags = fill.unwrap_or(' ') as u32
- | ((sign == Some(FormatSign::Plus)) as u32) << 21
- | ((sign == Some(FormatSign::Minus)) as u32) << 22
- | (alternate as u32) << 23
- | (zero_pad as u32) << 24
- | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
- | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
- | (width.is_some() as u32) << 27
- | (precision.is_some() as u32) << 28
- | align << 29
- | 1 << 31; // Highest bit always set.
- let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- flags as u128,
- Some(BuiltinUint::U32),
- )));
-
- let position =
- RecordLitField { name: Name::new_symbol_root(sym::position), expr: position };
- let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags };
- let precision = RecordLitField {
- name: Name::new_symbol_root(sym::precision),
- expr: precision_expr,
- };
- let width =
- RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr };
- self.alloc_expr_desugared(Expr::RecordLit {
- path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new),
- fields: Box::new([position, flags, precision, width]),
- spread: None,
- })
- } else {
- let format_placeholder_new = {
- let format_placeholder_new = self.ty_rel_lang_path(
- lang_items.FormatPlaceholder,
- Name::new_symbol_root(sym::new),
- );
- match format_placeholder_new {
- Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
- None => self.missing_expr(),
- }
- };
- // This needs to match `Flag` in library/core/src/fmt/rt.rs.
- let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
- | (((sign == Some(FormatSign::Minus)) as u32) << 1)
- | ((alternate as u32) << 2)
- | ((zero_pad as u32) << 3)
- | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
- | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
- let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- flags as u128,
- Some(BuiltinUint::U32),
- )));
- let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
- let align = {
- let align = self.ty_rel_lang_path(
- lang_items.FormatAlignment,
- match alignment {
- Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left),
- Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right),
- Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center),
- None => Name::new_symbol_root(sym::Unknown),
- },
- );
- match align {
- Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
- None => self.missing_expr(),
- }
- };
- self.alloc_expr_desugared(Expr::Call {
- callee: format_placeholder_new,
- args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
- })
- }
- }
-
- /// Generate a hir expression for a format_args Count.
- ///
- /// Generates:
- ///
- /// ```text
- /// <core::fmt::rt::Count>::Is(…)
- /// ```
- ///
- /// or
- ///
- /// ```text
- /// <core::fmt::rt::Count>::Param(…)
- /// ```
- ///
- /// or
- ///
- /// ```text
- /// <core::fmt::rt::Count>::Implied
- /// ```
- fn make_count(
- &mut self,
- count: &Option<FormatCount>,
- argmap: &mut FxIndexSet<(usize, ArgumentType)>,
- ) -> ExprId {
- let lang_items = self.lang_items();
- match count {
- Some(FormatCount::Literal(n)) => {
- let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- *n as u128,
- // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88
- None,
- )));
- let count_is = match self
- .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Is))
- {
- Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
- None => self.missing_expr(),
- };
- self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
- }
- Some(FormatCount::Argument(arg)) => {
- if let Ok(arg_index) = arg.index {
- let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
-
- let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
- i as u128,
- Some(BuiltinUint::Usize),
- )));
- let count_param = match self
- .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Param))
- {
- Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
- None => self.missing_expr(),
- };
- self.alloc_expr_desugared(Expr::Call {
- callee: count_param,
- args: Box::new([args]),
- })
- } else {
- // FIXME: This drops arg causing it to potentially not be resolved/type checked
- // when typing?
- self.missing_expr()
- }
- }
- None => match self
- .ty_rel_lang_path(lang_items.FormatCount, Name::new_symbol_root(sym::Implied))
- {
- Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
- None => self.missing_expr(),
- },
- }
- }
-
- /// Generate a hir expression representing an argument to a format_args invocation.
- ///
- /// Generates:
- ///
- /// ```text
- /// <core::fmt::Argument>::new_…(arg)
- /// ```
- fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
- use ArgumentType::*;
- use FormatTrait::*;
-
- let new_fn = match self.ty_rel_lang_path(
- self.lang_items().FormatArgument,
- Name::new_symbol_root(match ty {
- Format(Display) => sym::new_display,
- Format(Debug) => sym::new_debug,
- Format(LowerExp) => sym::new_lower_exp,
- Format(UpperExp) => sym::new_upper_exp,
- Format(Octal) => sym::new_octal,
- Format(Pointer) => sym::new_pointer,
- Format(Binary) => sym::new_binary,
- Format(LowerHex) => sym::new_lower_hex,
- Format(UpperHex) => sym::new_upper_hex,
- Usize => sym::from_usize,
- }),
- ) {
- Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
- None => self.missing_expr(),
- };
- self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
- }
-
- // endregion: format
-
fn lang_path(&self, lang: Option<impl Into<LangItemTarget>>) -> Option<Path> {
Some(Path::LangItem(lang?.into(), None))
}
@@ -3329,9 +2637,17 @@ impl<'db> ExprCollector<'db> {
fn ty_rel_lang_path(
&self,
lang: Option<impl Into<LangItemTarget>>,
- relative_name: Name,
+ relative_name: Symbol,
) -> Option<Path> {
- Some(Path::LangItem(lang?.into(), Some(relative_name)))
+ Some(Path::LangItem(lang?.into(), Some(Name::new_symbol_root(relative_name))))
+ }
+
+ fn ty_rel_lang_path_expr(
+ &self,
+ lang: Option<impl Into<LangItemTarget>>,
+ relative_name: Symbol,
+ ) -> Expr {
+ self.ty_rel_lang_path(lang, relative_name).map_or(Expr::Missing, Expr::Path)
}
}
@@ -3376,9 +2692,7 @@ impl ExprCollector<'_> {
hygiene: HygieneId,
) -> BindingId {
let binding = self.store.bindings.alloc(Binding { name, mode, problems: None, hygiene });
- if let Some(owner) = self.current_binding_owner {
- self.store.binding_owners.insert(binding, owner);
- }
+ self.unowned_bindings.push(binding);
binding
}
@@ -3450,12 +2764,6 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
.is_some_and(|it| it.kind() == syntax::T![,])
}
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum ArgumentType {
- Format(FormatTrait),
- Usize,
-}
-
/// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR.
pub fn hir_assoc_type_binding_to_ast(
segment_args: &ast::GenericArgList,
diff --git a/crates/hir-def/src/expr_store/lower/format_args.rs b/crates/hir-def/src/expr_store/lower/format_args.rs
new file mode 100644
index 0000000000..4bbfc5b144
--- /dev/null
+++ b/crates/hir-def/src/expr_store/lower/format_args.rs
@@ -0,0 +1,1012 @@
+//! Lowering of `format_args!()`.
+
+use base_db::FxIndexSet;
+use hir_expand::name::{AsName, Name};
+use intern::{Symbol, sym};
+use syntax::{
+ AstPtr, AstToken as _,
+ ast::{self, HasName},
+};
+
+use crate::{
+ builtin_type::BuiltinUint,
+ expr_store::{HygieneId, lower::ExprCollector, path::Path},
+ hir::{
+ Array, BindingAnnotation, Expr, ExprId, Literal, Pat, RecordLitField, Statement,
+ format_args::{
+ self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
+ FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
+ FormatPlaceholder, FormatSign, FormatTrait,
+ },
+ },
+ lang_item::LangItemTarget,
+ type_ref::{Mutability, Rawness},
+};
+
+impl<'db> ExprCollector<'db> {
+ pub(super) fn collect_format_args(
+ &mut self,
+ f: ast::FormatArgsExpr,
+ syntax_ptr: AstPtr<ast::Expr>,
+ ) -> ExprId {
+ let mut args = FormatArgumentsCollector::default();
+ f.args().for_each(|arg| {
+ args.add(FormatArgument {
+ kind: match arg.name() {
+ Some(name) => FormatArgumentKind::Named(name.as_name()),
+ None => FormatArgumentKind::Normal,
+ },
+ expr: self.collect_expr_opt(arg.expr()),
+ });
+ });
+ let template = f.template();
+ let fmt_snippet = template.as_ref().and_then(|it| match it {
+ ast::Expr::Literal(literal) => match literal.kind() {
+ ast::LiteralKind::String(s) => Some(s.text().to_owned()),
+ _ => None,
+ },
+ _ => None,
+ });
+ let mut mappings = vec![];
+ let (fmt, hygiene) = match template.and_then(|template| {
+ self.expand_macros_to_string(template.clone()).map(|it| (it, template))
+ }) {
+ Some(((s, is_direct_literal), template)) => {
+ let call_ctx = self.expander.call_syntax_ctx();
+ let hygiene = self.hygiene_id_for(s.syntax().text_range());
+ let fmt = format_args::parse(
+ &s,
+ fmt_snippet,
+ args,
+ is_direct_literal,
+ |name, range| {
+ let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
+ if let Some(range) = range {
+ self.store
+ .template_map
+ .get_or_insert_with(Default::default)
+ .implicit_capture_to_source
+ .insert(
+ expr_id,
+ self.expander.in_file((AstPtr::new(&template), range)),
+ );
+ }
+ if !hygiene.is_root() {
+ self.store.ident_hygiene.insert(expr_id.into(), hygiene);
+ }
+ expr_id
+ },
+ |name, span| {
+ if let Some(span) = span {
+ mappings.push((span, name))
+ }
+ },
+ call_ctx,
+ );
+ (fmt, hygiene)
+ }
+ None => (
+ FormatArgs {
+ template: Default::default(),
+ arguments: args.finish(),
+ orphans: Default::default(),
+ },
+ HygieneId::ROOT,
+ ),
+ };
+
+ let idx = if self.lang_items().FormatCount.is_none() {
+ self.collect_format_args_after_1_93_0_impl(syntax_ptr, fmt)
+ } else {
+ self.collect_format_args_before_1_93_0_impl(syntax_ptr, fmt)
+ };
+
+ self.store
+ .template_map
+ .get_or_insert_with(Default::default)
+ .format_args_to_captures
+ .insert(idx, (hygiene, mappings));
+ idx
+ }
+
+ fn collect_format_args_after_1_93_0_impl(
+ &mut self,
+ syntax_ptr: AstPtr<ast::Expr>,
+ fmt: FormatArgs,
+ ) -> ExprId {
+ let lang_items = self.lang_items();
+
+ // Create a list of all _unique_ (argument, format trait) combinations.
+ // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+ //
+ // We use usize::MAX for arguments that don't exist, because that can never be a valid index
+ // into the arguments array.
+ let mut argmap = FxIndexSet::default();
+
+ let mut incomplete_lit = String::new();
+
+ let mut implicit_arg_index = 0;
+
+ let mut bytecode = Vec::new();
+
+ let template = if fmt.template.is_empty() {
+ // Treat empty templates as a single literal piece (with an empty string),
+ // so we produce `from_str("")` for those.
+ &[FormatArgsPiece::Literal(sym::__empty)][..]
+ } else {
+ &fmt.template[..]
+ };
+
+ // See library/core/src/fmt/mod.rs for the format string encoding format.
+
+ for (i, piece) in template.iter().enumerate() {
+ match piece {
+ FormatArgsPiece::Literal(sym) => {
+ // Coalesce adjacent literal pieces.
+ if let Some(FormatArgsPiece::Literal(_)) = template.get(i + 1) {
+ incomplete_lit.push_str(sym.as_str());
+ continue;
+ }
+ let mut s = if incomplete_lit.is_empty() {
+ sym.as_str()
+ } else {
+ incomplete_lit.push_str(sym.as_str());
+ &incomplete_lit
+ };
+
+ // If this is the last piece and was the only piece, that means
+ // there are no placeholders and the entire format string is just a literal.
+ //
+ // In that case, we can just use `from_str`.
+ if i + 1 == template.len() && bytecode.is_empty() {
+ // Generate:
+ // <core::fmt::Arguments>::from_str("meow")
+ let from_str = self.ty_rel_lang_path_desugared_expr(
+ lang_items.FormatArguments,
+ sym::from_str,
+ );
+ let sym =
+ if incomplete_lit.is_empty() { sym.clone() } else { Symbol::intern(s) };
+ let s = self.alloc_expr_desugared(Expr::Literal(Literal::String(sym)));
+ let from_str = self.alloc_expr(
+ Expr::Call { callee: from_str, args: Box::new([s]) },
+ syntax_ptr,
+ );
+ return if !fmt.arguments.arguments.is_empty() {
+ // With an incomplete format string (e.g. only an opening `{`), it's possible for `arguments`
+ // to be non-empty when reaching this code path.
+ self.alloc_expr(
+ Expr::Block {
+ id: None,
+ statements: fmt
+ .arguments
+ .arguments
+ .iter()
+ .map(|arg| Statement::Expr {
+ expr: arg.expr,
+ has_semi: true,
+ })
+ .collect(),
+ tail: Some(from_str),
+ label: None,
+ },
+ syntax_ptr,
+ )
+ } else {
+ from_str
+ };
+ }
+
+ // Encode the literal in chunks of up to u16::MAX bytes, split at utf-8 boundaries.
+ while !s.is_empty() {
+ let len = s.floor_char_boundary(usize::from(u16::MAX));
+ if len < 0x80 {
+ bytecode.push(len as u8);
+ } else {
+ bytecode.push(0x80);
+ bytecode.extend_from_slice(&(len as u16).to_le_bytes());
+ }
+ bytecode.extend(&s.as_bytes()[..len]);
+ s = &s[len..];
+ }
+
+ incomplete_lit.clear();
+ }
+ FormatArgsPiece::Placeholder(p) => {
+ // Push the start byte and remember its index so we can set the option bits later.
+ let i = bytecode.len();
+ bytecode.push(0xC0);
+
+ let position = match &p.argument.index {
+ &Ok(it) => it,
+ Err(_) => usize::MAX,
+ };
+ let position = argmap
+ .insert_full((position, ArgumentType::Format(p.format_trait)))
+ .0 as u64;
+
+ // This needs to match the constants in library/core/src/fmt/mod.rs.
+ let o = &p.format_options;
+ let align = match o.alignment {
+ Some(FormatAlignment::Left) => 0,
+ Some(FormatAlignment::Right) => 1,
+ Some(FormatAlignment::Center) => 2,
+ None => 3,
+ };
+ let default_flags = 0x6000_0020;
+ let flags: u32 = o.fill.unwrap_or(' ') as u32
+ | ((o.sign == Some(FormatSign::Plus)) as u32) << 21
+ | ((o.sign == Some(FormatSign::Minus)) as u32) << 22
+ | (o.alternate as u32) << 23
+ | (o.zero_pad as u32) << 24
+ | ((o.debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
+ | ((o.debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
+ | (o.width.is_some() as u32) << 27
+ | (o.precision.is_some() as u32) << 28
+ | align << 29;
+ if flags != default_flags {
+ bytecode[i] |= 1;
+ bytecode.extend_from_slice(&flags.to_le_bytes());
+ if let Some(val) = &o.width {
+ let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap);
+ // Only encode if nonzero; zero is the default.
+ if indirect || val != 0 {
+ bytecode[i] |= 1 << 1 | (indirect as u8) << 4;
+ bytecode.extend_from_slice(&val.to_le_bytes());
+ }
+ }
+ if let Some(val) = &o.precision {
+ let (indirect, val) = self.make_count_after_1_93_0(val, &mut argmap);
+ // Only encode if nonzero; zero is the default.
+ if indirect || val != 0 {
+ bytecode[i] |= 1 << 2 | (indirect as u8) << 5;
+ bytecode.extend_from_slice(&val.to_le_bytes());
+ }
+ }
+ }
+ if implicit_arg_index != position {
+ bytecode[i] |= 1 << 3;
+ bytecode.extend_from_slice(&(position as u16).to_le_bytes());
+ }
+ implicit_arg_index = position + 1;
+ }
+ }
+ }
+
+ assert!(incomplete_lit.is_empty());
+
+ // Zero terminator.
+ bytecode.push(0);
+
+ // Ensure all argument indexes actually fit in 16 bits, as we truncated them to 16 bits before.
+ if argmap.len() > u16::MAX as usize {
+ // FIXME: Emit an error.
+ // ctx.dcx().span_err(macsp, "too many format arguments");
+ }
+
+ let arguments = &fmt.arguments.arguments[..];
+
+ let (mut statements, args) = if arguments.is_empty() {
+ // Generate:
+ // []
+ (
+ Vec::new(),
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements: Box::new([]),
+ })),
+ )
+ } else {
+ // Generate:
+ // super let args = (&arg0, &arg1, &…);
+ let args_name = self.generate_new_name();
+ let args_path = Path::from(args_name.clone());
+ let args_binding = self.alloc_binding(
+ args_name.clone(),
+ BindingAnnotation::Unannotated,
+ HygieneId::ROOT,
+ );
+ let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+ self.add_definition_to_binding(args_binding, args_pat);
+ let elements = arguments
+ .iter()
+ .map(|arg| {
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: arg.expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ })
+ .collect();
+ let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+ // FIXME: Make this a `super let` when we have this statement.
+ let let_statement_1 = Statement::Let {
+ pat: args_pat,
+ type_ref: None,
+ initializer: Some(args_tuple),
+ else_branch: None,
+ };
+
+ // Generate:
+ // super let args = [
+ // <core::fmt::Argument>::new_display(args.0),
+ // <core::fmt::Argument>::new_lower_hex(args.1),
+ // <core::fmt::Argument>::new_debug(args.0),
+ // …
+ // ];
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ let args_ident_expr = self.alloc_expr_desugared(Expr::Path(args_path.clone()));
+ let arg = self.alloc_expr_desugared(Expr::Field {
+ expr: args_ident_expr,
+ name: Name::new_tuple_field(arg_index),
+ });
+ self.make_argument(arg, ty)
+ })
+ .collect();
+ let args =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+ let args_binding =
+ self.alloc_binding(args_name, BindingAnnotation::Unannotated, HygieneId::ROOT);
+ let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+ self.add_definition_to_binding(args_binding, args_pat);
+ // FIXME: Make this a `super let` when we have this statement.
+ let let_statement_2 = Statement::Let {
+ pat: args_pat,
+ type_ref: None,
+ initializer: Some(args),
+ else_branch: None,
+ };
+ (
+ vec![let_statement_1, let_statement_2],
+ self.alloc_expr_desugared(Expr::Path(args_path)),
+ )
+ };
+
+ // Generate:
+ // unsafe {
+ // <core::fmt::Arguments>::new(b"…", &args)
+ // }
+ let template = self
+ .alloc_expr_desugared(Expr::Literal(Literal::ByteString(bytecode.into_boxed_slice())));
+ let call = {
+ let new = self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new);
+ let args = self.alloc_expr_desugared(Expr::Ref {
+ expr: args,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ self.alloc_expr_desugared(Expr::Call { callee: new, args: Box::new([template, args]) })
+ };
+ let call = self.alloc_expr(
+ Expr::Unsafe { id: None, statements: Box::new([]), tail: Some(call) },
+ syntax_ptr,
+ );
+
+ // We collect the unused expressions here so that we still infer them instead of
+ // dropping them out of the expression tree. We cannot store them in the `Unsafe`
+ // block because then unsafe blocks within them will get a false "unused unsafe"
+ // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
+ statements
+ .extend(fmt.orphans.into_iter().map(|expr| Statement::Expr { expr, has_semi: true }));
+
+ if !statements.is_empty() {
+ // Generate:
+ // {
+ // super let …
+ // super let …
+ // <core::fmt::Arguments>::new(…)
+ // }
+ self.alloc_expr(
+ Expr::Block {
+ id: None,
+ statements: statements.into_boxed_slice(),
+ tail: Some(call),
+ label: None,
+ },
+ syntax_ptr,
+ )
+ } else {
+ call
+ }
+ }
+
+ /// Get the value for a `width` or `precision` field.
+ ///
+ /// Returns the value and whether it is indirect (an indexed argument) or not.
+ fn make_count_after_1_93_0(
+ &self,
+ count: &FormatCount,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ ) -> (bool, u16) {
+ match count {
+ FormatCount::Literal(n) => (false, *n),
+ FormatCount::Argument(arg) => {
+ let index = match &arg.index {
+ &Ok(it) => it,
+ Err(_) => usize::MAX,
+ };
+ (true, argmap.insert_full((index, ArgumentType::Usize)).0 as u16)
+ }
+ }
+ }
+
+ fn collect_format_args_before_1_93_0_impl(
+ &mut self,
+ syntax_ptr: AstPtr<ast::Expr>,
+ fmt: FormatArgs,
+ ) -> ExprId {
+ // Create a list of all _unique_ (argument, format trait) combinations.
+ // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+ let mut argmap = FxIndexSet::default();
+ for piece in fmt.template.iter() {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+ if let Ok(index) = placeholder.argument.index {
+ argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
+ }
+ }
+
+ let lit_pieces = fmt
+ .template
+ .iter()
+ .enumerate()
+ .filter_map(|(i, piece)| {
+ match piece {
+ FormatArgsPiece::Literal(s) => {
+ Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))))
+ }
+ &FormatArgsPiece::Placeholder(_) => {
+ // Inject empty string before placeholders when not already preceded by a literal piece.
+ if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
+ {
+ Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
+ Symbol::empty(),
+ ))))
+ } else {
+ None
+ }
+ }
+ }
+ })
+ .collect();
+ let lit_pieces =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
+ let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
+ expr: lit_pieces,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ let format_options = {
+ // Generate:
+ // &[format_spec_0, format_spec_1, format_spec_2]
+ let elements = fmt
+ .template
+ .iter()
+ .filter_map(|piece| {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+ Some(self.make_format_spec(placeholder, &mut argmap))
+ })
+ .collect();
+ let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: array,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ };
+
+ // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
+ // but `format_unsafe_arg` does not
+ let lang_items = self.lang_items();
+ let fmt_args = lang_items.FormatArguments;
+ let fmt_unsafe_arg = lang_items.FormatUnsafeArg;
+ let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none();
+
+ if use_format_args_since_1_89_0 {
+ self.collect_format_args_after_1_89_0_impl(
+ syntax_ptr,
+ fmt,
+ argmap,
+ lit_pieces,
+ format_options,
+ )
+ } else {
+ self.collect_format_args_before_1_89_0_impl(
+ syntax_ptr,
+ fmt,
+ argmap,
+ lit_pieces,
+ format_options,
+ )
+ }
+ }
+
+ /// `format_args!` expansion implementation for rustc versions < `1.89.0`
+ fn collect_format_args_before_1_89_0_impl(
+ &mut self,
+ syntax_ptr: AstPtr<ast::Expr>,
+ fmt: FormatArgs,
+ argmap: FxIndexSet<(usize, ArgumentType)>,
+ lit_pieces: ExprId,
+ format_options: ExprId,
+ ) -> ExprId {
+ let arguments = &*fmt.arguments.arguments;
+
+ let args = if arguments.is_empty() {
+ let expr = self
+ .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ } else {
+ // Generate:
+ // &match (&arg0, &arg1, &…) {
+ // args => [
+ // <core::fmt::Argument>::new_display(args.0),
+ // <core::fmt::Argument>::new_lower_hex(args.1),
+ // <core::fmt::Argument>::new_debug(args.0),
+ // …
+ // ]
+ // }
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ let arg = self.alloc_expr_desugared(Expr::Ref {
+ expr: arguments[arg_index].expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ self.make_argument(arg, ty)
+ })
+ .collect();
+ let array =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: array,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ };
+
+ // Generate:
+ // <core::fmt::Arguments>::new_v1_formatted(
+ // lit_pieces,
+ // args,
+ // format_options,
+ // unsafe { ::core::fmt::UnsafeArg::new() }
+ // )
+
+ let lang_items = self.lang_items();
+ let new_v1_formatted =
+ self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new_v1_formatted);
+ let unsafe_arg_new =
+ self.ty_rel_lang_path_desugared_expr(lang_items.FormatUnsafeArg, sym::new);
+ let unsafe_arg_new =
+ self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
+ let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
+ id: None,
+ statements: Box::new([]),
+ tail: Some(unsafe_arg_new),
+ });
+ if !fmt.orphans.is_empty() {
+ unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
+ id: None,
+ // We collect the unused expressions here so that we still infer them instead of
+ // dropping them out of the expression tree. We cannot store them in the `Unsafe`
+ // block because then unsafe blocks within them will get a false "unused unsafe"
+ // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
+ statements: fmt
+ .orphans
+ .into_iter()
+ .map(|expr| Statement::Expr { expr, has_semi: true })
+ .collect(),
+ tail: Some(unsafe_arg_new),
+ label: None,
+ });
+ }
+
+ self.alloc_expr(
+ Expr::Call {
+ callee: new_v1_formatted,
+ args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
+ },
+ syntax_ptr,
+ )
+ }
+
+ /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
+ /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
+ fn collect_format_args_after_1_89_0_impl(
+ &mut self,
+ syntax_ptr: AstPtr<ast::Expr>,
+ fmt: FormatArgs,
+ argmap: FxIndexSet<(usize, ArgumentType)>,
+ lit_pieces: ExprId,
+ format_options: ExprId,
+ ) -> ExprId {
+ let arguments = &*fmt.arguments.arguments;
+
+ let (let_stmts, args) = if arguments.is_empty() {
+ (
+ // Generate:
+ // []
+ vec![],
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements: Box::default(),
+ })),
+ )
+ } else if argmap.len() == 1 && arguments.len() == 1 {
+ // Only one argument, so we don't need to make the `args` tuple.
+ //
+ // Generate:
+ // super let args = [<core::fmt::Arguments>::new_display(&arg)];
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ let ref_arg = self.alloc_expr_desugared(Expr::Ref {
+ expr: arguments[arg_index].expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ self.make_argument(ref_arg, ty)
+ })
+ .collect();
+ let args =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+ let args_name = self.generate_new_name();
+ let args_binding = self.alloc_binding(
+ args_name.clone(),
+ BindingAnnotation::Unannotated,
+ HygieneId::ROOT,
+ );
+ let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+ self.add_definition_to_binding(args_binding, args_pat);
+ // TODO: We don't have `super let` yet.
+ let let_stmt = Statement::Let {
+ pat: args_pat,
+ type_ref: None,
+ initializer: Some(args),
+ else_branch: None,
+ };
+ (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+ } else {
+ // Generate:
+ // super let args = (&arg0, &arg1, &...);
+ let args_name = self.generate_new_name();
+ let args_binding = self.alloc_binding(
+ args_name.clone(),
+ BindingAnnotation::Unannotated,
+ HygieneId::ROOT,
+ );
+ let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+ self.add_definition_to_binding(args_binding, args_pat);
+ let elements = arguments
+ .iter()
+ .map(|arg| {
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: arg.expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ })
+ .collect();
+ let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+ // TODO: We don't have `super let` yet
+ let let_stmt1 = Statement::Let {
+ pat: args_pat,
+ type_ref: None,
+ initializer: Some(args_tuple),
+ else_branch: None,
+ };
+
+ // Generate:
+ // super let args = [
+ // <core::fmt::Argument>::new_display(args.0),
+ // <core::fmt::Argument>::new_lower_hex(args.1),
+ // <core::fmt::Argument>::new_debug(args.0),
+ // …
+ // ];
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ let args_ident_expr =
+ self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
+ let arg = self.alloc_expr_desugared(Expr::Field {
+ expr: args_ident_expr,
+ name: Name::new_tuple_field(arg_index),
+ });
+ self.make_argument(arg, ty)
+ })
+ .collect();
+ let array =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+ let args_binding = self.alloc_binding(
+ args_name.clone(),
+ BindingAnnotation::Unannotated,
+ HygieneId::ROOT,
+ );
+ let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+ self.add_definition_to_binding(args_binding, args_pat);
+ let let_stmt2 = Statement::Let {
+ pat: args_pat,
+ type_ref: None,
+ initializer: Some(array),
+ else_branch: None,
+ };
+ (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+ };
+
+ // Generate:
+ // &args
+ let args = self.alloc_expr_desugared(Expr::Ref {
+ expr: args,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+
+ let call_block = {
+ // Generate:
+ // unsafe {
+ // <core::fmt::Arguments>::new_v1_formatted(
+ // lit_pieces,
+ // args,
+ // format_options,
+ // )
+ // }
+
+ let new_v1_formatted = self.ty_rel_lang_path_desugared_expr(
+ self.lang_items().FormatArguments,
+ sym::new_v1_formatted,
+ );
+ let args = [lit_pieces, args, format_options];
+ let call = self
+ .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
+
+ Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
+ };
+
+ if !let_stmts.is_empty() {
+ // Generate:
+ // {
+ // super let …
+ // super let …
+ // <core::fmt::Arguments>::new_…(…)
+ // }
+ let call = self.alloc_expr_desugared(call_block);
+ self.alloc_expr(
+ Expr::Block {
+ id: None,
+ statements: let_stmts.into(),
+ tail: Some(call),
+ label: None,
+ },
+ syntax_ptr,
+ )
+ } else {
+ self.alloc_expr(call_block, syntax_ptr)
+ }
+ }
+
+ /// Generate a hir expression for a format_args placeholder specification.
+ ///
+ /// Generates
+ ///
+ /// ```text
+ /// <core::fmt::rt::Placeholder::new(
+ /// …usize, // position
+ /// '…', // fill
+ /// <core::fmt::rt::Alignment>::…, // alignment
+ /// …u32, // flags
+ /// <core::fmt::rt::Count::…>, // width
+ /// <core::fmt::rt::Count::…>, // precision
+ /// )
+ /// ```
+ fn make_format_spec(
+ &mut self,
+ placeholder: &FormatPlaceholder,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ ) -> ExprId {
+ let lang_items = self.lang_items();
+ let position = match placeholder.argument.index {
+ Ok(arg_index) => {
+ let (i, _) =
+ argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+ self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ i as u128,
+ Some(BuiltinUint::Usize),
+ )))
+ }
+ Err(_) => self.missing_expr(),
+ };
+ let &FormatOptions {
+ ref width,
+ ref precision,
+ alignment,
+ fill,
+ sign,
+ alternate,
+ zero_pad,
+ debug_hex,
+ } = &placeholder.format_options;
+
+ let precision_expr = self.make_count_before_1_93_0(precision, argmap);
+ let width_expr = self.make_count_before_1_93_0(width, argmap);
+
+ if self.krate.workspace_data(self.db).is_atleast_187() {
+ // These need to match the constants in library/core/src/fmt/rt.rs.
+ let align = match alignment {
+ Some(FormatAlignment::Left) => 0,
+ Some(FormatAlignment::Right) => 1,
+ Some(FormatAlignment::Center) => 2,
+ None => 3,
+ };
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+ let flags = fill.unwrap_or(' ') as u32
+ | ((sign == Some(FormatSign::Plus)) as u32) << 21
+ | ((sign == Some(FormatSign::Minus)) as u32) << 22
+ | (alternate as u32) << 23
+ | (zero_pad as u32) << 24
+ | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
+ | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
+ | (width.is_some() as u32) << 27
+ | (precision.is_some() as u32) << 28
+ | align << 29
+ | 1 << 31; // Highest bit always set.
+ let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ flags as u128,
+ Some(BuiltinUint::U32),
+ )));
+
+ let position =
+ RecordLitField { name: Name::new_symbol_root(sym::position), expr: position };
+ let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags };
+ let precision = RecordLitField {
+ name: Name::new_symbol_root(sym::precision),
+ expr: precision_expr,
+ };
+ let width =
+ RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr };
+ self.alloc_expr_desugared(Expr::RecordLit {
+ path: self.lang_path(lang_items.FormatPlaceholder).map(Box::new),
+ fields: Box::new([position, flags, precision, width]),
+ spread: None,
+ })
+ } else {
+ let format_placeholder_new =
+ self.ty_rel_lang_path_desugared_expr(lang_items.FormatPlaceholder, sym::new);
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+ let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+ | (((sign == Some(FormatSign::Minus)) as u32) << 1)
+ | ((alternate as u32) << 2)
+ | ((zero_pad as u32) << 3)
+ | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
+ | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
+ let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ flags as u128,
+ Some(BuiltinUint::U32),
+ )));
+ let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
+ let align = self.ty_rel_lang_path_desugared_expr(
+ lang_items.FormatAlignment,
+ match alignment {
+ Some(FormatAlignment::Left) => sym::Left,
+ Some(FormatAlignment::Right) => sym::Right,
+ Some(FormatAlignment::Center) => sym::Center,
+ None => sym::Unknown,
+ },
+ );
+ self.alloc_expr_desugared(Expr::Call {
+ callee: format_placeholder_new,
+ args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
+ })
+ }
+ }
+
+ /// Generate a hir expression for a format_args Count.
+ ///
+ /// Generates:
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Is(…)
+ /// ```
+ ///
+ /// or
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Param(…)
+ /// ```
+ ///
+ /// or
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Implied
+ /// ```
+ fn make_count_before_1_93_0(
+ &mut self,
+ count: &Option<FormatCount>,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ ) -> ExprId {
+ let lang_items = self.lang_items();
+ match count {
+ Some(FormatCount::Literal(n)) => {
+ let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ *n as u128,
+ // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88
+ None,
+ )));
+ let count_is =
+ self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Is);
+ self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
+ }
+ Some(FormatCount::Argument(arg)) => {
+ if let Ok(arg_index) = arg.index {
+ let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+
+ let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ i as u128,
+ Some(BuiltinUint::Usize),
+ )));
+ let count_param =
+ self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Param);
+ self.alloc_expr_desugared(Expr::Call {
+ callee: count_param,
+ args: Box::new([args]),
+ })
+ } else {
+ // FIXME: This drops arg causing it to potentially not be resolved/type checked
+ // when typing?
+ self.missing_expr()
+ }
+ }
+ None => match self.ty_rel_lang_path(lang_items.FormatCount, sym::Implied) {
+ Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
+ None => self.missing_expr(),
+ },
+ }
+ }
+
+ /// Generate a hir expression representing an argument to a format_args invocation.
+ ///
+ /// Generates:
+ ///
+ /// ```text
+ /// <core::fmt::Argument>::new_…(arg)
+ /// ```
+ fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
+ use ArgumentType::*;
+ use FormatTrait::*;
+
+ let new_fn = self.ty_rel_lang_path_desugared_expr(
+ self.lang_items().FormatArgument,
+ match ty {
+ Format(Display) => sym::new_display,
+ Format(Debug) => sym::new_debug,
+ Format(LowerExp) => sym::new_lower_exp,
+ Format(UpperExp) => sym::new_upper_exp,
+ Format(Octal) => sym::new_octal,
+ Format(Pointer) => sym::new_pointer,
+ Format(Binary) => sym::new_binary,
+ Format(LowerHex) => sym::new_lower_hex,
+ Format(UpperHex) => sym::new_upper_hex,
+ Usize => sym::from_usize,
+ },
+ );
+ self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
+ }
+
+ fn ty_rel_lang_path_desugared_expr(
+ &mut self,
+ lang: Option<impl Into<LangItemTarget>>,
+ relative_name: Symbol,
+ ) -> ExprId {
+ self.alloc_expr_desugared(self.ty_rel_lang_path_expr(lang, relative_name))
+ }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+ Format(FormatTrait),
+ Usize,
+}
diff --git a/crates/hir-def/src/expr_store/tests/body.rs b/crates/hir-def/src/expr_store/tests/body.rs
index 4a775568bc..504c310684 100644
--- a/crates/hir-def/src/expr_store/tests/body.rs
+++ b/crates/hir-def/src/expr_store/tests/body.rs
@@ -32,14 +32,14 @@ fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
let (db, position) = TestDB::with_position(ra_fixture);
let module = db.module_at_position(position);
- module.def_map(&db).dump(&db)
+ salsa::plumbing::attach(&db, || module.def_map(&db).dump(&db))
}
fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let (db, position) = TestDB::with_position(ra_fixture);
let module = db.module_at_position(position);
- let actual = module.def_map(&db).dump_block_scopes(&db);
+ let actual = salsa::plumbing::attach(&db, || format!("{module:#?}"));
expect.assert_eq(&actual);
}
@@ -161,9 +161,9 @@ fn main() {
match builtin#lang(into_iter)(
0..10,
) {
- mut <ra@gennew>11 => loop {
+ mut <ra@gennew>0 => loop {
match builtin#lang(next)(
- &mut <ra@gennew>11,
+ &mut <ra@gennew>0,
) {
builtin#lang(None) => break,
builtin#lang(Some)(ident) => {
@@ -261,10 +261,10 @@ fn main() {
}
#[test]
-fn desugar_builtin_format_args() {
+fn desugar_builtin_format_args_before_1_93_0() {
let (db, body, def) = lower(
r#"
-//- minicore: fmt
+//- minicore: fmt_before_1_93_0
fn main() {
let are = "are";
let count = 10;
@@ -278,16 +278,16 @@ fn main() {
let are = "are";
let count = 10;
{
- let args = (&"fancy", &(), &"!", &count, &are, );
- let args = [
+ let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, );
+ let <ra@gennew>0 = [
builtin#lang(Argument::new_display)(
- args.3,
+ <ra@gennew>0.3,
), builtin#lang(Argument::new_display)(
- args.0,
+ <ra@gennew>0.0,
), builtin#lang(Argument::new_debug)(
- args.4,
+ <ra@gennew>0.4,
), builtin#lang(Argument::new_display)(
- args.2,
+ <ra@gennew>0.2,
),
];
unsafe {
@@ -295,7 +295,7 @@ fn main() {
&[
"\u{1b}hello ", " ", " friends, we ", " ", "",
],
- &args,
+ &<ra@gennew>0,
&[
builtin#lang(Placeholder::new)(
0usize,
@@ -344,6 +344,59 @@ fn main() {
}
#[test]
+fn desugar_builtin_format_args() {
+ let (db, body, def) = lower(
+ r#"
+//- minicore: fmt
+fn main() {
+ let are = "are";
+ let count = 10;
+ builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
+ builtin#format_args("hello world");
+ builtin#format_args("hello world", orphan = ());
+}
+"#,
+ );
+
+ expect![[r#"
+ fn main() {
+ let are = "are";
+ let count = 10;
+ {
+ let <ra@gennew>0 = (&"fancy", &(), &"!", &count, &are, );
+ let <ra@gennew>0 = [
+ builtin#lang(Argument::new_display)(
+ <ra@gennew>0.3,
+ ), builtin#lang(Argument::new_display)(
+ <ra@gennew>0.0,
+ ), builtin#lang(Argument::new_debug)(
+ <ra@gennew>0.4,
+ ), builtin#lang(Argument::new_display)(
+ <ra@gennew>0.2,
+ ),
+ ];
+ ();
+ unsafe {
+ builtin#lang(Arguments::new)(
+ "\x07\x1bhello \xc3 \x00\x00i\x02\x00\x01 \xc0\r friends, we \xc0\x01 \xc8\x01\x00\xc8\x03\x00\x00",
+ &<ra@gennew>0,
+ )
+ }
+ };
+ builtin#lang(Arguments::from_str)(
+ "hello world",
+ );
+ {
+ ();
+ builtin#lang(Arguments::from_str)(
+ "hello world",
+ )
+ };
+ }"#]]
+ .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
+
+#[test]
fn test_macro_hygiene() {
let (db, body, def) = lower(
r##"
@@ -382,27 +435,16 @@ impl SsrError {
fn main() {
_ = ra_test_fixture::error::SsrError::new(
{
- let args = [
+ let <ra@gennew>0 = (&node.text(), );
+ let <ra@gennew>0 = [
builtin#lang(Argument::new_display)(
- &node.text(),
+ <ra@gennew>0.0,
),
];
unsafe {
- builtin#lang(Arguments::new_v1_formatted)(
- &[
- "Failed to resolve path `", "`",
- ],
- &args,
- &[
- builtin#lang(Placeholder::new)(
- 0usize,
- ' ',
- builtin#lang(Alignment::Unknown),
- 0u32,
- builtin#lang(Count::Implied),
- builtin#lang(Count::Implied),
- ),
- ],
+ builtin#lang(Arguments::new)(
+ "\x18Failed to resolve path `\xc0\x01`\x00",
+ &<ra@gennew>0,
)
}
},
diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs
index 4501ff4df5..836a079e77 100644
--- a/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,10 +189,17 @@ fn f() {
}
"#,
expect![[r#"
- BlockId(3801) in BlockRelativeModuleId { block: Some(BlockId(3800)), local_id: Idx::<ModuleData>(1) }
- BlockId(3800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
- crate scope
- "#]],
+ ModuleIdLt {
+ [salsa id]: Id(3003),
+ krate: Crate(
+ Id(1c00),
+ ),
+ block: Some(
+ BlockId(
+ 3c01,
+ ),
+ ),
+ }"#]],
);
}
@@ -460,7 +467,7 @@ fn foo() {
}
#[test]
-fn is_visible_from_same_def_map() {
+fn is_visible_from_same_def_map_regression_9481() {
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481
check_at(
r#"
@@ -478,7 +485,6 @@ fn outer() {
- tests : type
(block scope)::tests
- - name : _
- outer : value (glob)
crate
diff --git a/crates/hir-def/src/expr_store/tests/signatures.rs b/crates/hir-def/src/expr_store/tests/signatures.rs
index 2dac4e7fc8..f1db00cf6a 100644
--- a/crates/hir-def/src/expr_store/tests/signatures.rs
+++ b/crates/hir-def/src/expr_store/tests/signatures.rs
@@ -197,3 +197,15 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
"#]],
);
}
+
+#[test]
+fn regression_21138() {
+ lower_and_print(
+ r#"
+fn foo(v: for<'a> Trait1 + Trait2) {}
+ "#,
+ expect![[r#"
+ fn foo(dyn for<'a> Trait1 + Trait2) {...}
+ "#]],
+ );
+}
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index e8a6ebcffa..5d1cac8e93 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -39,20 +39,23 @@ pub fn find_path(
// within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
// default to plain paths.
let item_module = item.module(db)?;
- if item_module.is_within_block() {
+ if item_module.block(db).is_some() {
prefix_kind = PrefixKind::Plain;
}
- cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
+ cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate(db));
+ let from_def_map = from.def_map(db);
find_path_inner(
&FindPathCtx {
db,
prefix: prefix_kind,
cfg,
ignore_local_imports,
- is_std_item: item_module.krate().data(db).origin.is_lang(),
+ is_std_item: item_module.krate(db).data(db).origin.is_lang(),
from,
- from_def_map: from.def_map(db),
+ from_crate: from.krate(db),
+ crate_root: from_def_map.crate_root(db),
+ from_def_map,
fuel: Cell::new(FIND_PATH_FUEL),
},
item,
@@ -100,6 +103,8 @@ struct FindPathCtx<'db> {
ignore_local_imports: bool,
is_std_item: bool,
from: ModuleId,
+ from_crate: Crate,
+ crate_root: ModuleId,
from_def_map: &'db DefMap,
fuel: Cell<usize>,
}
@@ -116,7 +121,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
let may_be_in_scope = match ctx.prefix {
PrefixKind::Plain | PrefixKind::BySelf => true,
- PrefixKind::ByCrate => ctx.from.is_crate_root(),
+ PrefixKind::ByCrate => ctx.crate_root == ctx.from,
};
if may_be_in_scope {
// - if the item is already in scope, return the name under which it is
@@ -163,8 +168,9 @@ fn find_path_for_module(
// recursive base case, we can't find a path of length 0
return None;
}
- if let Some(crate_root) = module_id.as_crate_root() {
- if !maybe_extern || crate_root == ctx.from.derive_crate_root() {
+ let module_crate_root = module_id.def_map(ctx.db).crate_root(ctx.db);
+ if module_crate_root == module_id {
+ if !maybe_extern || module_crate_root == ctx.crate_root {
// - if the item is the crate root, return `crate`
return Some(Choice {
path: ModPath::from_segments(PathKind::Crate, None),
@@ -175,19 +181,19 @@ fn find_path_for_module(
}
// - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude
- let root_local_def_map = ctx.from.derive_crate_root().local_def_map(ctx.db).1;
+ let root_local_def_map = ctx.crate_root.local_def_map(ctx.db).1;
// rev here so we prefer looking at renamed extern decls first
for (name, (def_id, _extern_crate)) in root_local_def_map.extern_prelude().rev() {
- if crate_root != def_id {
+ if module_crate_root != def_id {
continue;
}
let name_already_occupied_in_type_ns = ctx
.from_def_map
- .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| {
+ .with_ancestor_maps(ctx.db, ctx.from, &mut |def_map, local_id| {
def_map[local_id]
.scope
.type_(name)
- .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into()))
+ .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
})
.is_some();
let kind = if name_already_occupied_in_type_ns {
@@ -204,7 +210,7 @@ fn find_path_for_module(
let may_be_in_scope = match ctx.prefix {
PrefixKind::Plain | PrefixKind::BySelf => true,
- PrefixKind::ByCrate => ctx.from.is_crate_root(),
+ PrefixKind::ByCrate => ctx.crate_root == ctx.from,
};
if may_be_in_scope {
let scope_name = find_in_scope(
@@ -226,7 +232,7 @@ fn find_path_for_module(
}
// - if the module can be referenced as self, super or crate, do that
- if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from)
+ if let Some(kind) = is_kw_kind_relative_to_from(ctx.db, ctx.from_def_map, module_id, ctx.from)
&& (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate)
{
return Some(Choice {
@@ -259,7 +265,7 @@ fn find_in_scope(
ignore_local_imports: bool,
) -> Option<Name> {
// FIXME: We could have multiple applicable names here, but we currently only return the first
- def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| {
def_map[local_id].scope.names_of(item, |name, _, declared| {
(declared || !ignore_local_imports).then(|| name.clone())
})
@@ -276,7 +282,7 @@ fn find_in_prelude(
) -> Option<Choice> {
let (prelude_module, _) = local_def_map.prelude()?;
let prelude_def_map = prelude_module.def_map(db);
- let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
+ let prelude_scope = &prelude_def_map[prelude_module].scope;
let (name, vis, _declared) = prelude_scope.name_of(item)?;
if !vis.is_visible_from(db, from) {
return None;
@@ -284,7 +290,7 @@ fn find_in_prelude(
// Check if the name is in current scope and it points to the same def.
let found_and_same_def =
- local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ local_def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| {
let per_ns = def_map[local_id].scope.get(name);
let same_def = match item {
ItemInNs::Types(it) => per_ns.take_types()? == it,
@@ -302,22 +308,21 @@ fn find_in_prelude(
}
fn is_kw_kind_relative_to_from(
+ db: &dyn DefDatabase,
def_map: &DefMap,
item: ModuleId,
from: ModuleId,
) -> Option<PathKind> {
- if item.krate != from.krate || item.is_within_block() || from.is_within_block() {
+ if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() {
return None;
}
- let item = item.local_id;
- let from = from.local_id;
if item == from {
// - if the item is the module we're in, use `self`
Some(PathKind::SELF)
} else if let Some(parent_id) = def_map[from].parent {
if item == parent_id {
// - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
- Some(if parent_id == DefMap::ROOT { PathKind::Crate } else { PathKind::Super(1) })
+ Some(if parent_id == def_map.root { PathKind::Crate } else { PathKind::Super(1) })
} else {
None
}
@@ -340,13 +345,13 @@ fn calculate_best_path(
tracing::warn!(
"ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}",
item.krate(ctx.db),
- ctx.from.krate()
+ ctx.from_crate
);
return;
}
ctx.fuel.set(fuel - 1);
- if item.krate(ctx.db) == Some(ctx.from.krate) {
+ if item.krate(ctx.db) == Some(ctx.from_crate) {
// Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case.
calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
@@ -361,7 +366,7 @@ fn calculate_best_path(
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
// that wants to import it here, but we always prefer to use the external path here.
- ctx.from.krate.data(ctx.db).dependencies.iter().for_each(|dep| {
+ ctx.from_crate.data(ctx.db).dependencies.iter().for_each(|dep| {
find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id)
});
}
@@ -374,7 +379,7 @@ fn find_in_sysroot(
max_len: usize,
best_choice: &mut Option<Choice>,
) {
- let dependencies = &ctx.from.krate.data(ctx.db).dependencies;
+ let dependencies = &ctx.from_crate.data(ctx.db).dependencies;
let mut search = |lang, best_choice: &mut _| {
if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
match dep.crate_id.data(ctx.db).origin {
@@ -464,26 +469,19 @@ fn calculate_best_path_local(
best_choice: &mut Option<Choice>,
) {
// FIXME: cache the `find_local_import_locations` output?
- find_local_import_locations(
- ctx.db,
- item,
- ctx.from,
- ctx.from_def_map,
- visited_modules,
- |visited_modules, name, module_id| {
- // we are looking for paths of length up to best_path_len, any longer will make it be
- // less optimal. The -1 is due to us pushing name onto it afterwards.
- if let Some(choice) = find_path_for_module(
- ctx,
- visited_modules,
- module_id,
- false,
- best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1,
- ) {
- Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone());
- }
- },
- );
+ find_local_import_locations(ctx, item, visited_modules, |visited_modules, name, module_id| {
+ // we are looking for paths of length up to best_path_len, any longer will make it be
+ // less optimal. The -1 is due to us pushing name onto it afterwards.
+ if let Some(choice) = find_path_for_module(
+ ctx,
+ visited_modules,
+ module_id,
+ false,
+ best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1,
+ ) {
+ Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone());
+ }
+ });
}
#[derive(Debug)]
@@ -561,14 +559,13 @@ fn path_kind_len(kind: PathKind) -> usize {
/// Finds locations in `from.krate` from which `item` can be imported by `from`.
fn find_local_import_locations(
- db: &dyn DefDatabase,
+ ctx: &FindPathCtx<'_>,
item: ItemInNs,
- from: ModuleId,
- def_map: &DefMap,
visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId),
) {
let _p = tracing::info_span!("find_local_import_locations").entered();
+ let db = ctx.db;
// `from` can import anything below `from` with visibility of at least `from`, and anything
// above `from` with any visibility. That means we do not need to descend into private siblings
@@ -576,15 +573,16 @@ fn find_local_import_locations(
// Compute the initial worklist. We start with all direct child modules of `from` as well as all
// of its (recursive) parent modules.
- let mut worklist = def_map[from.local_id]
+ let mut worklist = ctx.from_def_map[ctx.from]
.children
.values()
- .map(|&child| def_map.module_id(child))
- .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db)))
+ .copied()
+ .chain(iter::successors(ctx.from.containing_module(db), |m| m.containing_module(db)))
.zip(iter::repeat(false))
.collect::<Vec<_>>();
- let def_map = def_map.crate_root().def_map(db);
+ let def_map =
+ if ctx.crate_root == ctx.from { ctx.from_def_map } else { ctx.crate_root.def_map(db) };
let mut block_def_map;
let mut cursor = 0;
@@ -595,17 +593,17 @@ fn find_local_import_locations(
continue;
}
*processed = true;
- let data = if module.block.is_some() {
+ let data = if module.block(db).is_some() {
// Re-query the block's DefMap
block_def_map = module.def_map(db);
- &block_def_map[module.local_id]
+ &block_def_map[module]
} else {
// Reuse the root DefMap
- &def_map[module.local_id]
+ &def_map[module]
};
if let Some((name, vis, declared)) = data.scope.name_of(item)
- && vis.is_visible_from(db, from)
+ && vis.is_visible_from(db, ctx.from)
{
let is_pub_or_explicit = match vis {
Visibility::Module(_, VisibilityExplicitness::Explicit) => {
@@ -632,7 +630,7 @@ fn find_local_import_locations(
// Descend into all modules visible from `from`.
for (module, vis) in data.scope.modules_in_scope() {
- if module.krate != from.krate {
+ if module.krate(db) != ctx.from.krate(db) {
// We don't need to look at modules from other crates as our item has to be in the
// current crate
continue;
@@ -641,7 +639,7 @@ fn find_local_import_locations(
continue;
}
- if vis.is_visible_from(db, from) {
+ if vis.is_visible_from(db, ctx.from) {
worklist.push((module, false));
}
}
@@ -694,7 +692,7 @@ mod tests {
.resolve_path(
local_def_map,
&db,
- module.local_id,
+ module,
&mod_path,
crate::item_scope::BuiltinShadowMode::Module,
None,
diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs
index 60cd66bf6b..1a2d5ebba4 100644
--- a/crates/hir-def/src/hir/generics.rs
+++ b/crates/hir-def/src/hir/generics.rs
@@ -20,7 +20,7 @@ pub type LocalLifetimeParamId = Idx<LifetimeParamData>;
/// Data about a generic type parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeParamData {
- /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
+ /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just
/// make it always be a value, giving impl trait a special name.
pub name: Option<Name>,
pub default: Option<TypeRefId>,
diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs
index 67cf466276..6c5d226cac 100644
--- a/crates/hir-def/src/import_map.rs
+++ b/crates/hir-def/src/import_map.rs
@@ -13,11 +13,11 @@ use stdx::format_to;
use triomphe::Arc;
use crate::{
- AssocItemId, AttrDefId, Complete, FxIndexMap, InternedModuleId, ModuleDefId, ModuleId, TraitId,
+ AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
attrs::AttrFlags,
db::DefDatabase,
item_scope::{ImportOrExternCrate, ItemInNs},
- nameres::{DefMap, assoc::TraitItems, crate_def_map},
+ nameres::{assoc::TraitItems, crate_def_map},
visibility::Visibility,
};
@@ -134,7 +134,7 @@ impl ImportMap {
let mut map = FxIndexMap::default();
// We look only into modules that are public(ly reexported), starting with the crate root.
- let root = def_map.module_id(DefMap::ROOT);
+ let root = def_map.root_module_id();
let mut worklist = vec![root];
let mut visited = FxHashSet::default();
@@ -142,13 +142,11 @@ impl ImportMap {
if !visited.insert(module) {
continue;
}
- let ext_def_map;
- let mod_data = if module.krate == krate {
- &def_map[module.local_id]
+ let mod_data = if module.krate(db) == krate {
+ &def_map[module]
} else {
// The crate might reexport a module defined in another crate.
- ext_def_map = module.def_map(db);
- &ext_def_map[module.local_id]
+ &module.def_map(db)[module]
};
let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
@@ -167,9 +165,7 @@ impl ImportMap {
} else {
match item {
ItemInNs::Types(id) | ItemInNs::Values(id) => match id {
- ModuleDefId::ModuleId(it) => {
- Some(AttrDefId::ModuleId(InternedModuleId::new(db, it)))
- }
+ ModuleDefId::ModuleId(it) => Some(AttrDefId::ModuleId(it)),
ModuleDefId::FunctionId(it) => Some(it.into()),
ModuleDefId::AdtId(it) => Some(it.into()),
ModuleDefId::EnumVariantId(it) => Some(it.into()),
@@ -640,9 +636,8 @@ mod tests {
assert!(def_map.block_id().is_none(), "block local items should not be in `ImportMap`");
while let Some(parent) = module.containing_module(db) {
- let parent_data = &def_map[parent.local_id];
- let (name, _) =
- parent_data.children.iter().find(|(_, id)| **id == module.local_id).unwrap();
+ let parent_data = &def_map[parent];
+ let (name, _) = parent_data.children.iter().find(|(_, id)| **id == module).unwrap();
segments.push(name);
module = parent;
}
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 1bfe649ebd..3ffeebfaf2 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -17,7 +17,7 @@ use thin_vec::ThinVec;
use crate::{
AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
- LocalModuleId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
+ Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
db::DefDatabase,
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
visibility::Visibility,
@@ -25,9 +25,9 @@ use crate::{
#[derive(Debug, Default)]
pub struct PerNsGlobImports {
- types: FxHashSet<(LocalModuleId, Name)>,
- values: FxHashSet<(LocalModuleId, Name)>,
- macros: FxHashSet<(LocalModuleId, Name)>,
+ types: FxHashSet<(ModuleId, Name)>,
+ values: FxHashSet<(ModuleId, Name)>,
+ macros: FxHashSet<(ModuleId, Name)>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -133,13 +133,13 @@ pub struct GlobId {
}
impl PerNsGlobImports {
- pub(crate) fn contains_type(&self, module_id: LocalModuleId, name: Name) -> bool {
+ pub(crate) fn contains_type(&self, module_id: ModuleId, name: Name) -> bool {
self.types.contains(&(module_id, name))
}
- pub(crate) fn contains_value(&self, module_id: LocalModuleId, name: Name) -> bool {
+ pub(crate) fn contains_value(&self, module_id: ModuleId, name: Name) -> bool {
self.values.contains(&(module_id, name))
}
- pub(crate) fn contains_macro(&self, module_id: LocalModuleId, name: Name) -> bool {
+ pub(crate) fn contains_macro(&self, module_id: ModuleId, name: Name) -> bool {
self.macros.contains(&(module_id, name))
}
}
@@ -261,14 +261,12 @@ impl ItemScope {
pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
let mut res = PerNs::none();
- let mut def_map;
let mut scope = self;
while let Some(&m) = scope.use_imports_macros.get(&ImportOrExternCrate::Import(import)) {
match m {
ImportOrDef::Import(i) => {
let module_id = i.use_.lookup(db).container;
- def_map = module_id.def_map(db);
- scope = &def_map[module_id.local_id].scope;
+ scope = &module_id.def_map(db)[module_id].scope;
import = i;
}
ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
@@ -283,8 +281,7 @@ impl ItemScope {
match m {
ImportOrDef::Import(i) => {
let module_id = i.use_.lookup(db).container;
- def_map = module_id.def_map(db);
- scope = &def_map[module_id.local_id].scope;
+ scope = &module_id.def_map(db)[module_id].scope;
import = i;
}
ImportOrDef::Def(def) => {
@@ -299,8 +296,7 @@ impl ItemScope {
match m {
ImportOrDef::Import(i) => {
let module_id = i.use_.lookup(db).container;
- def_map = module_id.def_map(db);
- scope = &def_map[module_id.local_id].scope;
+ scope = &module_id.def_map(db)[module_id].scope;
import = i;
}
ImportOrDef::Def(def) => {
@@ -578,7 +574,7 @@ impl ItemScope {
pub(crate) fn push_res_with_import(
&mut self,
glob_imports: &mut PerNsGlobImports,
- lookup: (LocalModuleId, Name),
+ lookup: (ModuleId, Name),
def: PerNs,
import: Option<ImportOrExternCrate>,
) -> bool {
@@ -922,10 +918,7 @@ impl ItemInNs {
/// Returns the crate defining this item (or `None` if `self` is built-in).
pub fn krate(&self, db: &dyn DefDatabase) -> Option<Crate> {
- match self {
- ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
- ItemInNs::Macros(id) => Some(id.module(db).krate),
- }
+ self.module(db).map(|module_id| module_id.krate(db))
}
pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 3f2cf09e21..9fdfb5f5b3 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -111,11 +111,12 @@ pub fn lang_items(db: &dyn DefDatabase, start_crate: Crate) -> LangItems {
// while nameres.
//
// See https://github.com/rust-lang/rust-analyzer/pull/20475 for details.
- for (_, (krate, _)) in crate_local_def_map(db, start_crate).local(db).extern_prelude() {
+ for (_, (module, _)) in crate_local_def_map(db, start_crate).local(db).extern_prelude() {
// Some crates declares themselves as extern crate like `extern crate self as core`.
// Ignore these to prevent cycles.
- if krate.krate != start_crate {
- result.merge_prefer_self(lang_items(db, krate.krate));
+ let krate = module.krate(db);
+ if krate != start_crate {
+ result.merge_prefer_self(lang_items(db, krate));
}
}
@@ -238,7 +239,7 @@ language_item_table! { LangItems =>
Clone, sym::clone, clone_trait, TraitId, GenericRequirement::None;
Sync, sym::sync, sync_trait, TraitId, GenericRequirement::Exact(0);
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, TraitId, GenericRequirement::None;
- /// The associated item of the [`DiscriminantKind`] trait.
+ /// The associated item of the `DiscriminantKind` trait.
Discriminant, sym::discriminant_type, discriminant_type, TypeAliasId, GenericRequirement::None;
PointeeTrait, sym::pointee_trait, pointee_trait, TraitId, GenericRequirement::None;
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index ad247e0d68..97af8ad93d 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -71,7 +71,6 @@ use hir_expand::{
name::Name,
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
};
-use la_arena::Idx;
use nameres::DefMap;
use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
use stdx::impl_from;
@@ -412,14 +411,14 @@ pub enum MacroExpander {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProcMacroLoc {
- pub container: CrateRootModuleId,
+ pub container: ModuleId,
pub id: AstId<ast::Fn>,
pub expander: CustomProcMacroExpander,
pub kind: ProcMacroKind,
pub edition: Edition,
}
impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
-impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId);
+impl_loc!(ProcMacroLoc, id: Fn, container: ModuleId);
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct BlockLoc {
@@ -429,164 +428,75 @@ pub struct BlockLoc {
}
impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
-/// A `ModuleId` that is always a crate's root module.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct CrateRootModuleId {
- krate: Crate,
-}
-
-impl CrateRootModuleId {
- pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
- crate_def_map(db, self.krate)
- }
-
- pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
- let def_map = crate_local_def_map(db, self.krate);
- (def_map.def_map(db), def_map.local(db))
- }
-
- pub fn krate(self) -> Crate {
- self.krate
- }
-}
-
-impl HasModule for CrateRootModuleId {
- #[inline]
- fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
- ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT }
- }
-
- #[inline]
- fn krate(&self, _db: &dyn DefDatabase) -> Crate {
- self.krate
- }
-}
-
-impl PartialEq<ModuleId> for CrateRootModuleId {
- fn eq(&self, other: &ModuleId) -> bool {
- other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
- }
-}
-impl PartialEq<CrateRootModuleId> for ModuleId {
- fn eq(&self, other: &CrateRootModuleId) -> bool {
- other == self
- }
-}
-
-impl From<CrateRootModuleId> for ModuleId {
- fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
- ModuleId { krate, block: None, local_id: DefMap::ROOT }
- }
-}
-
-impl From<CrateRootModuleId> for ModuleDefId {
- fn from(value: CrateRootModuleId) -> Self {
- ModuleDefId::ModuleId(value.into())
- }
-}
-
-impl From<Crate> for CrateRootModuleId {
- fn from(krate: Crate) -> Self {
- CrateRootModuleId { krate }
- }
-}
-
-impl TryFrom<ModuleId> for CrateRootModuleId {
- type Error = ();
-
- fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result<Self, Self::Error> {
- if block.is_none() && local_id == DefMap::ROOT {
- Ok(CrateRootModuleId { krate })
- } else {
- Err(())
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct ModuleId {
- krate: Crate,
+#[salsa_macros::tracked(debug)]
+#[derive(PartialOrd, Ord)]
+pub struct ModuleIdLt<'db> {
+ /// The crate this module belongs to.
+ pub krate: Crate,
/// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
/// `BlockId` of that block expression. If `None`, this module is part of the crate-level
/// `DefMap` of `krate`.
- block: Option<BlockId>,
- /// The module's ID in its originating `DefMap`.
- pub local_id: LocalModuleId,
+ pub block: Option<BlockId>,
}
+pub type ModuleId = ModuleIdLt<'static>;
+impl ModuleIdLt<'_> {
+ /// # Safety
+ ///
+ /// The caller must ensure that the `ModuleId` is not leaked outside of query computations.
+ pub unsafe fn to_static(self) -> ModuleId {
+ unsafe { std::mem::transmute(self) }
+ }
+}
impl ModuleId {
+ /// # Safety
+ ///
+ /// The caller must ensure that the `ModuleId` comes from the given database.
+ pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> {
+ unsafe { std::mem::transmute(self) }
+ }
+
pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
- match self.block {
+ match self.block(db) {
Some(block) => block_def_map(db, block),
- None => crate_def_map(db, self.krate),
+ None => crate_def_map(db, self.krate(db)),
}
}
pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
- match self.block {
+ match self.block(db) {
Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
None => {
- let def_map = crate_local_def_map(db, self.krate);
+ let def_map = crate_local_def_map(db, self.krate(db));
(def_map.def_map(db), def_map.local(db))
}
}
}
pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap {
- crate_local_def_map(db, self.krate).local(db)
+ crate_local_def_map(db, self.krate(db)).local(db)
}
pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap {
- crate_def_map(db, self.krate)
- }
-
- pub fn krate(self) -> Crate {
- self.krate
+ crate_def_map(db, self.krate(db))
}
pub fn name(self, db: &dyn DefDatabase) -> Option<Name> {
let def_map = self.def_map(db);
- let parent = def_map[self.local_id].parent?;
+ let parent = def_map[self].parent?;
def_map[parent].children.iter().find_map(|(name, module_id)| {
- if *module_id == self.local_id { Some(name.clone()) } else { None }
+ if *module_id == self { Some(name.clone()) } else { None }
})
}
/// Returns the module containing `self`, either the parent `mod`, or the module (or block) containing
/// the block, if `self` corresponds to a block expression.
pub fn containing_module(self, db: &dyn DefDatabase) -> Option<ModuleId> {
- self.def_map(db).containing_module(self.local_id)
- }
-
- pub fn containing_block(self) -> Option<BlockId> {
- self.block
- }
-
- pub fn is_block_module(self) -> bool {
- self.block.is_some() && self.local_id == DefMap::ROOT
+ self.def_map(db).containing_module(self)
}
- pub fn is_within_block(self) -> bool {
- self.block.is_some()
- }
-
- /// Returns the [`CrateRootModuleId`] for this module if it is the crate root module.
- pub fn as_crate_root(&self) -> Option<CrateRootModuleId> {
- if self.local_id == DefMap::ROOT && self.block.is_none() {
- Some(CrateRootModuleId { krate: self.krate })
- } else {
- None
- }
- }
-
- /// Returns the [`CrateRootModuleId`] for this module.
- pub fn derive_crate_root(&self) -> CrateRootModuleId {
- CrateRootModuleId { krate: self.krate }
- }
-
- /// Whether this module represents the crate root module
- pub fn is_crate_root(&self) -> bool {
- self.local_id == DefMap::ROOT && self.block.is_none()
+ pub fn is_block_module(self, db: &dyn DefDatabase) -> bool {
+ self.block(db).is_some() && self.def_map(db).root_module_id() == self
}
}
@@ -597,9 +507,6 @@ impl HasModule for ModuleId {
}
}
-/// An ID of a module, **local** to a `DefMap`.
-pub type LocalModuleId = Idx<nameres::ModuleData>;
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
pub struct FieldId {
// FIXME: Store this as an erased `salsa::Id` to save space
@@ -682,7 +589,7 @@ pub struct LifetimeParamId {
pub local_id: LocalLifetimeParamId,
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
pub enum ItemContainerId {
ExternBlockId(ExternBlockId),
ModuleId(ModuleId),
@@ -956,16 +863,9 @@ impl CallableDefId {
}
}
-// FIXME: We probably should use this in more places.
-/// This is used to avoid interning the whole `AttrDefId`, so we intern just modules and not everything.
-#[salsa_macros::interned(debug, no_lifetime)]
-pub struct InternedModuleId {
- pub loc: ModuleId,
-}
-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa_macros::Supertype)]
pub enum AttrDefId {
- ModuleId(InternedModuleId),
+ ModuleId(ModuleId),
AdtId(AdtId),
FunctionId(FunctionId),
EnumVariantId(EnumVariantId),
@@ -1058,7 +958,7 @@ pub trait HasModule {
#[inline]
#[doc(alias = "crate")]
fn krate(&self, db: &dyn DefDatabase) -> Crate {
- self.module(db).krate
+ self.module(db).krate(db)
}
}
@@ -1162,7 +1062,7 @@ impl HasModule for Macro2Id {
impl HasModule for ProcMacroId {
#[inline]
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
- self.lookup(db).container.into()
+ self.lookup(db).container
}
}
@@ -1235,7 +1135,7 @@ impl HasModule for GenericDefId {
impl HasModule for AttrDefId {
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
match self {
- AttrDefId::ModuleId(it) => it.loc(db),
+ AttrDefId::ModuleId(it) => *it,
AttrDefId::AdtId(it) => it.module(db),
AttrDefId::FunctionId(it) => it.module(db),
AttrDefId::EnumVariantId(it) => it.module(db),
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 947a54f888..a12674f353 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
};
}
-struct#0:MacroRules[BE8F, 0]@58..64#14336# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#14336#
- map#0:MacroRules[BE8F, 0]@86..89#14336#:#0:MacroRules[BE8F, 0]@89..90#14336# #0:MacroRules[BE8F, 0]@89..90#14336#::#0:MacroRules[BE8F, 0]@91..93#14336#std#0:MacroRules[BE8F, 0]@93..96#14336#::#0:MacroRules[BE8F, 0]@96..98#14336#collections#0:MacroRules[BE8F, 0]@98..109#14336#::#0:MacroRules[BE8F, 0]@109..111#14336#HashSet#0:MacroRules[BE8F, 0]@111..118#14336#<#0:MacroRules[BE8F, 0]@118..119#14336#(#0:MacroRules[BE8F, 0]@119..120#14336#)#0:MacroRules[BE8F, 0]@120..121#14336#>#0:MacroRules[BE8F, 0]@121..122#14336#,#0:MacroRules[BE8F, 0]@122..123#14336#
-}#0:MacroRules[BE8F, 0]@132..133#14336#
+struct#0:MacroRules[BE8F, 0]@58..64#15360# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#15360#
+ map#0:MacroRules[BE8F, 0]@86..89#15360#:#0:MacroRules[BE8F, 0]@89..90#15360# #0:MacroRules[BE8F, 0]@89..90#15360#::#0:MacroRules[BE8F, 0]@91..93#15360#std#0:MacroRules[BE8F, 0]@93..96#15360#::#0:MacroRules[BE8F, 0]@96..98#15360#collections#0:MacroRules[BE8F, 0]@98..109#15360#::#0:MacroRules[BE8F, 0]@109..111#15360#HashSet#0:MacroRules[BE8F, 0]@111..118#15360#<#0:MacroRules[BE8F, 0]@118..119#15360#(#0:MacroRules[BE8F, 0]@119..120#15360#)#0:MacroRules[BE8F, 0]@120..121#15360#>#0:MacroRules[BE8F, 0]@121..122#15360#,#0:MacroRules[BE8F, 0]@122..123#15360#
+}#0:MacroRules[BE8F, 0]@132..133#15360#
"#]],
);
}
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
#[macro_use]
mod foo;
-struct#1:MacroRules[DB0C, 0]@59..65#14336# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#14336#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#14336#;#1:MacroRules[DB0C, 0]@75..76#14336#
+struct#1:MacroRules[DB0C, 0]@59..65#15360# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#15360#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#15360#;#1:MacroRules[DB0C, 0]@75..76#15360#
"#]],
);
}
@@ -423,10 +423,10 @@ m! { foo, bar }
macro_rules! m {
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
}
-impl#\14336# Bar#\14336# {#\14336#
- fn#\14336# foo#\ROOT2024#(#\14336#)#\14336# {#\14336#}#\14336#
- fn#\14336# bar#\ROOT2024#(#\14336#)#\14336# {#\14336#}#\14336#
-}#\14336#
+impl#\15360# Bar#\15360# {#\15360#
+ fn#\15360# foo#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360#
+ fn#\15360# bar#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360#
+}#\15360#
"#]],
);
}
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index 98b3115814..78af976e1b 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -131,8 +131,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
let krate = db.fetch_test_crate();
let def_map = crate_def_map(&db, krate);
- let local_id = DefMap::ROOT;
- let source = def_map[local_id].definition_source(&db);
+ let source = def_map[def_map.root].definition_source(&db);
let source_file = match source.value {
ModuleSource::SourceFile(it) => it,
ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(),
@@ -209,7 +208,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
expanded_text.replace_range(range, &text);
}
- for decl_id in def_map[local_id].scope.declarations() {
+ for decl_id in def_map[def_map.root].scope.declarations() {
// FIXME: I'm sure there's already better way to do this
let src = match decl_id {
ModuleDefId::AdtId(AdtId::StructId(struct_id)) => {
@@ -260,7 +259,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
}
}
- for impl_id in def_map[local_id].scope.impls() {
+ for impl_id in def_map[def_map.root].scope.impls() {
let src = impl_id.lookup(&db).source(&db);
if let Some(macro_file) = src.file_id.macro_file()
&& let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db)
diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index 5216246910..6f30ca04af 100644
--- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -341,3 +341,22 @@ struct Foo;
#[helper_should_be_ignored] struct Foo;"#]],
);
}
+
+#[test]
+fn attribute_macro_stripping_with_cfg() {
+ check(
+ r#"
+//- proc_macros: generate_suffixed_type
+#[cfg(all())]
+#[proc_macros::generate_suffixed_type]
+struct S;
+"#,
+ expect![[r#"
+#[cfg(all())]
+#[proc_macros::generate_suffixed_type]
+struct S;
+
+struct S;
+struct SSuffix;"#]],
+ );
+}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 5f45e188e0..3f29619bcb 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -58,7 +58,7 @@ pub mod proc_macro;
#[cfg(test)]
mod tests;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut, Index, IndexMut};
use base_db::Crate;
use hir_expand::{
@@ -67,7 +67,6 @@ use hir_expand::{
};
use intern::Symbol;
use itertools::Itertools;
-use la_arena::Arena;
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to;
@@ -76,8 +75,8 @@ use triomphe::Arc;
use tt::TextRange;
use crate::{
- AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
- LocalModuleId, Lookup, MacroCallStyles, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
+ AstId, BlockId, BlockLoc, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles,
+ MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId,
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::TreeId,
@@ -109,7 +108,7 @@ pub struct LocalDefMap {
// FIXME: There are probably some other things that could be here, but this is less severe and you
// need to be careful with things that block def maps also have.
/// The extern prelude which contains all root modules of external crates that are in scope.
- extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
+ extern_prelude: FxIndexMap<Name, (ModuleId, Option<ExternCrateId>)>,
}
impl std::hash::Hash for LocalDefMap {
@@ -135,8 +134,7 @@ impl LocalDefMap {
pub(crate) fn extern_prelude(
&self,
- ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
- {
+ ) -> impl DoubleEndedIterator<Item = (&Name, (ModuleId, Option<ExternCrateId>))> + '_ {
self.extern_prelude.iter().map(|(name, &def)| (name, def))
}
}
@@ -157,8 +155,9 @@ pub struct DefMap {
/// When this is a block def map, this will hold the block id of the block and module that
/// contains this block.
block: Option<BlockInfo>,
+ pub root: ModuleId,
/// The modules and their data declared in this crate.
- pub modules: Arena<ModuleData>,
+ pub modules: ModulesMap,
/// The prelude module for this crate. This either comes from an import
/// marked with the `prelude_import` attribute, or (in the normal case) from
/// a dependency (`std` or `core`).
@@ -245,33 +244,22 @@ struct BlockInfo {
/// The `BlockId` this `DefMap` was created from.
block: BlockId,
/// The containing module.
- parent: BlockRelativeModuleId,
+ parent: ModuleId,
}
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-struct BlockRelativeModuleId {
- block: Option<BlockId>,
- local_id: LocalModuleId,
-}
-
-impl BlockRelativeModuleId {
- fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
- self.into_module(krate).def_map(db)
- }
-
- fn into_module(self, krate: Crate) -> ModuleId {
- ModuleId { krate, block: self.block, local_id: self.local_id }
- }
+impl std::ops::Index<ModuleId> for DefMap {
+ type Output = ModuleData;
- fn is_block_module(self) -> bool {
- self.block.is_some() && self.local_id == DefMap::ROOT
+ fn index(&self, id: ModuleId) -> &ModuleData {
+ self.modules
+ .get(&id)
+ .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap {:#?}: {id:#?}", self.root))
}
}
-impl std::ops::Index<LocalModuleId> for DefMap {
- type Output = ModuleData;
- fn index(&self, id: LocalModuleId) -> &ModuleData {
- &self.modules[id]
+impl std::ops::IndexMut<ModuleId> for DefMap {
+ fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData {
+ &mut self.modules[id]
}
}
@@ -358,8 +346,8 @@ pub struct ModuleData {
/// Parent module in the same `DefMap`.
///
/// [`None`] for block modules because they are always its `DefMap`'s root.
- pub parent: Option<LocalModuleId>,
- pub children: FxIndexMap<Name, LocalModuleId>,
+ pub parent: Option<ModuleId>,
+ pub children: FxIndexMap<Name, ModuleId>,
pub scope: ItemScope,
}
@@ -392,11 +380,19 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
.entered();
let root_file_id = crate_id.root_file_id(db);
- let module_data =
- ModuleData::new(ModuleOrigin::CrateRoot { definition: root_file_id }, Visibility::Public);
+ let module_data = ModuleData::new(
+ ModuleOrigin::CrateRoot { definition: root_file_id },
+ Visibility::Public,
+ None,
+ );
- let def_map =
- DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
+ let def_map = DefMap::empty(
+ db,
+ crate_id,
+ Arc::new(DefMapCrateData::new(krate.edition)),
+ module_data,
+ None,
+ );
let (def_map, local_def_map) =
collector::collect_defs(db, def_map, TreeId::new(root_file_id.into(), None), None);
@@ -407,22 +403,18 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
let BlockLoc { ast_id, module } = block_id.lookup(db);
- let visibility = Visibility::Module(
- ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
- VisibilityExplicitness::Implicit,
- );
+ let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit);
let module_data =
- ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
+ ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility, None);
- let local_def_map = crate_local_def_map(db, module.krate);
+ let krate = module.krate(db);
+ let local_def_map = crate_local_def_map(db, krate);
let def_map = DefMap::empty(
- module.krate,
+ db,
+ krate,
local_def_map.def_map(db).data.clone(),
module_data,
- Some(BlockInfo {
- block: block_id,
- parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
- }),
+ Some(BlockInfo { block: block_id, parent: module }),
);
let (def_map, _) = collector::collect_defs(
@@ -435,25 +427,24 @@ pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
}
impl DefMap {
- /// The module id of a crate or block root.
- pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
-
pub fn edition(&self) -> Edition {
self.data.edition
}
fn empty(
+ db: &dyn DefDatabase,
krate: Crate,
crate_data: Arc<DefMapCrateData>,
module_data: ModuleData,
block: Option<BlockInfo>,
) -> DefMap {
- let mut modules: Arena<ModuleData> = Arena::default();
- let root = modules.alloc(module_data);
- assert_eq!(root, Self::ROOT);
+ let mut modules = ModulesMap::new();
+ let root = unsafe { ModuleIdLt::new(db, krate, block.map(|it| it.block)).to_static() };
+ modules.insert(root, module_data);
DefMap {
block,
+ root,
modules,
krate,
prelude: None,
@@ -471,6 +462,7 @@ impl DefMap {
diagnostics,
modules,
derive_helpers_in_scope,
+ root: _,
block: _,
krate: _,
prelude: _,
@@ -495,7 +487,7 @@ impl DefMap {
&'a self,
db: &'a dyn DefDatabase,
file_id: FileId,
- ) -> impl Iterator<Item = LocalModuleId> + 'a {
+ ) -> impl Iterator<Item = ModuleId> + 'a {
self.modules
.iter()
.filter(move |(_id, data)| {
@@ -504,7 +496,7 @@ impl DefMap {
.map(|(id, _data)| id)
}
- pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
+ pub fn modules(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ {
self.modules.iter()
}
@@ -543,40 +535,32 @@ impl DefMap {
self.krate
}
- pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
- let block = self.block.map(|b| b.block);
- ModuleId { krate: self.krate, local_id, block }
- }
-
- pub fn crate_root(&self) -> CrateRootModuleId {
- CrateRootModuleId { krate: self.krate }
+ #[inline]
+ pub fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
+ match self.block {
+ Some(_) => crate_def_map(db, self.krate()).root,
+ None => self.root,
+ }
}
/// This is the same as [`Self::crate_root`] for crate def maps, but for block def maps, it
/// returns the root block module.
pub fn root_module_id(&self) -> ModuleId {
- self.module_id(Self::ROOT)
+ self.root
}
/// If this `DefMap` is for a block expression, returns the module containing the block (which
/// might again be a block, or a module inside a block).
pub fn parent(&self) -> Option<ModuleId> {
- let BlockRelativeModuleId { block, local_id } = self.block?.parent;
- Some(ModuleId { krate: self.krate, block, local_id })
+ Some(self.block?.parent)
}
/// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
/// the block, if `self` corresponds to a block expression.
- pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
+ pub fn containing_module(&self, local_mod: ModuleId) -> Option<ModuleId> {
match self[local_mod].parent {
- Some(parent) => Some(self.module_id(parent)),
- None => {
- self.block.map(
- |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
- ModuleId { krate: self.krate, block, local_id }
- },
- )
- }
+ Some(parent) => Some(parent),
+ None => self.block.map(|BlockInfo { parent, .. }| parent),
}
}
@@ -594,30 +578,21 @@ impl DefMap {
// even), as this should be a great debugging aid.
pub fn dump(&self, db: &dyn DefDatabase) -> String {
let mut buf = String::new();
- let mut arc;
let mut current_map = self;
while let Some(block) = current_map.block {
- go(&mut buf, db, current_map, "(block scope)", Self::ROOT);
+ go(&mut buf, db, current_map, "(block scope)", current_map.root);
buf.push('\n');
- arc = block.parent.def_map(db, self.krate);
- current_map = arc;
+ current_map = block.parent.def_map(db);
}
- go(&mut buf, db, current_map, "crate", Self::ROOT);
+ go(&mut buf, db, current_map, "crate", current_map.root);
return buf;
- fn go(
- buf: &mut String,
- db: &dyn DefDatabase,
- map: &DefMap,
- path: &str,
- module: LocalModuleId,
- ) {
+ fn go(buf: &mut String, db: &dyn DefDatabase, map: &DefMap, path: &str, module: ModuleId) {
format_to!(buf, "{}\n", path);
- map.modules[module].scope.dump(db, buf);
+ map[module].scope.dump(db, buf);
- for (name, child) in
- map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
+ for (name, child) in map[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
{
let path = format!("{path}::{}", name.display(db, Edition::LATEST));
buf.push('\n');
@@ -625,20 +600,6 @@ impl DefMap {
}
}
}
-
- pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
- let mut buf = String::new();
- let mut arc;
- let mut current_map = self;
- while let Some(block) = current_map.block {
- format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
- arc = block.parent.def_map(db, self.krate);
- current_map = arc;
- }
-
- format_to!(buf, "crate scope\n");
- buf
- }
}
impl DefMap {
@@ -658,7 +619,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
expected_macro_subns: Option<MacroSubNs>,
@@ -681,7 +642,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
@@ -704,16 +665,16 @@ impl DefMap {
pub(crate) fn with_ancestor_maps<T>(
&self,
db: &dyn DefDatabase,
- local_mod: LocalModuleId,
- f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
+ local_mod: ModuleId,
+ f: &mut dyn FnMut(&DefMap, ModuleId) -> Option<T>,
) -> Option<T> {
if let Some(it) = f(self, local_mod) {
return Some(it);
}
let mut block = self.block;
while let Some(block_info) = block {
- let parent = block_info.parent.def_map(db, self.krate);
- if let Some(it) = f(parent, block_info.parent.local_id) {
+ let parent = block_info.parent.def_map(db);
+ if let Some(it) = f(parent, block_info.parent) {
return Some(it);
}
block = parent.block;
@@ -724,11 +685,15 @@ impl DefMap {
}
impl ModuleData {
- pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
+ pub(crate) fn new(
+ origin: ModuleOrigin,
+ visibility: Visibility,
+ parent: Option<ModuleId>,
+ ) -> Self {
ModuleData {
origin,
visibility,
- parent: None,
+ parent,
children: Default::default(),
scope: ItemScope::default(),
}
@@ -739,7 +704,7 @@ impl ModuleData {
self.origin.definition_source(db)
}
- /// Same as [`definition_source`] but only returns the file id to prevent parsing the ASt.
+ /// Same as [`ModuleData::definition_source`] but only returns the file id to prevent parsing the ASt.
pub fn definition_source_file_id(&self) -> HirFileId {
match self.origin {
ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
@@ -852,3 +817,53 @@ fn sub_namespace_match(
None => true,
}
}
+
+/// A newtype wrapper around `FxHashMap<ModuleId, ModuleData>` that implements `IndexMut`.
+#[derive(Debug, PartialEq, Eq)]
+pub struct ModulesMap {
+ inner: FxIndexMap<ModuleId, ModuleData>,
+}
+
+impl ModulesMap {
+ fn new() -> Self {
+ Self { inner: FxIndexMap::default() }
+ }
+
+ fn iter(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ {
+ self.inner.iter().map(|(&k, v)| (k, v))
+ }
+
+ fn iter_mut(&mut self) -> impl Iterator<Item = (ModuleId, &mut ModuleData)> + '_ {
+ self.inner.iter_mut().map(|(&k, v)| (k, v))
+ }
+}
+
+impl Deref for ModulesMap {
+ type Target = FxIndexMap<ModuleId, ModuleData>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl DerefMut for ModulesMap {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.inner
+ }
+}
+
+impl Index<ModuleId> for ModulesMap {
+ type Output = ModuleData;
+
+ fn index(&self, id: ModuleId) -> &ModuleData {
+ self.inner.get(&id).unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
+ }
+}
+
+impl IndexMut<ModuleId> for ModulesMap {
+ fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData {
+ self.inner
+ .get_mut(&id)
+ .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
+ }
+}
diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs
index b67853347b..9d2b2109fb 100644
--- a/crates/hir-def/src/nameres/assoc.rs
+++ b/crates/hir-def/src/nameres/assoc.rs
@@ -165,7 +165,7 @@ impl<'a> AssocItemCollector<'a> {
local_def_map,
ast_id_map: db.ast_id_map(file_id),
span_map: db.span_map(file_id),
- cfg_options: module_id.krate.cfg_options(db),
+ cfg_options: module_id.krate(db).cfg_options(db),
file_id,
container,
items: Vec::new(),
@@ -197,7 +197,7 @@ impl<'a> AssocItemCollector<'a> {
AttrsOrCfg::Enabled { attrs } => attrs,
AttrsOrCfg::CfgDisabled(cfg) => {
self.diagnostics.push(DefDiagnostic::unconfigured_code(
- self.module_id.local_id,
+ self.module_id,
InFile::new(self.file_id, ast_id.erase()),
cfg.0,
self.cfg_options.clone(),
@@ -213,7 +213,7 @@ impl<'a> AssocItemCollector<'a> {
match self.def_map.resolve_attr_macro(
self.local_def_map,
self.db,
- self.module_id.local_id,
+ self.module_id,
ast_id_with_path,
attr,
attr_id,
@@ -226,9 +226,9 @@ impl<'a> AssocItemCollector<'a> {
// crate failed), skip expansion like we would if it was
// disabled. This is analogous to the handling in
// `DefCollector::collect_macros`.
- if let Some(err) = exp.as_expand_error(self.module_id.krate) {
+ if let Some(err) = exp.as_expand_error(self.module_id.krate(self.db)) {
self.diagnostics.push(DefDiagnostic::macro_error(
- self.module_id.local_id,
+ self.module_id,
ast_id,
(*attr.path).clone(),
err,
@@ -244,7 +244,7 @@ impl<'a> AssocItemCollector<'a> {
Ok(_) => (),
Err(_) => {
self.diagnostics.push(DefDiagnostic::unresolved_macro_call(
- self.module_id.local_id,
+ self.module_id,
MacroCallKind::Attr {
ast_id,
attr_args: None,
@@ -307,7 +307,7 @@ impl<'a> AssocItemCollector<'a> {
.resolve_path(
self.local_def_map,
self.db,
- self.module_id.local_id,
+ self.module_id,
path,
crate::item_scope::BuiltinShadowMode::Other,
Some(MacroSubNs::Bang),
@@ -322,7 +322,7 @@ impl<'a> AssocItemCollector<'a> {
&path,
ctxt,
ExpandTo::Items,
- self.module_id.krate(),
+ self.module_id.krate(self.db),
resolver,
&mut |ptr, call_id| {
self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id))
@@ -338,7 +338,7 @@ impl<'a> AssocItemCollector<'a> {
},
Err(_) => {
self.diagnostics.push(DefDiagnostic::unresolved_macro_call(
- self.module_id.local_id,
+ self.module_id,
MacroCallKind::FnLike {
ast_id,
expand_to: ExpandTo::Items,
diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs
index fb755026c3..ec05c02bd6 100644
--- a/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/crates/hir-def/src/nameres/attr_resolution.rs
@@ -12,7 +12,7 @@ use syntax::ast;
use triomphe::Arc;
use crate::{
- AstIdWithPath, LocalModuleId, MacroId, UnresolvedMacro,
+ AstIdWithPath, MacroId, ModuleId, UnresolvedMacro,
db::DefDatabase,
item_scope::BuiltinShadowMode,
nameres::{LocalDefMap, path_resolution::ResolveMode},
@@ -33,7 +33,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- original_module: LocalModuleId,
+ original_module: ModuleId,
ast_id: AstIdWithPath<ast::Item>,
attr: &Attr,
attr_id: AttrId,
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 9aa7febdfd..08edf41c56 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -3,7 +3,7 @@
//! `DefCollector::collect` contains the fixed-point iteration loop which
//! resolves imports and expands macros.
-use std::{cmp::Ordering, iter, mem};
+use std::{iter, mem};
use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
use cfg::{CfgAtom, CfgExpr, CfgOptions};
@@ -27,12 +27,11 @@ use syntax::ast;
use triomphe::Arc;
use crate::{
- AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
- ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern,
- ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
- MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
- ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId,
- UseLoc,
+ AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, EnumLoc, ExternBlockLoc, ExternCrateId,
+ ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, ItemContainerId, Lookup,
+ Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags,
+ ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc,
+ UnionLoc, UnresolvedMacro, UseId, UseLoc,
db::DefDatabase,
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
item_tree::{
@@ -177,14 +176,14 @@ impl Import {
#[derive(Debug, Eq, PartialEq)]
struct ImportDirective {
/// The module this import directive is in.
- module_id: LocalModuleId,
+ module_id: ModuleId,
import: Import,
status: PartialResolvedImport,
}
#[derive(Clone, Debug, Eq, PartialEq)]
struct MacroDirective<'db> {
- module_id: LocalModuleId,
+ module_id: ModuleId,
depth: usize,
kind: MacroDirectiveKind<'db>,
container: ItemContainerId,
@@ -224,7 +223,7 @@ struct DefCollector<'db> {
crate_local_def_map: Option<&'db LocalDefMap>,
// The dependencies of the current crate, including optional deps like `test`.
deps: FxIndexMap<Name, BuiltDependency>,
- glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
+ glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, Visibility, GlobId)>>,
unresolved_imports: Vec<ImportDirective>,
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
unresolved_macros: Vec<MacroDirective<'db>>,
@@ -232,7 +231,7 @@ struct DefCollector<'db> {
// resolve. When we emit diagnostics for unresolved imports, we only do so if the import
// doesn't start with an unresolved crate's name.
unresolved_extern_crates: FxHashSet<Name>,
- mod_dirs: FxHashMap<LocalModuleId, ModDir>,
+ mod_dirs: FxHashMap<ModuleId, ModDir>,
cfg_options: &'db CfgOptions,
/// List of procedural macros defined by this crate. This is read from the dynamic library
/// built by the build system, and is the list of proc-macros we can actually expand. It is
@@ -337,9 +336,14 @@ impl<'db> DefCollector<'db> {
continue;
}
- self.local_def_map
- .extern_prelude
- .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
+ // This eagerly draws a dependency edge between the crate def maps even if the
+ // things the crates are not used. This is not great, but at the same time we would
+ // like to compute our dependency def maps in parallel here anyways in the future
+ // which will have the same effect.
+ self.local_def_map.extern_prelude.insert(
+ name.clone(),
+ (crate_def_map(self.db, dep.crate_id).root_module_id(), None),
+ );
}
}
@@ -349,10 +353,11 @@ impl<'db> DefCollector<'db> {
return;
}
+ let module_id = self.def_map.root;
ModCollector {
def_collector: self,
macro_depth: 0,
- module_id: DefMap::ROOT,
+ module_id,
tree_id: TreeId::new(file_id.into(), None),
item_tree,
mod_dir: ModDir::root(),
@@ -367,10 +372,11 @@ impl<'db> DefCollector<'db> {
if is_cfg_enabled {
self.inject_prelude();
+ let module_id = self.def_map.root;
ModCollector {
def_collector: self,
macro_depth: 0,
- module_id: DefMap::ROOT,
+ module_id,
tree_id,
item_tree,
mod_dir: ModDir::root(),
@@ -433,7 +439,8 @@ impl<'db> DefCollector<'db> {
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
// exported in type/value namespace. This function reduces the visibility of all items
// in the crate root that aren't proc macros.
- let root = &mut self.def_map.modules[DefMap::ROOT];
+ let module_id = self.def_map.root_module_id();
+ let root = &mut self.def_map.modules[module_id];
root.scope.censor_non_proc_macros(self.def_map.krate);
}
}
@@ -537,7 +544,7 @@ impl<'db> DefCollector<'db> {
let (per_ns, _) = self.def_map.resolve_path(
self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
- DefMap::ROOT,
+ self.def_map.root_module_id(),
&path,
BuiltinShadowMode::Other,
None,
@@ -592,7 +599,7 @@ impl<'db> DefCollector<'db> {
};
let proc_macro_id = ProcMacroLoc {
- container: self.def_map.crate_root(),
+ container: self.def_map.root_module_id(),
id: ast_id,
expander,
kind,
@@ -636,7 +643,7 @@ impl<'db> DefCollector<'db> {
/// ```
fn define_macro_rules(
&mut self,
- module_id: LocalModuleId,
+ module_id: ModuleId,
name: Name,
macro_: MacroRulesId,
export: bool,
@@ -648,7 +655,7 @@ impl<'db> DefCollector<'db> {
// In Rust, `#[macro_export]` macros are unconditionally visible at the
// crate root, even if the parent modules is **not** visible.
if export {
- let module_id = DefMap::ROOT;
+ let module_id = self.def_map.root;
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
@@ -666,7 +673,7 @@ impl<'db> DefCollector<'db> {
/// the definition of current module.
/// And also, `macro_use` on a module will import all legacy macros visible inside to
/// current legacy scope, with possible shadowing.
- fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) {
+ fn define_legacy_macro(&mut self, module_id: ModuleId, name: Name, mac: MacroId) {
// Always shadowing
self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
}
@@ -676,7 +683,7 @@ impl<'db> DefCollector<'db> {
/// The scoped of macro 2.0 macro is equal to normal function
fn define_macro_def(
&mut self,
- module_id: LocalModuleId,
+ module_id: ModuleId,
name: Name,
macro_: Macro2Id,
vis: &RawVisibility,
@@ -705,7 +712,7 @@ impl<'db> DefCollector<'db> {
/// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
/// And unconditionally exported.
fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
- let module_id = DefMap::ROOT;
+ let module_id = self.def_map.root;
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
@@ -730,7 +737,7 @@ impl<'db> DefCollector<'db> {
let def_map = crate_def_map(self.db, krate);
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
// macros.
- let root_scope = &def_map[DefMap::ROOT].scope;
+ let root_scope = &def_map[def_map.root].scope;
match names {
Some(names) => {
for name in names {
@@ -803,7 +810,7 @@ impl<'db> DefCollector<'db> {
res
}
- fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
+ fn resolve_import(&self, module_id: ModuleId, import: &Import) -> PartialResolvedImport {
let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db, Edition::LATEST))
.entered();
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
@@ -916,11 +923,10 @@ impl<'db> DefCollector<'db> {
// implementation seems to work the same though.
cov_mark::hit!(std_prelude);
self.def_map.prelude = Some((m, Some(id)));
- } else if m.krate != self.def_map.krate {
+ } else if m.krate(self.db) != self.def_map.krate {
cov_mark::hit!(glob_across_crates);
// glob import from other crate => we can just import everything once
- let item_map = m.def_map(self.db);
- let scope = &item_map[m.local_id].scope;
+ let scope = &m.def_map(self.db)[m].scope;
// Module scoped macros is included
let items = scope
@@ -942,12 +948,10 @@ impl<'db> DefCollector<'db> {
// glob import from same crate => we do an initial
// import, and then need to propagate any further
// additions
- let def_map;
- let scope = if m.block == self.def_map.block_id() {
- &self.def_map[m.local_id].scope
+ let scope = if m.block(self.db) == self.def_map.block_id() {
+ &self.def_map[m].scope
} else {
- def_map = m.def_map(self.db);
- &def_map[m.local_id].scope
+ &m.def_map(self.db)[m].scope
};
// Module scoped macros is included
@@ -976,11 +980,12 @@ impl<'db> DefCollector<'db> {
Some(ImportOrExternCrate::Glob(glob)),
);
// record the glob import in case we add further items
- let glob_imports = self.glob_imports.entry(m.local_id).or_default();
+ let glob_imports = self.glob_imports.entry(m).or_default();
match glob_imports.iter_mut().find(|(mid, _, _)| *mid == module_id) {
None => glob_imports.push((module_id, vis, glob)),
Some((_, old_vis, _)) => {
- if let Some(new_vis) = old_vis.max(vis, &self.def_map) {
+ if let Some(new_vis) = old_vis.max(self.db, vis, &self.def_map)
+ {
*old_vis = new_vis;
}
}
@@ -1056,20 +1061,19 @@ impl<'db> DefCollector<'db> {
fn update(
&mut self,
// The module for which `resolutions` have been resolve
- module_id: LocalModuleId,
+ module_id: ModuleId,
resolutions: &[(Option<Name>, PerNs)],
// Visibility this import will have
vis: Visibility,
import: Option<ImportOrExternCrate>,
) {
- self.db.unwind_if_revision_cancelled();
self.update_recursive(module_id, resolutions, vis, import, 0)
}
fn update_recursive(
&mut self,
// The module for which `resolutions` have been resolved.
- module_id: LocalModuleId,
+ module_id: ModuleId,
resolutions: &[(Option<Name>, PerNs)],
// All resolutions are imported with this visibility; the visibilities in
// the `PerNs` values are ignored and overwritten
@@ -1104,7 +1108,7 @@ impl<'db> DefCollector<'db> {
let should_update = match old_vis {
None => true,
Some(old_vis) => {
- let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
+ let max_vis = old_vis.max(self.db, vis, &self.def_map).unwrap_or_else(|| {
panic!("`Tr as _` imports with unrelated visibilities {old_vis:?} and {vis:?} (trait {tr:?})");
});
@@ -1146,7 +1150,7 @@ impl<'db> DefCollector<'db> {
.collect::<Vec<_>>();
for (glob_importing_module, glob_import_vis, glob) in glob_imports {
- let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
+ let vis = glob_import_vis.min(self.db, vis, &self.def_map).unwrap_or(glob_import_vis);
self.update_recursive(
glob_importing_module,
resolutions,
@@ -1159,20 +1163,20 @@ impl<'db> DefCollector<'db> {
fn push_res_and_update_glob_vis(
&mut self,
- module_id: LocalModuleId,
+ module_id: ModuleId,
name: &Name,
mut defs: PerNs,
vis: Visibility,
def_import_type: Option<ImportOrExternCrate>,
) -> bool {
if let Some(def) = defs.types.as_mut() {
- def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
+ def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis);
}
if let Some(def) = defs.values.as_mut() {
- def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
+ def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis);
}
if let Some(def) = defs.macros.as_mut() {
- def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
+ def.vis = def.vis.min(self.db, vis, &self.def_map).unwrap_or(vis);
}
let mut changed = false;
@@ -1188,7 +1192,7 @@ impl<'db> DefCollector<'db> {
&& def.def == prev_def.def
&& self.from_glob_import.contains_type(module_id, name.clone())
&& def.vis != prev_def.vis
- && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
+ && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis)
{
changed = true;
// This import is being handled here, don't pass it down to
@@ -1202,7 +1206,7 @@ impl<'db> DefCollector<'db> {
&& def.def == prev_def.def
&& self.from_glob_import.contains_value(module_id, name.clone())
&& def.vis != prev_def.vis
- && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
+ && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis)
{
changed = true;
// See comment above.
@@ -1215,7 +1219,7 @@ impl<'db> DefCollector<'db> {
&& def.def == prev_def.def
&& self.from_glob_import.contains_macro(module_id, name.clone())
&& def.vis != prev_def.vis
- && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis)
+ && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis)
{
changed = true;
// See comment above.
@@ -1555,7 +1559,7 @@ impl<'db> DefCollector<'db> {
fn collect_macro_expansion(
&mut self,
- module_id: LocalModuleId,
+ module_id: ModuleId,
macro_call_id: MacroCallId,
depth: usize,
container: ItemContainerId,
@@ -1713,7 +1717,7 @@ impl<'db> DefCollector<'db> {
struct ModCollector<'a, 'db> {
def_collector: &'a mut DefCollector<'db>,
macro_depth: usize,
- module_id: LocalModuleId,
+ module_id: ModuleId,
tree_id: TreeId,
item_tree: &'db ItemTree,
mod_dir: ModDir,
@@ -1721,14 +1725,13 @@ struct ModCollector<'a, 'db> {
impl ModCollector<'_, '_> {
fn collect_in_top_module(&mut self, items: &[ModItemId]) {
- let module = self.def_collector.def_map.module_id(self.module_id);
- self.collect(items, module.into())
+ self.collect(items, self.module_id.into())
}
fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
let krate = self.def_collector.def_map.krate;
- let is_crate_root =
- self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none();
+ let is_crate_root = self.module_id == self.def_collector.def_map.root
+ && self.def_collector.def_map.block.is_none();
// Note: don't assert that inserted value is fresh: it's simply not true
// for macros.
@@ -1737,10 +1740,10 @@ impl ModCollector<'_, '_> {
// Prelude module is always considered to be `#[macro_use]`.
if let Some((prelude_module, _use)) = self.def_collector.def_map.prelude {
// Don't insert macros from the prelude into blocks, as they can be shadowed by other macros.
- if prelude_module.krate != krate && is_crate_root {
+ if is_crate_root && prelude_module.krate(self.def_collector.db) != krate {
cov_mark::hit!(prelude_is_macro_use);
self.def_collector.import_macros_from_extern_crate(
- prelude_module.krate,
+ prelude_module.krate(self.def_collector.db),
None,
None,
);
@@ -1781,7 +1784,6 @@ impl ModCollector<'_, '_> {
return;
}
- let module = self.def_collector.def_map.module_id(module_id);
let def_map = &mut self.def_collector.def_map;
let local_def_map =
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
@@ -1789,9 +1791,11 @@ impl ModCollector<'_, '_> {
match item {
ModItemId::Mod(m) => self.collect_module(m, attrs),
ModItemId::Use(item_tree_id) => {
- let id =
- UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) }
- .intern(db);
+ let id = UseLoc {
+ container: module_id,
+ id: InFile::new(self.file_id(), item_tree_id),
+ }
+ .intern(db);
let is_prelude = attrs.by_key(sym::prelude_import).exists();
Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| {
self.def_collector.unresolved_imports.push(ImportDirective {
@@ -1806,7 +1810,7 @@ impl ModCollector<'_, '_> {
&self.item_tree[item_tree_id];
let id = ExternCrateLoc {
- container: module,
+ container: module_id,
id: InFile::new(self.tree_id.file_id(), item_tree_id),
}
.intern(db);
@@ -1815,12 +1819,12 @@ impl ModCollector<'_, '_> {
let is_self = *name == sym::self_;
let resolved = if is_self {
cov_mark::hit!(extern_crate_self_as);
- Some(def_map.crate_root())
+ Some(def_map.crate_root(db))
} else {
self.def_collector
.deps
.get(name)
- .map(|dep| CrateRootModuleId { krate: dep.crate_id })
+ .map(|dep| crate_def_map(db, dep.crate_id).root_module_id())
};
let name = match alias {
@@ -1845,7 +1849,7 @@ impl ModCollector<'_, '_> {
self.process_macro_use_extern_crate(
id,
attrs.by_key(sym::macro_use).attrs(),
- resolved.krate,
+ resolved.krate(self.def_collector.db),
);
}
}
@@ -1877,7 +1881,7 @@ impl ModCollector<'_, '_> {
}
ModItemId::ExternBlock(block) => {
let extern_block_id = ExternBlockLoc {
- container: module,
+ container: module_id,
id: InFile::new(self.file_id(), block),
}
.intern(db);
@@ -1890,11 +1894,11 @@ impl ModCollector<'_, '_> {
)
}
ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container),
- ModItemId::MacroRules(id) => self.collect_macro_rules(id, module),
- ModItemId::Macro2(id) => self.collect_macro_def(id, module),
+ ModItemId::MacroRules(id) => self.collect_macro_rules(id, module_id),
+ ModItemId::Macro2(id) => self.collect_macro_def(id, module_id),
ModItemId::Impl(imp) => {
let impl_id =
- ImplLoc { container: module, id: InFile::new(self.file_id(), imp) }
+ ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) }
.intern(db);
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
}
@@ -1908,7 +1912,7 @@ impl ModCollector<'_, '_> {
if self.def_collector.def_map.block.is_none()
&& self.def_collector.is_proc_macro
- && self.module_id == DefMap::ROOT
+ && self.module_id == self.def_collector.def_map.root
&& let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name)
{
self.def_collector.export_proc_macro(
@@ -1926,7 +1930,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- StructLoc { container: module, id: InFile::new(self.file_id(), id) }
+ StructLoc { container: module_id, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@@ -1940,7 +1944,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- UnionLoc { container: module, id: InFile::new(self.file_id(), id) }
+ UnionLoc { container: module_id, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@@ -1950,9 +1954,11 @@ impl ModCollector<'_, '_> {
}
ModItemId::Enum(id) => {
let it = &self.item_tree[id];
- let enum_ =
- EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) }
- .intern(db);
+ let enum_ = EnumLoc {
+ container: module_id,
+ id: InFile::new(self.tree_id.file_id(), id),
+ }
+ .intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
@@ -1997,7 +2003,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- TraitLoc { container: module, id: InFile::new(self.file_id(), id) }
+ TraitLoc { container: module_id, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@@ -2172,9 +2178,10 @@ impl ModCollector<'_, '_> {
declaration: FileAstId<ast::Module>,
definition: Option<(EditionedFileId, bool)>,
visibility: &crate::visibility::RawVisibility,
- ) -> LocalModuleId {
- let def_map = &mut self.def_collector.def_map;
- let vis = def_map
+ ) -> ModuleId {
+ let vis = self
+ .def_collector
+ .def_map
.resolve_visibility(
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map),
self.def_collector.db,
@@ -2195,21 +2202,25 @@ impl ModCollector<'_, '_> {
},
};
+ let module = unsafe {
+ crate::ModuleIdLt::new(
+ self.def_collector.db,
+ self.def_collector.def_map.krate,
+ self.def_collector.def_map.block_id(),
+ )
+ .to_static()
+ };
+ let def_map = &mut self.def_collector.def_map;
let modules = &mut def_map.modules;
- let res = modules.alloc(ModuleData::new(origin, vis));
- modules[res].parent = Some(self.module_id);
-
- if let Some((target, source)) = Self::borrow_modules(modules.as_mut(), res, self.module_id)
- {
- for (name, macs) in source.scope.legacy_macros() {
- for &mac in macs {
- target.scope.define_legacy_macro(name.clone(), mac);
- }
+ let mut data = ModuleData::new(origin, vis, Some(self.module_id));
+ for (name, macs) in modules[self.module_id].scope.legacy_macros() {
+ for &mac in macs {
+ data.scope.define_legacy_macro(name.clone(), mac);
}
}
- modules[self.module_id].children.insert(name.clone(), res);
+ modules[self.module_id].children.insert(name.clone(), module);
+ modules.insert(module, data);
- let module = def_map.module_id(res);
let def = ModuleDefId::from(module);
def_map.modules[self.module_id].scope.declare(def);
@@ -2219,7 +2230,7 @@ impl ModCollector<'_, '_> {
vis,
None,
);
- res
+ module
}
/// Resolves attributes on an item.
@@ -2516,12 +2527,10 @@ impl ModCollector<'_, '_> {
});
}
- fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
- let Some((source, target)) = Self::borrow_modules(
- self.def_collector.def_map.modules.as_mut(),
- module_id,
- self.module_id,
- ) else {
+ fn import_all_legacy_macros(&mut self, module_id: ModuleId) {
+ let [Some(source), Some(target)] =
+ self.def_collector.def_map.modules.get_disjoint_mut([&module_id, &self.module_id])
+ else {
return;
};
@@ -2532,29 +2541,6 @@ impl ModCollector<'_, '_> {
}
}
- /// Mutably borrow two modules at once, retu
- fn borrow_modules(
- modules: &mut [ModuleData],
- a: LocalModuleId,
- b: LocalModuleId,
- ) -> Option<(&mut ModuleData, &mut ModuleData)> {
- let a = a.into_raw().into_u32() as usize;
- let b = b.into_raw().into_u32() as usize;
-
- let (a, b) = match a.cmp(&b) {
- Ordering::Equal => return None,
- Ordering::Less => {
- let (prefix, b) = modules.split_at_mut(b);
- (&mut prefix[a], &mut b[0])
- }
- Ordering::Greater => {
- let (prefix, a) = modules.split_at_mut(a);
- (&mut a[0], &mut prefix[b])
- }
- };
- Some((a, b))
- }
-
fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) {
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id,
@@ -2574,48 +2560,15 @@ impl ModCollector<'_, '_> {
mod tests {
use test_fixture::WithFixture;
- use crate::{nameres::DefMapCrateData, test_db::TestDB};
+ use crate::test_db::TestDB;
use super::*;
- fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
- let mut collector = DefCollector {
- db,
- def_map,
- local_def_map: LocalDefMap::default(),
- crate_local_def_map: None,
- deps: FxIndexMap::default(),
- glob_imports: FxHashMap::default(),
- unresolved_imports: Vec::new(),
- indeterminate_imports: Vec::new(),
- unresolved_macros: Vec::new(),
- mod_dirs: FxHashMap::default(),
- cfg_options: &CfgOptions::default(),
- proc_macros: Default::default(),
- from_glob_import: Default::default(),
- skip_attrs: Default::default(),
- prev_active_attrs: Default::default(),
- is_proc_macro: false,
- unresolved_extern_crates: Default::default(),
- };
- collector.seed_with_top_level();
- collector.collect();
- collector.def_map
- }
-
- fn do_resolve(not_ra_fixture: &str) -> DefMap {
- let (db, file_id) = TestDB::with_single_file(not_ra_fixture);
+ fn do_resolve(not_ra_fixture: &str) {
+ let (db, _) = TestDB::with_single_file(not_ra_fixture);
let krate = db.test_crate();
- let edition = krate.data(&db).edition;
- let module_origin = ModuleOrigin::CrateRoot { definition: file_id };
- let def_map = DefMap::empty(
- krate,
- Arc::new(DefMapCrateData::new(edition)),
- ModuleData::new(module_origin, Visibility::Public),
- None,
- );
- do_collect_defs(&db, def_map)
+ crate_def_map(&db, krate);
}
#[test]
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index 6a07c56aee..be28e08509 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -7,7 +7,7 @@ use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod
use la_arena::Idx;
use syntax::ast;
-use crate::{AstId, nameres::LocalModuleId};
+use crate::{AstId, nameres::ModuleId};
#[derive(Debug, PartialEq, Eq)]
pub enum DefDiagnosticKind {
@@ -43,13 +43,13 @@ impl DefDiagnostics {
#[derive(Debug, PartialEq, Eq)]
pub struct DefDiagnostic {
- pub in_module: LocalModuleId,
+ pub in_module: ModuleId,
pub kind: DefDiagnosticKind,
}
impl DefDiagnostic {
pub(super) fn unresolved_module(
- container: LocalModuleId,
+ container: ModuleId,
declaration: AstId<ast::Module>,
candidates: Box<[String]>,
) -> Self {
@@ -60,7 +60,7 @@ impl DefDiagnostic {
}
pub(super) fn unresolved_extern_crate(
- container: LocalModuleId,
+ container: ModuleId,
declaration: AstId<ast::ExternCrate>,
) -> Self {
Self {
@@ -70,7 +70,7 @@ impl DefDiagnostic {
}
pub(super) fn unresolved_import(
- container: LocalModuleId,
+ container: ModuleId,
id: AstId<ast::Use>,
index: Idx<ast::UseTree>,
) -> Self {
@@ -78,7 +78,7 @@ impl DefDiagnostic {
}
pub fn macro_error(
- container: LocalModuleId,
+ container: ModuleId,
ast: AstId<ast::Item>,
path: ModPath,
err: ExpandErrorKind,
@@ -87,7 +87,7 @@ impl DefDiagnostic {
}
pub fn unconfigured_code(
- container: LocalModuleId,
+ container: ModuleId,
ast_id: ErasedAstId,
cfg: CfgExpr,
opts: CfgOptions,
@@ -100,33 +100,26 @@ impl DefDiagnostic {
// FIXME: Whats the difference between this and unresolved_proc_macro
pub(crate) fn unresolved_macro_call(
- container: LocalModuleId,
+ container: ModuleId,
ast: MacroCallKind,
path: ModPath,
) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
}
- pub(super) fn unimplemented_builtin_macro(
- container: LocalModuleId,
- ast: AstId<ast::Macro>,
- ) -> Self {
+ pub(super) fn unimplemented_builtin_macro(container: ModuleId, ast: AstId<ast::Macro>) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } }
}
pub(super) fn invalid_derive_target(
- container: LocalModuleId,
+ container: ModuleId,
ast: AstId<ast::Item>,
id: AttrId,
) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id } }
}
- pub(super) fn malformed_derive(
- container: LocalModuleId,
- ast: AstId<ast::Adt>,
- id: AttrId,
- ) -> Self {
+ pub(super) fn malformed_derive(container: ModuleId, ast: AstId<ast::Adt>, id: AttrId) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::MalformedDerive { ast, id } }
}
}
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 184a57410d..e4b1d2a987 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -19,7 +19,7 @@ use span::Edition;
use stdx::TupleExt;
use crate::{
- AdtId, LocalModuleId, ModuleDefId,
+ AdtId, ModuleDefId, ModuleId,
db::DefDatabase,
item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
item_tree::FieldsShape,
@@ -97,7 +97,7 @@ impl DefMap {
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
// module to import to
- original_module: LocalModuleId,
+ original_module: ModuleId,
// pub(path)
// ^^^^ this
visibility: &RawVisibility,
@@ -130,8 +130,8 @@ impl DefMap {
// DefMap they're written in, so we restrict them when that happens.
if let Visibility::Module(m, mv) = vis {
// ...unless we're resolving visibility for an associated item in an impl.
- if self.block_id() != m.block && !within_impl {
- vis = Visibility::Module(self.module_id(Self::ROOT), mv);
+ if self.block_id() != m.block(db) && !within_impl {
+ vis = Visibility::Module(self.root, mv);
tracing::debug!(
"visibility {:?} points outside DefMap, adjusting to {:?}",
m,
@@ -142,7 +142,7 @@ impl DefMap {
vis
}
RawVisibility::PubSelf(explicitness) => {
- Visibility::Module(self.module_id(original_module), *explicitness)
+ Visibility::Module(original_module, *explicitness)
}
RawVisibility::Public => Visibility::Public,
RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
@@ -158,7 +158,7 @@ impl DefMap {
db: &dyn DefDatabase,
mode: ResolveMode,
// module to import to
- mut original_module: LocalModuleId,
+ mut original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
// Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're
@@ -198,17 +198,17 @@ impl DefMap {
loop {
match current_map.block {
- Some(block) if original_module == Self::ROOT => {
+ Some(block) if original_module == current_map.root => {
// Block modules "inherit" names from its parent module.
- original_module = block.parent.local_id;
- current_map = block.parent.def_map(db, current_map.krate);
+ original_module = block.parent;
+ current_map = block.parent.def_map(db);
}
// Proper (non-block) modules, including those in block `DefMap`s, don't.
_ => {
- if original_module != Self::ROOT && current_map.block.is_some() {
+ if original_module != current_map.root && current_map.block.is_some() {
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
// the prelude items (which are not inserted into blocks because they can be overridden there).
- original_module = Self::ROOT;
+ original_module = current_map.root;
current_map = crate_def_map(db, self.krate);
let new = current_map.resolve_path_fp_in_all_preludes(
@@ -245,7 +245,7 @@ impl DefMap {
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
mode: ResolveMode,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
expected_macro_subns: Option<MacroSubNs>,
@@ -255,15 +255,15 @@ impl DefMap {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
cov_mark::hit!(macro_dollar_crate_self);
- PerNs::types(self.crate_root().into(), Visibility::Public, None)
+ PerNs::types(self.crate_root(db).into(), Visibility::Public, None)
} else {
let def_map = crate_def_map(db, krate);
- let module = def_map.module_id(Self::ROOT);
+ let module = def_map.root;
cov_mark::hit!(macro_dollar_crate_other);
PerNs::types(module.into(), Visibility::Public, None)
}
}
- PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public, None),
+ PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public, None),
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
@@ -310,14 +310,10 @@ impl DefMap {
}
PathKind::Super(lvl) => {
let mut local_id = original_module;
- let mut ext;
let mut def_map = self;
// Adjust `local_id` to `self`, i.e. the nearest non-block module.
- if def_map.module_id(local_id).is_block_module() {
- (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
- def_map = ext;
- }
+ (def_map, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
// Go up the module tree but skip block modules as `super` always refers to the
// nearest non-block module.
@@ -325,12 +321,8 @@ impl DefMap {
// Loop invariant: at the beginning of each loop, `local_id` must refer to a
// non-block module.
if let Some(parent) = def_map.modules[local_id].parent {
- local_id = parent;
- if def_map.module_id(local_id).is_block_module() {
- (ext, local_id) =
- adjust_to_nearest_non_block_module(db, def_map, local_id);
- def_map = ext;
- }
+ (def_map, local_id) =
+ adjust_to_nearest_non_block_module(db, def_map, parent);
} else {
stdx::always!(def_map.block.is_none());
tracing::debug!("super path in root module");
@@ -338,9 +330,6 @@ impl DefMap {
}
}
- let module = def_map.module_id(local_id);
- stdx::never!(module.is_block_module());
-
if self.block != def_map.block {
// If we have a different `DefMap` from `self` (the original `DefMap` we started
// with), resolve the remaining path segments in that `DefMap`.
@@ -358,7 +347,7 @@ impl DefMap {
);
}
- PerNs::types(module.into(), Visibility::Public, None)
+ PerNs::types(local_id.into(), Visibility::Public, None)
}
PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
Either::Left(it) => it,
@@ -385,7 +374,7 @@ impl DefMap {
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
mode: ResolveMode,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> ResolvePathResult {
@@ -467,7 +456,7 @@ impl DefMap {
mut curr_per_ns: PerNs,
path: &ModPath,
shadow: BuiltinShadowMode,
- original_module: LocalModuleId,
+ original_module: ModuleId,
) -> ResolvePathResult {
while let Some((i, segment)) = segments.next() {
let curr = match curr_per_ns.take_types_full() {
@@ -485,7 +474,7 @@ impl DefMap {
curr_per_ns = match curr.def {
ModuleDefId::ModuleId(module) => {
- if module.krate != self.krate {
+ if module.krate(db) != self.krate {
// FIXME: Inefficient
let path = ModPath::from_segments(
PathKind::SELF,
@@ -501,7 +490,7 @@ impl DefMap {
LocalDefMap::EMPTY,
db,
mode,
- module.local_id,
+ module,
&path,
shadow,
None,
@@ -518,11 +507,11 @@ impl DefMap {
}
let def_map;
- let module_data = if module.block == self.block_id() {
- &self[module.local_id]
+ let module_data = if module.block(db) == self.block_id() {
+ &self[module]
} else {
def_map = module.def_map(db);
- &def_map[module.local_id]
+ &def_map[module]
};
// Since it is a qualified path here, it should not contains legacy macros
@@ -649,7 +638,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- module: LocalModuleId,
+ module: ModuleId,
name: &Name,
shadow: BuiltinShadowMode,
expected_macro_subns: Option<MacroSubNs>,
@@ -684,7 +673,7 @@ impl DefMap {
};
let extern_prelude = || {
- if self.block.is_some() && module == DefMap::ROOT {
+ if self.block.is_some() && module == self.root {
// Don't resolve extern prelude in pseudo-modules of blocks, because
// they might been shadowed by local names.
return PerNs::none();
@@ -693,7 +682,7 @@ impl DefMap {
};
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || {
- if self.block.is_some() && module == DefMap::ROOT {
+ if self.block.is_some() && module == self.root {
return PerNs::none();
}
self.resolve_in_prelude(db, name)
@@ -746,18 +735,18 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- module: LocalModuleId,
+ module: ModuleId,
name: &Name,
) -> PerNs {
let from_crate_root = match self.block {
Some(_) => {
- let def_map = self.crate_root().def_map(db);
- def_map[Self::ROOT].scope.get(name)
+ let def_map = self.crate_root(db).def_map(db);
+ def_map[def_map.root].scope.get(name)
}
- None => self[Self::ROOT].scope.get(name),
+ None => self[self.root].scope.get(name),
};
let from_extern_prelude = || {
- if self.block.is_some() && module == DefMap::ROOT {
+ if self.block.is_some() && module == self.root {
// Don't resolve extern prelude in pseudo-module of a block.
return PerNs::none();
}
@@ -770,14 +759,14 @@ impl DefMap {
fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
if let Some((prelude, _use)) = self.prelude {
let keep;
- let def_map = if prelude.krate == self.krate {
+ let def_map = if prelude.krate(db) == self.krate {
self
} else {
// Extend lifetime
keep = prelude.def_map(db);
keep
};
- def_map[prelude.local_id].scope.get(name)
+ def_map[prelude].scope.get(name)
} else {
PerNs::none()
}
@@ -785,23 +774,23 @@ impl DefMap {
}
/// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to.
+#[inline]
fn adjust_to_nearest_non_block_module<'db>(
db: &'db dyn DefDatabase,
- def_map: &'db DefMap,
- mut local_id: LocalModuleId,
-) -> (&'db DefMap, LocalModuleId) {
- // INVARIANT: `local_id` in `def_map` must be a block module.
- stdx::always!(def_map.module_id(local_id).is_block_module());
-
- // This needs to be a local variable due to our mighty lifetime.
- let mut def_map = def_map;
- loop {
- let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
-
- def_map = parent.def_map(db, def_map.krate);
- local_id = parent.local_id;
- if !parent.is_block_module() {
+ mut def_map: &'db DefMap,
+ mut local_id: ModuleId,
+) -> (&'db DefMap, ModuleId) {
+ if def_map.root_module_id() != local_id {
+ // if we aren't the root, we are either not a block module, or a non-block module inside a
+ // block def map.
+ return (def_map, local_id);
+ }
+ while let Some(BlockInfo { parent, .. }) = def_map.block {
+ def_map = parent.def_map(db);
+ local_id = parent;
+ if def_map.root_module_id() != local_id {
return (def_map, local_id);
}
}
+ (def_map, local_id)
}
diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs
index 40283f67cc..5724334601 100644
--- a/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/crates/hir-def/src/nameres/tests/incremental.rs
@@ -63,7 +63,7 @@ pub const BAZ: u32 = 0;
let all_crates_before = db.all_crates();
{
- // Add a dependency a -> b.
+ // Add dependencies: c -> b, b -> a.
let mut new_crate_graph = CrateGraphBuilder::default();
let mut add_crate = |crate_name, root_file_idx: usize| {
@@ -111,10 +111,13 @@ pub const BAZ: u32 = 0;
crate_def_map(&db, krate);
}
},
- &[("crate_local_def_map", 1)],
+ // `c` gets invalidated as its dependency `b` changed
+ // `b` gets invalidated due to its new dependency edge to `a`
+ &[("crate_local_def_map", 2)],
expect![[r#"
[
"crate_local_def_map",
+ "crate_local_def_map",
]
"#]],
);
@@ -280,6 +283,8 @@ fn f() { foo }
"ast_id_map_shim",
"parse_shim",
"real_span_map_shim",
+ "crate_local_def_map",
+ "proc_macros_for_crate_shim",
"file_item_tree_query",
"ast_id_map_shim",
"parse_shim",
@@ -288,8 +293,6 @@ fn f() { foo }
"ast_id_map_shim",
"parse_shim",
"real_span_map_shim",
- "crate_local_def_map",
- "proc_macros_for_crate_shim",
"file_item_tree_query",
"ast_id_map_shim",
"parse_shim",
@@ -404,6 +407,12 @@ pub struct S {}
"ast_id_map_shim",
"parse_shim",
"real_span_map_shim",
+ "crate_local_def_map",
+ "proc_macros_for_crate_shim",
+ "file_item_tree_query",
+ "ast_id_map_shim",
+ "parse_shim",
+ "real_span_map_shim",
"decl_macro_expander_shim",
"file_item_tree_query",
"ast_id_map_shim",
@@ -424,12 +433,6 @@ pub struct S {}
"ast_id_map_shim",
"parse_macro_expansion_shim",
"macro_arg_shim",
- "crate_local_def_map",
- "proc_macros_for_crate_shim",
- "file_item_tree_query",
- "ast_id_map_shim",
- "parse_shim",
- "real_span_map_shim",
"macro_def_shim",
"file_item_tree_query",
"ast_id_map_shim",
@@ -509,7 +512,8 @@ m!(Z);
&db,
|| {
let crate_def_map = crate_def_map(&db, krate);
- let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
+ let module_data = &crate_def_map
+ [crate_def_map.modules_for_file(&db, pos.file_id.file_id(&db)).next().unwrap()];
assert_eq!(module_data.scope.resolutions().count(), 4);
},
&[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)],
@@ -558,7 +562,8 @@ m!(Z);
&db,
|| {
let crate_def_map = crate_def_map(&db, krate);
- let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
+ let module_data = &crate_def_map
+ [crate_def_map.modules_for_file(&db, pos.file_id.file_id(&db)).next().unwrap()];
assert_eq!(module_data.scope.resolutions().count(), 4);
},
&[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)],
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index a5fd0488e7..c8eb968b35 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -784,7 +784,7 @@ macro_rules! foo {
pub use core::clone::Clone;
"#,
- |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
+ |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
);
}
@@ -806,7 +806,7 @@ pub macro Copy {}
#[rustc_builtin_macro]
pub macro Clone {}
"#,
- |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2),
+ |map| assert_eq!(map.modules[map.root].scope.impls().len(), 2),
);
}
@@ -849,7 +849,7 @@ pub macro derive($item:item) {}
#[rustc_builtin_macro]
pub macro Clone {}
"#,
- |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
+ |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
);
}
@@ -1502,7 +1502,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
let krate = *db.all_crates().last().expect("no crate graph present");
let def_map = crate_def_map(&db, krate);
- let root_module = &def_map[DefMap::ROOT].scope;
+ let root_module = &def_map[def_map.root].scope;
assert!(
root_module.legacy_macros().count() == 0,
"`#[macro_use]` shouldn't bring macros into textual macro scope",
@@ -1609,7 +1609,7 @@ macro_rules! derive { () => {} }
#[derive(Clone)]
struct S;
"#,
- |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
+ |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
);
}
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index ccea043739..263f603a0b 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -16,11 +16,11 @@ use syntax::ast::HasName;
use triomphe::Arc;
use crate::{
- AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
- EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId,
- GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup,
- Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId,
- TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
+ AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
+ ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId,
+ ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId,
+ ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
+ TypeParamId, UseId, VariantId,
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::{
@@ -55,7 +55,7 @@ pub struct Resolver<'db> {
struct ModuleItemMap<'db> {
def_map: &'db DefMap,
local_def_map: &'db LocalDefMap,
- module_id: LocalModuleId,
+ module_id: ModuleId,
}
impl fmt::Debug for ModuleItemMap<'_> {
@@ -608,14 +608,14 @@ impl<'db> Resolver<'db> {
},
);
local_def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
- res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
+ res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
res.add_per_ns(name, def);
});
if let Some((prelude, _use)) = def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
- for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
+ for (name, def) in prelude_def_map[prelude].scope.entries() {
res.add_per_ns(name, def)
}
}
@@ -647,7 +647,7 @@ impl<'db> Resolver<'db> {
self.module_scope
.local_def_map
.extern_prelude()
- .map(|(name, module_id)| (name.clone(), module_id.0.into()))
+ .map(|(name, module_id)| (name.clone(), module_id.0))
}
pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
@@ -674,7 +674,7 @@ impl<'db> Resolver<'db> {
// Fill in the prelude traits
if let Some((prelude, _use)) = self.module_scope.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
- traits.extend(prelude_def_map[prelude.local_id].scope.traits());
+ traits.extend(prelude_def_map[prelude].scope.traits());
}
// Fill in module visible traits
traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
@@ -691,8 +691,7 @@ impl<'db> Resolver<'db> {
}
pub fn module(&self) -> ModuleId {
- let (def_map, _, local_id) = self.item_scope_();
- def_map.module_id(local_id)
+ self.item_scope_().2
}
pub fn item_scope(&self) -> &ItemScope {
@@ -886,7 +885,7 @@ impl<'db> Resolver<'db> {
resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
def_map,
local_def_map,
- module_id: DefMap::ROOT,
+ module_id: def_map.root,
}));
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
// already traverses all parents, so this is O(n²). I think we could only store the
@@ -985,7 +984,7 @@ impl<'db> Resolver<'db> {
}
/// The innermost block scope that contains items or the module scope that contains this resolver.
- fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
+ fn item_scope_(&self) -> (&DefMap, &LocalDefMap, ModuleId) {
self.scopes()
.find_map(|scope| match scope {
Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)),
@@ -1091,7 +1090,7 @@ fn resolver_for_scope_<'db>(
let local_def_map = block.lookup(db).module.only_local_def_map(db);
// Using `DefMap::ROOT` is okay here since inside modules other than the root,
// there can't directly be expressions.
- r = r.push_block_scope(def_map, local_def_map, DefMap::ROOT);
+ r = r.push_block_scope(def_map, local_def_map, def_map.root);
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
@@ -1124,7 +1123,7 @@ impl<'db> Resolver<'db> {
self,
def_map: &'db DefMap,
local_def_map: &'db LocalDefMap,
- module_id: LocalModuleId,
+ module_id: ModuleId,
) -> Resolver<'db> {
self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, module_id }))
}
@@ -1284,9 +1283,9 @@ pub trait HasResolver: Copy {
impl HasResolver for ModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
let (mut def_map, local_def_map) = self.local_def_map(db);
- let mut module_id = self.local_id;
+ let mut module_id = self;
- if !self.is_within_block() {
+ if self.block(db).is_none() {
return Resolver {
scopes: vec![],
module_scope: ModuleItemMap { def_map, local_def_map, module_id },
@@ -1296,9 +1295,9 @@ impl HasResolver for ModuleId {
let mut modules: SmallVec<[_; 1]> = smallvec![];
while let Some(parent) = def_map.parent() {
let block_def_map = mem::replace(&mut def_map, parent.def_map(db));
- let block_module_id = mem::replace(&mut module_id, parent.local_id);
+ let block_module_id = mem::replace(&mut module_id, parent);
modules.push((block_def_map, block_module_id));
- if !parent.is_within_block() {
+ if parent.block(db).is_none() {
break;
}
}
@@ -1313,16 +1312,6 @@ impl HasResolver for ModuleId {
}
}
-impl HasResolver for CrateRootModuleId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
- let (def_map, local_def_map) = self.local_def_map(db);
- Resolver {
- scopes: vec![],
- module_scope: ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT },
- }
- }
-}
-
impl HasResolver for TraitId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs
index e8ccf56059..a13ef484ba 100644
--- a/crates/hir-def/src/signatures.rs
+++ b/crates/hir-def/src/signatures.rs
@@ -860,7 +860,7 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
mut field_name: impl FnMut(usize, &Field) -> Name,
override_visibility: Option<Option<ast::Visibility>>,
) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
- let cfg_options = module.krate.cfg_options(db);
+ let cfg_options = module.krate(db).cfg_options(db);
let mut col = ExprCollector::new(db, module, fields.file_id);
let override_visibility = override_visibility.map(|vis| {
LazyCell::new(|| {
@@ -938,7 +938,7 @@ impl EnumVariants {
let ast_id_map = db.ast_id_map(source.file_id);
let mut diagnostics = ThinVec::new();
- let cfg_options = loc.container.krate.cfg_options(db);
+ let cfg_options = loc.container.krate(db).cfg_options(db);
let mut index = 0;
let Some(variants) = source.value.variant_list() else {
return (EnumVariants { variants: Box::default() }, None);
diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs
index 153fd195f0..6fe016f1e6 100644
--- a/crates/hir-def/src/src.rs
+++ b/crates/hir-def/src/src.rs
@@ -148,7 +148,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
let mut map = ArenaMap::new();
match &src.value {
ast::StructKind::Tuple(fl) => {
- let cfg_options = container.krate.cfg_options(db);
+ let cfg_options = container.krate(db).cfg_options(db);
let mut idx = 0;
for fd in fl.fields() {
let enabled = AttrFlags::is_cfg_enabled_for(&fd, cfg_options).is_ok();
@@ -163,7 +163,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
}
}
ast::StructKind::Record(fl) => {
- let cfg_options = container.krate.cfg_options(db);
+ let cfg_options = container.krate(db).cfg_options(db);
let mut idx = 0;
for fd in fl.fields() {
let enabled = AttrFlags::is_cfg_enabled_for(&fd, cfg_options).is_ok();
diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs
index 3bb9c361b3..cdb49b2970 100644
--- a/crates/hir-def/src/test_db.rs
+++ b/crates/hir-def/src/test_db.rs
@@ -13,7 +13,7 @@ use syntax::{AstNode, algo, ast};
use triomphe::Arc;
use crate::{
- LocalModuleId, Lookup, ModuleDefId, ModuleId,
+ Lookup, ModuleDefId, ModuleId,
db::DefDatabase,
nameres::{DefMap, ModuleSource, block_def_map, crate_def_map},
src::HasSource,
@@ -154,7 +154,7 @@ impl TestDB {
let crate_def_map = crate_def_map(self, krate);
for (local_id, data) in crate_def_map.modules() {
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
- return crate_def_map.module_id(local_id);
+ return local_id;
}
}
}
@@ -168,7 +168,7 @@ impl TestDB {
def_map = match self.block_at_position(def_map, position) {
Some(it) => it,
- None => return def_map.module_id(module),
+ None => return module,
};
loop {
let new_map = self.block_at_position(def_map, position);
@@ -178,16 +178,16 @@ impl TestDB {
}
_ => {
// FIXME: handle `mod` inside block expression
- return def_map.module_id(DefMap::ROOT);
+ return def_map.root;
}
}
}
}
/// Finds the smallest/innermost module in `def_map` containing `position`.
- fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
+ fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> ModuleId {
let mut size = None;
- let mut res = DefMap::ROOT;
+ let mut res = def_map.root;
for (module, data) in def_map.modules() {
let src = data.definition_source(self);
// We're not comparing the `base_db::EditionedFileId`, but rather the VFS `FileId`, because
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index 948f6ed8c3..a1645de6ec 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -9,8 +9,8 @@ use syntax::ast::{self, HasVisibility};
use triomphe::Arc;
use crate::{
- AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId,
- VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
+ AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId,
+ db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
};
pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
@@ -44,7 +44,7 @@ impl Visibility {
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
let to_module = match self {
Visibility::Module(m, _) => m,
- Visibility::PubCrate(krate) => return from_module.krate == krate,
+ Visibility::PubCrate(krate) => return from_module.krate(db) == krate,
Visibility::Public => return true,
};
if from_module == to_module {
@@ -52,30 +52,37 @@ impl Visibility {
return true;
}
// if they're not in the same crate, it can't be visible
- if from_module.krate != to_module.krate {
+ if from_module.krate(db) != to_module.krate(db) {
return false;
}
let def_map = from_module.def_map(db);
- Self::is_visible_from_def_map_(db, def_map, to_module, from_module.local_id)
+ Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
}
pub(crate) fn is_visible_from_def_map(
self,
db: &dyn DefDatabase,
def_map: &DefMap,
- from_module: LocalModuleId,
+ from_module: ModuleId,
) -> bool {
+ if cfg!(debug_assertions) {
+ _ = def_map.modules[from_module];
+ }
let to_module = match self {
Visibility::Module(m, _) => m,
- Visibility::PubCrate(krate) => return def_map.krate() == krate,
+ Visibility::PubCrate(krate) => return from_module.krate(db) == krate,
Visibility::Public => return true,
};
+ if from_module == to_module {
+ // if the modules are the same, visibility is trivially satisfied
+ return true;
+ }
// if they're not in the same crate, it can't be visible
- if def_map.krate() != to_module.krate {
+ if def_map.krate() != to_module.krate(db) {
return false;
}
- if from_module == to_module.local_id && def_map.block_id() == to_module.block {
+ if from_module == to_module && def_map.block_id() == to_module.block(db) {
// if the modules are the same, visibility is trivially satisfied
return true;
}
@@ -86,9 +93,9 @@ impl Visibility {
db: &dyn DefDatabase,
def_map: &DefMap,
mut to_module: ModuleId,
- mut from_module: LocalModuleId,
+ mut from_module: ModuleId,
) -> bool {
- debug_assert_eq!(to_module.krate, def_map.krate());
+ debug_assert_eq!(to_module.krate(db), def_map.krate());
// `to_module` might be the root module of a block expression. Those have the same
// visibility as the containing module (even though no items are directly nameable from
// there, getting this right is important for method resolution).
@@ -98,7 +105,7 @@ impl Visibility {
// currently computing, so we must not call the `def_map` query for it.
let def_map_block = def_map.block_id();
loop {
- match (to_module.block, def_map_block) {
+ match (to_module.block(db), def_map_block) {
// `to_module` is not a block, so there is no parent def map to use.
(None, _) => (),
// `to_module` is at `def_map`'s block, no need to move further.
@@ -117,7 +124,7 @@ impl Visibility {
let mut def_map = def_map;
let mut parent_arc;
loop {
- if def_map.module_id(from_module) == to_module {
+ if from_module == to_module {
return true;
}
match def_map[from_module].parent {
@@ -127,7 +134,7 @@ impl Visibility {
Some(module) => {
parent_arc = module.def_map(db);
def_map = parent_arc;
- from_module = module.local_id;
+ from_module = module;
}
// Reached the root module, nothing left to check.
None => return false,
@@ -141,7 +148,12 @@ impl Visibility {
///
/// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
/// visible in unrelated modules).
- pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
+ pub(crate) fn max(
+ self,
+ db: &dyn DefDatabase,
+ other: Visibility,
+ def_map: &DefMap,
+ ) -> Option<Visibility> {
match (self, other) {
(_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
(Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
@@ -153,11 +165,7 @@ impl Visibility {
}
(Visibility::Module(mod_, _), Visibility::PubCrate(krate))
| (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => {
- if mod_.krate == krate {
- Some(Visibility::PubCrate(krate))
- } else {
- None
- }
+ if mod_.krate(db) == krate { Some(Visibility::PubCrate(krate)) } else { None }
}
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
if mod_a == mod_b {
@@ -175,26 +183,24 @@ impl Visibility {
));
}
- if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
+ if mod_a.krate(db) != def_map.krate() || mod_b.krate(db) != def_map.krate() {
return None;
}
let def_block = def_map.block_id();
- if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
+ if mod_a.block(db) != def_block || mod_b.block(db) != def_block {
return None;
}
- let mut a_ancestors =
- iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+ let mut a_ancestors = iter::successors(Some(mod_a), |&m| def_map[m].parent);
- if a_ancestors.any(|m| m == mod_b.local_id) {
+ if a_ancestors.any(|m| m == mod_b) {
// B is above A
return Some(Visibility::Module(mod_b, expl_b));
}
- let mut b_ancestors =
- iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
- if b_ancestors.any(|m| m == mod_a.local_id) {
+ let mut b_ancestors = iter::successors(Some(mod_b), |&m| def_map[m].parent);
+ if b_ancestors.any(|m| m == mod_a) {
// A is above B
return Some(Visibility::Module(mod_a, expl_a));
}
@@ -208,7 +214,12 @@ impl Visibility {
///
/// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
/// visible in unrelated modules).
- pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
+ pub(crate) fn min(
+ self,
+ db: &dyn DefDatabase,
+ other: Visibility,
+ def_map: &DefMap,
+ ) -> Option<Visibility> {
match (self, other) {
(vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
(Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
@@ -220,10 +231,10 @@ impl Visibility {
}
(Visibility::Module(mod_, exp), Visibility::PubCrate(krate))
| (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => {
- if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None }
+ if mod_.krate(db) == krate { Some(Visibility::Module(mod_, exp)) } else { None }
}
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
- if mod_a == mod_b {
+ if mod_a.krate(db) != mod_b.krate(db) {
// Most module visibilities are `pub(self)`, and assuming no errors
// this will be the common and thus fast path.
return Some(Visibility::Module(
@@ -238,26 +249,24 @@ impl Visibility {
));
}
- if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
+ if mod_a.krate(db) != def_map.krate() || mod_b.krate(db) != def_map.krate() {
return None;
}
let def_block = def_map.block_id();
- if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
+ if mod_a.block(db) != def_block || mod_b.block(db) != def_block {
return None;
}
- let mut a_ancestors =
- iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+ let mut a_ancestors = iter::successors(Some(mod_a), |&m| def_map[m].parent);
- if a_ancestors.any(|m| m == mod_b.local_id) {
+ if a_ancestors.any(|m| m == mod_b) {
// B is above A
return Some(Visibility::Module(mod_a, expl_a));
}
- let mut b_ancestors =
- iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
- if b_ancestors.any(|m| m == mod_a.local_id) {
+ let mut b_ancestors = iter::successors(Some(mod_b), |&m| def_map[m].parent);
+ if b_ancestors.any(|m| m == mod_a) {
// A is above B
return Some(Visibility::Module(mod_b, expl_b));
}
diff --git a/crates/hir-expand/src/builtin/attr_macro.rs b/crates/hir-expand/src/builtin/attr_macro.rs
index 25dd933f26..06b9b5418e 100644
--- a/crates/hir-expand/src/builtin/attr_macro.rs
+++ b/crates/hir-expand/src/builtin/attr_macro.rs
@@ -7,7 +7,7 @@ use crate::{ExpandResult, MacroCallId, MacroCallKind, db::ExpandDatabase, name,
use super::quote;
macro_rules! register_builtin {
- ($(($name:ident, $variant:ident) => $expand:ident),* ) => {
+ ($(($name:ident, $variant:ident) => $expand:ident),* $(,)? ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinAttrExpander {
$($variant),*
@@ -65,7 +65,8 @@ register_builtin! {
(derive_const, DeriveConst) => derive_expand,
(global_allocator, GlobalAllocator) => dummy_attr_expand,
(test, Test) => dummy_gate_test_expand,
- (test_case, TestCase) => dummy_gate_test_expand
+ (test_case, TestCase) => dummy_gate_test_expand,
+ (define_opaque, DefineOpaque) => dummy_attr_expand,
}
pub fn find_builtin_attr(ident: &name::Name) -> Option<BuiltinAttrExpander> {
diff --git a/crates/hir-expand/src/cfg_process.rs b/crates/hir-expand/src/cfg_process.rs
index 227a62ff9f..a0de36548e 100644
--- a/crates/hir-expand/src/cfg_process.rs
+++ b/crates/hir-expand/src/cfg_process.rs
@@ -162,25 +162,19 @@ fn macro_input_callback(
}
}
Meta::TokenTree { path, tt } => {
- if path.segments.len() != 1
+ if path.is1("cfg") {
+ let cfg_expr = CfgExpr::parse_from_ast(
+ &mut TokenTreeChildren::new(&tt).peekable(),
+ );
+ if cfg_options().check(&cfg_expr) == Some(false) {
+ return ControlFlow::Break(ItemIsCfgedOut);
+ }
+ strip_current_attr = true;
+ } else if path.segments.len() != 1
|| !is_item_tree_filtered_attr(path.segments[0].text())
{
strip_current_attr = should_strip_attr();
}
-
- if path.segments.len() == 1 {
- let name = path.segments[0].text();
-
- if name == "cfg" {
- let cfg_expr = CfgExpr::parse_from_ast(
- &mut TokenTreeChildren::new(&tt).peekable(),
- );
- if cfg_options().check(&cfg_expr) == Some(false) {
- return ControlFlow::Break(ItemIsCfgedOut);
- }
- strip_current_attr = true;
- }
- }
}
Meta::Path { path } => {
if path.segments.len() != 1
diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs
index fe557d6802..fce92c8a3e 100644
--- a/crates/hir-expand/src/files.rs
+++ b/crates/hir-expand/src/files.rs
@@ -295,7 +295,7 @@ impl<SN: Borrow<SyntaxNode>> InFile<SN> {
/// Falls back to the macro call range if the node cannot be mapped up fully.
///
/// For attributes and derives, this will point back to the attribute only.
- /// For the entire item use [`InFile::original_file_range_full`].
+ /// For the entire item use `InFile::original_file_range_full`.
pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange {
self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db)
}
diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs
index 28800c6fab..bd6f7e4f2b 100644
--- a/crates/hir-expand/src/hygiene.rs
+++ b/crates/hir-expand/src/hygiene.rs
@@ -8,9 +8,9 @@
//!
//! # The Expansion Order Hierarchy
//!
-//! `ExpnData` in rustc, rust-analyzer's version is [`MacroCallLoc`]. Traversing the hierarchy
-//! upwards can be achieved by walking up [`MacroCallLoc::kind`]'s contained file id, as
-//! [`MacroFile`]s are interned [`MacroCallLoc`]s.
+//! `ExpnData` in rustc, rust-analyzer's version is `MacroCallLoc`. Traversing the hierarchy
+//! upwards can be achieved by walking up `MacroCallLoc::kind`'s contained file id, as
+//! `MacroFile`s are interned `MacroCallLoc`s.
//!
//! # The Macro Definition Hierarchy
//!
@@ -18,7 +18,7 @@
//!
//! # The Call-site Hierarchy
//!
-//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
+//! `ExpnData::call_site` in rustc, `MacroCallLoc::call_site` in rust-analyzer.
// FIXME: Move this into the span crate? Not quite possible today as that depends on `MacroCallLoc`
// which contains a bunch of unrelated things
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 157a5310bd..c92e41f507 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -4,6 +4,8 @@
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.
#![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)]
pub use intern;
@@ -860,7 +862,7 @@ impl ExpansionInfo {
}
/// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
- /// Unlike [`map_range_down_exact`], this will consider spans that contain the given span.
+ /// Unlike [`ExpansionInfo::map_range_down_exact`], this will consider spans that contain the given span.
///
/// Note this does a linear search through the entire backing vector of the spanmap.
pub fn map_range_down(
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 0a36c0e726..abab3bfb25 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -8,10 +8,9 @@ use std::fmt;
use hir_def::{TraitId, TypeAliasId};
use rustc_type_ir::inherent::{IntoKind, Ty as _};
use tracing::debug;
-use triomphe::Arc;
use crate::{
- TraitEnvironment,
+ ParamEnvAndCrate,
db::HirDatabase,
infer::InferenceContext,
next_solver::{
@@ -35,13 +34,13 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20;
/// detects a cycle in the deref chain.
pub fn autoderef<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
ty: Canonical<'db, Ty<'db>>,
) -> impl Iterator<Item = Ty<'db>> + use<'db> {
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let (ty, _) = infcx.instantiate_canonical(&ty);
- let autoderef = Autoderef::new(&infcx, &env, ty);
+ let autoderef = Autoderef::new(&infcx, env.param_env, ty);
let mut v = Vec::new();
for (ty, _steps) in autoderef {
// `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -111,12 +110,12 @@ struct AutoderefTraits {
// borrows it.
pub(crate) trait AutoderefCtx<'db> {
fn infcx(&self) -> &InferCtxt<'db>;
- fn env(&self) -> &TraitEnvironment<'db>;
+ fn param_env(&self) -> ParamEnv<'db>;
}
pub(crate) struct DefaultAutoderefCtx<'a, 'db> {
infcx: &'a InferCtxt<'db>,
- env: &'a TraitEnvironment<'db>,
+ param_env: ParamEnv<'db>,
}
impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> {
#[inline]
@@ -124,8 +123,8 @@ impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> {
self.infcx
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- self.env
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.param_env
}
}
@@ -136,8 +135,8 @@ impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, '_, 'db> {
&self.0.table.infer_ctxt
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- &self.0.table.trait_env
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.0.table.param_env
}
}
@@ -201,7 +200,7 @@ where
// autoderef expect this type to have been structurally normalized.
if let TyKind::Alias(..) = ty.kind() {
let (normalized_ty, obligations) =
- structurally_normalize_ty(self.infcx(), self.env().env, ty)?;
+ structurally_normalize_ty(self.infcx(), self.param_env(), ty)?;
self.state.obligations.extend(obligations);
(AutoderefKind::Builtin, normalized_ty)
} else {
@@ -231,10 +230,10 @@ impl<'a, 'db> Autoderef<'a, 'db> {
#[inline]
pub(crate) fn new_with_tracking(
infcx: &'a InferCtxt<'db>,
- env: &'a TraitEnvironment<'db>,
+ param_env: ParamEnv<'db>,
base_ty: Ty<'db>,
) -> Self {
- Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty)
+ Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty)
}
}
@@ -257,10 +256,10 @@ impl<'a, 'db> Autoderef<'a, 'db, usize> {
#[inline]
pub(crate) fn new(
infcx: &'a InferCtxt<'db>,
- env: &'a TraitEnvironment<'db>,
+ param_env: ParamEnv<'db>,
base_ty: Ty<'db>,
) -> Self {
- Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty)
+ Self::new_impl(DefaultAutoderefCtx { infcx, param_env }, base_ty)
}
}
@@ -292,8 +291,8 @@ where
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- self.ctx.env()
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.ctx.param_env()
}
#[inline]
@@ -339,7 +338,7 @@ where
let trait_ref = TraitRef::new(interner, trait_.into(), [ty]);
let obligation =
- Obligation::new(interner, ObligationCause::new(), self.env().env, trait_ref);
+ Obligation::new(interner, ObligationCause::new(), self.param_env(), trait_ref);
// We detect whether the self type implements `Deref` before trying to
// structurally normalize. We use `predicate_may_hold_opaque_types_jank`
// to support not-yet-defined opaque types. It will succeed for `impl Deref`
@@ -351,7 +350,7 @@ where
let (normalized_ty, obligations) = structurally_normalize_ty(
self.infcx(),
- self.env().env,
+ self.param_env(),
Ty::new_projection(interner, trait_target.into(), [ty]),
)?;
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 65250f94c2..012632aa55 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -5,7 +5,7 @@ mod tests;
use base_db::Crate;
use hir_def::{
- ConstId, EnumVariantId, GeneralConstId, StaticId,
+ ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId,
attrs::AttrFlags,
expr_store::Body,
hir::{Expr, ExprId},
@@ -16,14 +16,14 @@ use rustc_type_ir::inherent::IntoKind;
use triomphe::Arc;
use crate::{
- LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext,
+ LifetimeElisionKind, MemoryMap, ParamEnvAndCrate, TyLoweringContext,
db::HirDatabase,
display::DisplayTarget,
infer::InferenceContext,
mir::{MirEvalError, MirLowerError},
next_solver::{
- Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Ty,
- ValueConst,
+ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
+ ParamEnv, Ty, ValueConst,
},
};
@@ -85,7 +85,7 @@ pub fn intern_const_ref<'a>(
krate: Crate,
) -> Const<'a> {
let interner = DbInterner::new_no_crate(db);
- let layout = db.layout_of_ty(ty, TraitEnvironment::empty(krate));
+ let layout = db.layout_of_ty(ty, ParamEnvAndCrate { param_env: ParamEnv::empty(), krate });
let kind = match value {
LiteralConstRef::Int(i) => {
// FIXME: We should handle failure of layout better.
@@ -207,7 +207,7 @@ pub(crate) fn const_eval_discriminant_variant<'db>(
let mir_body = db.monomorphized_mir_body(
def,
GenericArgs::new_from_iter(interner, []),
- db.trait_environment_for_body(def),
+ ParamEnvAndCrate { param_env: db.trait_environment_for_body(def), krate: def.krate(db) },
)?;
let c = interpret_mir(db, mir_body, false, None)?.0?;
let c = if is_signed {
@@ -259,7 +259,7 @@ pub(crate) fn const_eval_cycle_result<'db>(
_: &'db dyn HirDatabase,
_: ConstId,
_: GenericArgs<'db>,
- _: Option<Arc<TraitEnvironment<'db>>>,
+ _: Option<ParamEnvAndCrate<'db>>,
) -> Result<Const<'db>, ConstEvalError<'db>> {
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
}
@@ -282,9 +282,13 @@ pub(crate) fn const_eval_query<'db>(
db: &'db dyn HirDatabase,
def: ConstId,
subst: GenericArgs<'db>,
- trait_env: Option<Arc<TraitEnvironment<'db>>>,
+ trait_env: Option<ParamEnvAndCrate<'db>>,
) -> Result<Const<'db>, ConstEvalError<'db>> {
- let body = db.monomorphized_mir_body(def.into(), subst, db.trait_environment(def.into()))?;
+ let body = db.monomorphized_mir_body(
+ def.into(),
+ subst,
+ ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) },
+ )?;
let c = interpret_mir(db, body, false, trait_env)?.0?;
Ok(c)
}
@@ -297,7 +301,10 @@ pub(crate) fn const_eval_static_query<'db>(
let body = db.monomorphized_mir_body(
def.into(),
GenericArgs::new_from_iter(interner, []),
- db.trait_environment_for_body(def.into()),
+ ParamEnvAndCrate {
+ param_env: db.trait_environment_for_body(def.into()),
+ krate: def.krate(db),
+ },
)?;
let c = interpret_mir(db, body, false, None)?.0?;
Ok(c)
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index f25147622f..2dc937d760 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -126,7 +126,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const<'_>, ConstEv
let interner = DbInterner::new_no_crate(db);
let module_id = db.module_for_file(file_id.file_id(db));
let def_map = module_id.def_map(db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
let const_id = scope
.declarations()
.find_map(|x| match x {
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index df058711a6..f9523e7168 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -12,13 +12,16 @@ use salsa::plumbing::AsId;
use triomphe::Arc;
use crate::{
- ImplTraitId, TraitEnvironment, TyDefId, ValueTyDefId,
+ ImplTraitId, TyDefId, ValueTyDefId,
consteval::ConstEvalError,
dyn_compatibility::DynCompatibilityViolation,
layout::{Layout, LayoutError},
lower::{Diagnostics, GenericDefaults},
mir::{BorrowckResult, MirBody, MirLowerError},
- next_solver::{Const, EarlyBinder, GenericArgs, PolyFnSig, TraitRef, Ty, VariancesOf},
+ next_solver::{
+ Const, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, TraitRef, Ty, VariancesOf,
+ },
+ traits::ParamEnvAndCrate,
};
#[query_group::query_group]
@@ -46,7 +49,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
&'db self,
def: DefWithBodyId,
subst: GenericArgs<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
#[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
@@ -54,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
&'db self,
def: InternedClosureId,
subst: GenericArgs<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
#[salsa::invoke(crate::mir::borrowck_query)]
@@ -70,7 +73,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
&'db self,
def: ConstId,
subst: GenericArgs<'db>,
- trait_env: Option<Arc<TraitEnvironment<'db>>>,
+ trait_env: Option<ParamEnvAndCrate<'db>>,
) -> Result<Const<'db>, ConstEvalError<'db>>;
#[salsa::invoke(crate::consteval::const_eval_static_query)]
@@ -88,7 +91,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
#[salsa::transparent]
fn lookup_impl_method<'db>(
&'db self,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
func: FunctionId,
fn_subst: GenericArgs<'db>,
) -> (FunctionId, GenericArgs<'db>);
@@ -101,7 +104,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
&'db self,
def: AdtId,
args: GenericArgs<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
@@ -109,7 +112,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
fn layout_of_ty<'db>(
&'db self,
ty: Ty<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
@@ -186,11 +189,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
#[salsa::invoke(crate::lower::trait_environment_for_body_query)]
#[salsa::transparent]
- fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId)
- -> Arc<TraitEnvironment<'db>>;
+ fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> ParamEnv<'db>;
#[salsa::invoke(crate::lower::trait_environment_query)]
- fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>;
+ fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>;
#[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
#[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)]
diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs
index 79dc6e3672..a6852b87f6 100644
--- a/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -164,7 +164,7 @@ impl<'a> DeclValidator<'a> {
else {
return;
};
- let module_data = &module_id.def_map(self.db)[module_id.local_id];
+ let module_data = &module_id.def_map(self.db)[module_id];
let Some(module_src) = module_data.declaration_source(self.db) else {
return;
};
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index ffbcea4d25..0de7fab8d1 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -25,7 +25,7 @@ use triomphe::Arc;
use typed_arena::Arena;
use crate::{
- Adjust, InferenceResult, TraitEnvironment,
+ Adjust, InferenceResult,
db::HirDatabase,
diagnostics::match_check::{
self,
@@ -33,7 +33,7 @@ use crate::{
},
display::{DisplayTarget, HirDisplay},
next_solver::{
- DbInterner, Ty, TyKind, TypingMode,
+ DbInterner, ParamEnv, Ty, TyKind, TypingMode,
infer::{DbInternerInferExt, InferCtxt},
},
};
@@ -79,7 +79,7 @@ impl BodyValidationDiagnostic {
let infer = InferenceResult::for_body(db, owner);
let body = db.body(owner);
let env = db.trait_environment_for_body(owner);
- let interner = DbInterner::new_with(db, env.krate);
+ let interner = DbInterner::new_with(db, owner.krate(db));
let infcx =
interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into()));
let mut validator = ExprValidator {
@@ -100,7 +100,7 @@ struct ExprValidator<'db> {
owner: DefWithBodyId,
body: Arc<Body>,
infer: &'db InferenceResult<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
diagnostics: Vec<BodyValidationDiagnostic>,
validate_lints: bool,
infcx: InferCtxt<'db>,
@@ -210,7 +210,7 @@ impl<'db> ExprValidator<'db> {
return;
}
- let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env);
let pattern_arena = Arena::new();
let mut m_arms = Vec::with_capacity(arms.len());
@@ -332,7 +332,7 @@ impl<'db> ExprValidator<'db> {
return;
};
let pattern_arena = Arena::new();
- let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env);
for stmt in &**statements {
let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
continue;
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index c70c6b6119..91448d5806 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -14,14 +14,12 @@ use rustc_pattern_analysis::{
use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike};
use smallvec::{SmallVec, smallvec};
use stdx::never;
-use triomphe::Arc;
use crate::{
- TraitEnvironment,
db::HirDatabase,
inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
next_solver::{
- Ty, TyKind,
+ ParamEnv, Ty, TyKind,
infer::{InferCtxt, traits::ObligationCause},
},
};
@@ -76,16 +74,12 @@ pub(crate) struct MatchCheckCtx<'a, 'db> {
module: ModuleId,
pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
infcx: &'a InferCtxt<'db>,
}
impl<'a, 'db> MatchCheckCtx<'a, 'db> {
- pub(crate) fn new(
- module: ModuleId,
- infcx: &'a InferCtxt<'db>,
- env: Arc<TraitEnvironment<'db>>,
- ) -> Self {
+ pub(crate) fn new(module: ModuleId, infcx: &'a InferCtxt<'db>, env: ParamEnv<'db>) -> Self {
let db = infcx.interner.db;
let def_map = module.crate_def_map(db);
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
@@ -114,12 +108,12 @@ impl<'a, 'db> MatchCheckCtx<'a, 'db> {
}
fn is_uninhabited(&self, ty: Ty<'db>) -> bool {
- is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone())
+ is_ty_uninhabited_from(self.infcx, ty, self.module, self.env)
}
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
fn is_foreign_non_exhaustive(&self, adt: hir_def::AdtId) -> bool {
- let is_local = adt.krate(self.db) == self.module.krate();
+ let is_local = adt.krate(self.db) == self.module.krate(self.db);
!is_local && AttrFlags::query(self.db, adt.into()).contains(AttrFlags::NON_EXHAUSTIVE)
}
@@ -159,7 +153,7 @@ impl<'a, 'db> MatchCheckCtx<'a, 'db> {
let ty = field_tys[fid].instantiate(self.infcx.interner, substs);
let ty = self
.infcx
- .at(&ObligationCause::dummy(), self.env.env)
+ .at(&ObligationCause::dummy(), self.env)
.deeply_normalize(ty)
.unwrap_or(ty);
(fid, ty)
@@ -446,11 +440,7 @@ impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> {
let mut variants = IndexVec::with_capacity(enum_data.variants.len());
for &(variant, _, _) in enum_data.variants.iter() {
let is_uninhabited = is_enum_variant_uninhabited_from(
- cx.infcx,
- variant,
- subst,
- cx.module,
- self.env.clone(),
+ cx.infcx, variant, subst, cx.module, self.env,
);
let visibility = if is_uninhabited {
VariantVisibility::Empty
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 6160962e3b..bbc381ba5d 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -165,7 +165,7 @@ impl<'db> UnsafeVisitor<'db> {
DefWithBodyId::FunctionId(func) => TargetFeatures::from_fn(db, func),
_ => TargetFeatures::default(),
};
- let krate = resolver.module().krate();
+ let krate = resolver.krate();
let edition = krate.data(db).edition;
let target_feature_is_safe = match &krate.workspace_data(db).target {
Ok(target) => target_feature_is_safe_in_target(target),
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index c76b8dc5f0..e1d62a9c7a 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -18,7 +18,6 @@ use hir_def::{
item_scope::ItemInNs,
item_tree::FieldsShape,
lang_item::LangItems,
- nameres::DefMap,
signatures::VariantFields,
type_ref::{
ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId,
@@ -44,10 +43,9 @@ use rustc_type_ir::{
use smallvec::SmallVec;
use span::Edition;
use stdx::never;
-use triomphe::Arc;
use crate::{
- CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, TraitEnvironment, consteval,
+ CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval,
db::{HirDatabase, InternedClosure, InternedCoroutine},
generics::generics,
layout::Layout,
@@ -55,8 +53,8 @@ use crate::{
mir::pad16,
next_solver::{
AliasTy, Clause, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder,
- ExistentialPredicate, FnSig, GenericArg, GenericArgs, PolyFnSig, Region, SolverDefId, Term,
- TraitRef, Ty, TyKind, TypingMode,
+ ExistentialPredicate, FnSig, GenericArg, GenericArgs, ParamEnv, PolyFnSig, Region,
+ SolverDefId, Term, TraitRef, Ty, TyKind, TypingMode,
abi::Safety,
infer::{DbInternerInferExt, traits::ObligationCause},
},
@@ -64,6 +62,8 @@ use crate::{
utils::{detect_variant_from_bytes, fn_traits},
};
+pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>;
+
pub trait HirWrite: fmt::Write {
fn start_location_link(&mut self, _location: ModuleDefId) {}
fn end_location_link(&mut self) {}
@@ -191,7 +191,7 @@ impl<'db> HirFormatter<'_, 'db> {
}
pub trait HirDisplay<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result;
/// Returns a `Display`able type that is human-readable.
fn into_displayable<'a>(
@@ -309,7 +309,7 @@ pub trait HirDisplay<'db> {
allow_opaque: bool,
) -> Result<String, DisplaySourceCodeError> {
let mut result = String::new();
- let interner = DbInterner::new_with(db, module_id.krate());
+ let interner = DbInterner::new_with(db, module_id.krate(db));
match self.hir_fmt(&mut HirFormatter {
db,
interner,
@@ -320,7 +320,7 @@ pub trait HirDisplay<'db> {
entity_limit: None,
omit_verbose_types: false,
closure_style: ClosureStyle::ImplFn,
- display_target: DisplayTarget::from_crate(db, module_id.krate()),
+ display_target: DisplayTarget::from_crate(db, module_id.krate(db)),
display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque },
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
@@ -400,7 +400,7 @@ impl<'db> HirFormatter<'_, 'db> {
&mut self,
iter: impl IntoIterator<Item = T>,
sep: &str,
- ) -> Result<(), HirDisplayError> {
+ ) -> Result {
let mut first = true;
for e in iter {
if !first {
@@ -419,7 +419,7 @@ impl<'db> HirFormatter<'_, 'db> {
}
/// This allows using the `write!` macro directly with a `HirFormatter`.
- pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> {
+ pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result {
// We write to a buffer first to track output size
self.buf.clear();
fmt::write(&mut self.buf, args)?;
@@ -429,12 +429,12 @@ impl<'db> HirFormatter<'_, 'db> {
self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
}
- pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> {
+ pub fn write_str(&mut self, s: &str) -> Result {
self.fmt.write_str(s)?;
Ok(())
}
- pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> {
+ pub fn write_char(&mut self, c: char) -> Result {
self.fmt.write_char(c)?;
Ok(())
}
@@ -542,7 +542,7 @@ pub enum ClosureStyle {
}
impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
- pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
+ pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result {
let krate = self.display_target.krate;
let interner = DbInterner::new_with(self.db, krate);
self.t.hir_fmt(&mut HirFormatter {
@@ -595,21 +595,18 @@ where
const TYPE_HINT_TRUNCATION: &str = "…";
impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
HirDisplay::hir_fmt(*self, f)
}
}
impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
HirDisplay::hir_fmt(self.as_ref(), f)
}
}
-fn write_projection<'db>(
- f: &mut HirFormatter<'_, 'db>,
- alias: &AliasTy<'db>,
-) -> Result<(), HirDisplayError> {
+fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) -> Result {
if f.should_truncate() {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}
@@ -666,7 +663,7 @@ fn write_projection<'db>(
}
impl<'db> HirDisplay<'db> for GenericArg<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self {
GenericArg::Ty(ty) => ty.hir_fmt(f),
GenericArg::Lifetime(lt) => lt.hir_fmt(f),
@@ -676,7 +673,7 @@ impl<'db> HirDisplay<'db> for GenericArg<'db> {
}
impl<'db> HirDisplay<'db> for Const<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.kind() {
ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => {
@@ -715,11 +712,11 @@ fn render_const_scalar<'db>(
b: &[u8],
memory_map: &MemoryMap<'db>,
ty: Ty<'db>,
-) -> Result<(), HirDisplayError> {
- let trait_env = TraitEnvironment::empty(f.krate());
+) -> Result {
+ let param_env = ParamEnv::empty();
let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
- let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty);
- render_const_scalar_inner(f, b, memory_map, ty, trait_env)
+ let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty);
+ render_const_scalar_inner(f, b, memory_map, ty, param_env)
}
fn render_const_scalar_inner<'db>(
@@ -727,9 +724,10 @@ fn render_const_scalar_inner<'db>(
b: &[u8],
memory_map: &MemoryMap<'db>,
ty: Ty<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
-) -> Result<(), HirDisplayError> {
+ param_env: ParamEnv<'db>,
+) -> Result {
use TyKind;
+ let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
match ty.kind() {
TyKind::Bool => write!(f, "{}", b[0] != 0),
TyKind::Char => {
@@ -792,7 +790,7 @@ fn render_const_scalar_inner<'db>(
TyKind::Slice(ty) => {
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
- let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else {
+ let Ok(layout) = f.db.layout_of_ty(ty, param_env) else {
return f.write_str("<layout-error>");
};
let size_one = layout.size.bytes_usize();
@@ -826,7 +824,7 @@ fn render_const_scalar_inner<'db>(
let Ok(t) = memory_map.vtable_ty(ty_id) else {
return f.write_str("<ty-missing-in-vtable-map>");
};
- let Ok(layout) = f.db.layout_of_ty(t, trait_env) else {
+ let Ok(layout) = f.db.layout_of_ty(t, param_env) else {
return f.write_str("<layout-error>");
};
let size = layout.size.bytes_usize();
@@ -856,7 +854,7 @@ fn render_const_scalar_inner<'db>(
return f.write_str("<layout-error>");
}
});
- let Ok(layout) = f.db.layout_of_ty(t, trait_env) else {
+ let Ok(layout) = f.db.layout_of_ty(t, param_env) else {
return f.write_str("<layout-error>");
};
let size = layout.size.bytes_usize();
@@ -868,7 +866,7 @@ fn render_const_scalar_inner<'db>(
}
},
TyKind::Tuple(tys) => {
- let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else {
+ let Ok(layout) = f.db.layout_of_ty(ty, param_env) else {
return f.write_str("<layout-error>");
};
f.write_str("(")?;
@@ -880,7 +878,7 @@ fn render_const_scalar_inner<'db>(
f.write_str(", ")?;
}
let offset = layout.fields.offset(id).bytes_usize();
- let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else {
+ let Ok(layout) = f.db.layout_of_ty(ty, param_env) else {
f.write_str("<layout-error>")?;
continue;
};
@@ -891,7 +889,7 @@ fn render_const_scalar_inner<'db>(
}
TyKind::Adt(def, args) => {
let def = def.def_id().0;
- let Ok(layout) = f.db.layout_of_adt(def, args, trait_env.clone()) else {
+ let Ok(layout) = f.db.layout_of_adt(def, args, param_env) else {
return f.write_str("<layout-error>");
};
match def {
@@ -914,7 +912,7 @@ fn render_const_scalar_inner<'db>(
write!(f, "{}", f.db.union_signature(u).name.display(f.db, f.edition()))
}
hir_def::AdtId::EnumId(e) => {
- let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else {
+ let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else {
return f.write_str("<target-layout-not-available>");
};
let Some((var_id, var_layout)) =
@@ -954,7 +952,7 @@ fn render_const_scalar_inner<'db>(
let Some(len) = consteval::try_const_usize(f.db, len) else {
return f.write_str("<unknown-array-len>");
};
- let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else {
+ let Ok(layout) = f.db.layout_of_ty(ty, param_env) else {
return f.write_str("<layout-error>");
};
let size_one = layout.size.bytes_usize();
@@ -995,18 +993,19 @@ fn render_variant_after_name<'db>(
data: &VariantFields,
f: &mut HirFormatter<'_, 'db>,
field_types: &ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ param_env: ParamEnv<'db>,
layout: &Layout,
args: GenericArgs<'db>,
b: &[u8],
memory_map: &MemoryMap<'db>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
+ let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
match data.shape {
FieldsShape::Record | FieldsShape::Tuple => {
let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| {
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
let ty = field_types[id].instantiate(f.interner, args);
- let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else {
+ let Ok(layout) = f.db.layout_of_ty(ty, param_env) else {
return f.write_str("<layout-error>");
};
let size = layout.size.bytes_usize();
@@ -1043,10 +1042,7 @@ fn render_variant_after_name<'db>(
}
impl<'db> HirDisplay<'db> for Ty<'db> {
- fn hir_fmt(
- &self,
- f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) -> Result {
let interner = f.interner;
if f.should_truncate() {
return write!(f, "{TYPE_HINT_TRUNCATION}");
@@ -1519,7 +1515,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
_ => false,
})
.collect::<Vec<_>>();
- let krate = param.id.parent().module(db).krate();
+ let krate = param.id.parent().module(db).krate(db);
write_bounds_like_dyn_trait_with_prefix(
f,
"impl",
@@ -1649,7 +1645,7 @@ fn hir_fmt_generics<'db>(
parameters: &[GenericArg<'db>],
generic_def: Option<hir_def::GenericDefId>,
self_: Option<Ty<'db>>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
if parameters.is_empty() {
return Ok(());
}
@@ -1699,7 +1695,7 @@ fn hir_fmt_generic_args<'db>(
parameters: &[GenericArg<'db>],
generic_def: Option<hir_def::GenericDefId>,
self_: Option<Ty<'db>>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
if parameters.is_empty() {
return Ok(());
}
@@ -1719,7 +1715,7 @@ fn hir_fmt_generic_arguments<'db>(
f: &mut HirFormatter<'_, 'db>,
parameters: &[GenericArg<'db>],
self_: Option<Ty<'db>>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
let mut first = true;
let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some());
@@ -1743,7 +1739,7 @@ fn hir_fmt_tys<'db>(
f: &mut HirFormatter<'_, 'db>,
tys: &[Ty<'db>],
self_: Option<Ty<'db>>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
let mut first = true;
for ty in tys {
@@ -1759,7 +1755,7 @@ fn hir_fmt_tys<'db>(
}
impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder();
if let Safety::Unsafe = safety {
write!(f, "unsafe ")?;
@@ -1790,7 +1786,7 @@ impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
}
impl<'db> HirDisplay<'db> for Term<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self {
Term::Ty(it) => it.hir_fmt(f),
Term::Const(it) => it.hir_fmt(f),
@@ -1822,7 +1818,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
this: Either<Ty<'db>, Region<'db>>,
predicates: &[Clause<'db>],
default_sized: SizedByDefault,
-) -> Result<(), HirDisplayError> {
+) -> Result {
write!(f, "{prefix}")?;
if !predicates.is_empty()
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
@@ -1839,7 +1835,7 @@ fn write_bounds_like_dyn_trait<'db>(
this: Either<Ty<'db>, Region<'db>>,
predicates: &[Clause<'db>],
default_sized: SizedByDefault,
-) -> Result<(), HirDisplayError> {
+) -> Result {
// Note: This code is written to produce nice results (i.e.
// corresponding to surface Rust) for types that can occur in
// actual Rust. It will have weird results if the predicates
@@ -1983,7 +1979,7 @@ fn write_bounds_like_dyn_trait<'db>(
}
impl<'db> HirDisplay<'db> for TraitRef<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let trait_ = self.def_id.0;
f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
@@ -1994,7 +1990,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> {
}
impl<'db> HirDisplay<'db> for Region<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.kind() {
RegionKind::ReEarlyParam(param) => {
let generics = generics(f.db, param.id.parent);
@@ -2028,19 +2024,20 @@ pub fn write_visibility<'db>(
module_id: ModuleId,
vis: Visibility,
f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
match vis {
Visibility::Public => write!(f, "pub "),
Visibility::PubCrate(_) => write!(f, "pub(crate) "),
Visibility::Module(vis_id, _) => {
let def_map = module_id.def_map(f.db);
- let root_module_id = def_map.module_id(DefMap::ROOT);
+ let root_module_id = def_map.root_module_id();
if vis_id == module_id {
// pub(self) or omitted
Ok(())
- } else if root_module_id == vis_id && !root_module_id.is_within_block() {
+ } else if root_module_id == vis_id && root_module_id.block(f.db).is_none() {
write!(f, "pub(crate) ")
- } else if module_id.containing_module(f.db) == Some(vis_id) && !vis_id.is_block_module()
+ } else if module_id.containing_module(f.db) == Some(vis_id)
+ && !vis_id.is_block_module(f.db)
{
write!(f, "pub(super) ")
} else {
@@ -2051,21 +2048,13 @@ pub fn write_visibility<'db>(
}
pub trait HirDisplayWithExpressionStore<'db> {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError>;
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result;
}
impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db>
for &'_ T
{
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
T::hir_fmt(&**self, f, store)
}
}
@@ -2086,16 +2075,12 @@ impl<'a, T> ExpressionStoreAdapter<'a, T> {
}
impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
T::hir_fmt(&self.0, f, self.1)
}
}
impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
match &store[*self] {
LifetimeRef::Named(name) => write!(f, "{}", name.display(f.db, f.edition())),
LifetimeRef::Static => write!(f, "'static"),
@@ -2114,11 +2099,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
}
impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
match &store[*self] {
TypeRef::Never => write!(f, "!")?,
TypeRef::TypeParam(param) => {
@@ -2243,11 +2224,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
}
impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- _store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, _store: &ExpressionStore) -> Result {
// FIXME
write!(f, "{{const}}")?;
@@ -2256,11 +2233,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
}
impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
match self {
&TypeBound::Path(path, modifier) => {
match modifier {
@@ -2300,11 +2273,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
}
impl<'db> HirDisplayWithExpressionStore<'db> for Path {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
match (self.type_anchor(), self.kind()) {
(Some(anchor), _) => {
write!(f, "<")?;
@@ -2452,11 +2421,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path {
}
impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg {
- fn hir_fmt(
- &self,
- f: &mut HirFormatter<'_, 'db>,
- store: &ExpressionStore,
- ) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result {
match self {
hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, store),
hir_def::expr_store::path::GenericArg::Const(_c) => {
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index d76de4b8ca..3ae6451d69 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -4,13 +4,12 @@ use hir_def::{AdtId, signatures::StructFlags};
use rustc_hash::FxHashSet;
use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike};
use stdx::never;
-use triomphe::Arc;
use crate::{
- InferenceResult, TraitEnvironment, consteval,
+ InferenceResult, consteval,
method_resolution::TraitImpls,
next_solver::{
- DbInterner, SimplifiedType, Ty, TyKind,
+ DbInterner, ParamEnv, SimplifiedType, Ty, TyKind,
infer::{InferCtxt, traits::ObligationCause},
obligation_ctxt::ObligationCtxt,
},
@@ -26,12 +25,12 @@ fn has_destructor(interner: DbInterner<'_>, adt: AdtId) -> bool {
let Some(drop_trait) = interner.lang_items().Drop else {
return false;
};
- let impls = match module.containing_block() {
+ let impls = match module.block(db) {
Some(block) => match TraitImpls::for_block(db, block) {
Some(it) => &**it,
None => return false,
},
- None => TraitImpls::for_crate(db, module.krate()),
+ None => TraitImpls::for_crate(db, module.krate(db)),
};
!impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty()
}
@@ -47,22 +46,18 @@ pub enum DropGlue {
HasDropGlue,
}
-pub fn has_drop_glue<'db>(
- infcx: &InferCtxt<'db>,
- ty: Ty<'db>,
- env: Arc<TraitEnvironment<'db>>,
-) -> DropGlue {
+pub fn has_drop_glue<'db>(infcx: &InferCtxt<'db>, ty: Ty<'db>, env: ParamEnv<'db>) -> DropGlue {
has_drop_glue_impl(infcx, ty, env, &mut FxHashSet::default())
}
fn has_drop_glue_impl<'db>(
infcx: &InferCtxt<'db>,
ty: Ty<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
visited: &mut FxHashSet<Ty<'db>>,
) -> DropGlue {
let mut ocx = ObligationCtxt::new(infcx);
- let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty);
+ let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, ty).unwrap_or(ty);
if !visited.insert(ty) {
// Recursive type.
@@ -91,7 +86,7 @@ fn has_drop_glue_impl<'db>(
has_drop_glue_impl(
infcx,
field_ty.instantiate(infcx.interner, subst),
- env.clone(),
+ env,
visited,
)
})
@@ -111,7 +106,7 @@ fn has_drop_glue_impl<'db>(
has_drop_glue_impl(
infcx,
field_ty.instantiate(infcx.interner, subst),
- env.clone(),
+ env,
visited,
)
})
@@ -124,7 +119,7 @@ fn has_drop_glue_impl<'db>(
}
TyKind::Tuple(tys) => tys
.iter()
- .map(|ty| has_drop_glue_impl(infcx, ty, env.clone(), visited))
+ .map(|ty| has_drop_glue_impl(infcx, ty, env, visited))
.max()
.unwrap_or(DropGlue::None),
TyKind::Array(ty, len) => {
@@ -142,9 +137,7 @@ fn has_drop_glue_impl<'db>(
let env = db.trait_environment_for_body(owner);
captures
.iter()
- .map(|capture| {
- has_drop_glue_impl(infcx, capture.ty(db, subst), env.clone(), visited)
- })
+ .map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited))
.max()
.unwrap_or(DropGlue::None)
}
@@ -169,14 +162,14 @@ fn has_drop_glue_impl<'db>(
| TyKind::Placeholder(..) => DropGlue::None,
TyKind::Dynamic(..) => DropGlue::HasDropGlue,
TyKind::Alias(..) => {
- if infcx.type_is_copy_modulo_regions(env.env, ty) {
+ if infcx.type_is_copy_modulo_regions(env, ty) {
DropGlue::None
} else {
DropGlue::HasDropGlue
}
}
TyKind::Param(_) => {
- if infcx.type_is_copy_modulo_regions(env.env, ty) {
+ if infcx.type_is_copy_modulo_regions(env, ty) {
DropGlue::None
} else {
DropGlue::DependOnParams
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 4c1590a450..64b15eb017 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -3,9 +3,9 @@
use std::ops::ControlFlow;
use hir_def::{
- AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
- TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId,
- signatures::TraitFlags,
+ AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId,
+ TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId,
+ nameres::crate_def_map, signatures::TraitFlags,
};
use rustc_hash::FxHashSet;
use rustc_type_ir::{
@@ -130,7 +130,7 @@ pub fn dyn_compatibility_of_trait_query(
}
pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
- let krate = def.module(db).krate();
+ let krate = def.module(db).krate(db);
let interner = DbInterner::new_with(db, krate);
let Some(sized) = interner.lang_items().Sized else {
return false;
@@ -295,7 +295,7 @@ where
})
}
AssocItemId::TypeAliasId(it) => {
- let def_map = CrateRootModuleId::from(trait_.krate(db)).def_map(db);
+ let def_map = crate_def_map(db, trait_.krate(db));
if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) {
ControlFlow::Continue(())
} else {
@@ -402,7 +402,7 @@ fn receiver_is_dispatchable<'db>(
let sig = sig.instantiate_identity();
let module = trait_.module(db);
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
let self_param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
parent: trait_.into(),
local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
@@ -427,9 +427,14 @@ fn receiver_is_dispatchable<'db>(
};
let meta_sized_did = lang_items.MetaSized;
- let Some(meta_sized_did) = meta_sized_did else {
- return false;
- };
+
+ // TODO: This is for supporting dyn compatibility for toolchains doesn't contain `MetaSized`
+ // trait. Uncomment and short circuit here once `MINIMUM_SUPPORTED_TOOLCHAIN_VERSION`
+ // become > 1.88.0
+ //
+ // let Some(meta_sized_did) = meta_sized_did else {
+ // return false;
+ // };
// Type `U`
// FIXME: That seems problematic to fake a generic param like that?
@@ -450,17 +455,16 @@ fn receiver_is_dispatchable<'db>(
});
let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args);
- let meta_sized_predicate =
- TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]);
+ let meta_sized_predicate = meta_sized_did
+ .map(|did| TraitRef::new(interner, did.into(), [unsized_self_ty]).upcast(interner));
ParamEnv {
clauses: Clauses::new_from_iter(
interner,
- generic_predicates.iter_identity_copied().chain([
- unsize_predicate.upcast(interner),
- trait_predicate.upcast(interner),
- meta_sized_predicate.upcast(interner),
- ]),
+ generic_predicates
+ .iter_identity_copied()
+ .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)])
+ .chain(meta_sized_predicate),
),
}
};
diff --git a/crates/hir-ty/src/dyn_compatibility/tests.rs b/crates/hir-ty/src/dyn_compatibility/tests.rs
index f90cd608e9..5c9b06e39a 100644
--- a/crates/hir-ty/src/dyn_compatibility/tests.rs
+++ b/crates/hir-ty/src/dyn_compatibility/tests.rs
@@ -35,7 +35,7 @@ fn check_dyn_compatibility<'a>(
for (trait_id, name) in file_ids.into_iter().flat_map(|file_id| {
let module_id = db.module_for_file(file_id.file_id(&db));
let def_map = module_id.def_map(&db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
scope
.declarations()
.filter_map(|def| {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index ab173799bc..70868e4b95 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -653,19 +653,16 @@ impl<'db> InferenceResult<'db> {
}
pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<Ty<'db>> {
match self.expr_adjustments.get(&id).and_then(|adjustments| {
- adjustments
- .iter()
- .filter(|adj| {
- // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140
- !matches!(
- adj,
- Adjustment {
- kind: Adjust::NeverToAny,
- target,
- } if target.is_never()
- )
- })
- .next_back()
+ adjustments.iter().rfind(|adj| {
+ // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140
+ !matches!(
+ adj,
+ Adjustment {
+ kind: Adjust::NeverToAny,
+ target,
+ } if target.is_never()
+ )
+ })
}) {
Some(adjustment) => Some(adjustment.target),
None => self.type_of_expr.get(id).copied(),
@@ -944,7 +941,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
resolver: Resolver<'db>,
) -> Self {
let trait_env = db.trait_environment_for_body(owner);
- let table = unify::InferenceTable::new(db, trait_env, Some(owner));
+ let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner));
let types = InternedStandardTypes::new(table.interner());
InferenceContext {
result: InferenceResult::new(types.error),
diff --git a/crates/hir-ty/src/infer/autoderef.rs b/crates/hir-ty/src/infer/autoderef.rs
index 1af102af23..b54a6cdee2 100644
--- a/crates/hir-ty/src/infer/autoderef.rs
+++ b/crates/hir-ty/src/infer/autoderef.rs
@@ -16,11 +16,11 @@ use crate::{
impl<'db> InferenceTable<'db> {
pub(crate) fn autoderef(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db, usize> {
- Autoderef::new(&self.infer_ctxt, &self.trait_env, base_ty)
+ Autoderef::new(&self.infer_ctxt, self.param_env, base_ty)
}
pub(crate) fn autoderef_with_tracking(&self, base_ty: Ty<'db>) -> Autoderef<'_, 'db> {
- Autoderef::new_with_tracking(&self.infer_ctxt, &self.trait_env, base_ty)
+ Autoderef::new_with_tracking(&self.infer_ctxt, self.param_env, base_ty)
}
}
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 89ebd2b21d..14b0c9076c 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -367,7 +367,7 @@ impl<'db> InferenceContext<'_, 'db> {
_ = self
.table
.infer_ctxt
- .at(&ObligationCause::new(), self.table.trait_env.env)
+ .at(&ObligationCause::new(), self.table.param_env)
.eq(inferred_fnptr_sig, generalized_fnptr_sig)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
@@ -749,19 +749,18 @@ impl<'db> InferenceContext<'_, 'db> {
{
// Check that E' = S'.
let cause = ObligationCause::new();
- let InferOk { value: (), obligations } = table
- .infer_ctxt
- .at(&cause, table.trait_env.env)
- .eq(expected_ty, supplied_ty)?;
+ let InferOk { value: (), obligations } =
+ table.infer_ctxt.at(&cause, table.param_env).eq(expected_ty, supplied_ty)?;
all_obligations.extend(obligations);
}
let supplied_output_ty = supplied_sig.output();
let cause = ObligationCause::new();
- let InferOk { value: (), obligations } = table
- .infer_ctxt
- .at(&cause, table.trait_env.env)
- .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
+ let InferOk { value: (), obligations } =
+ table
+ .infer_ctxt
+ .at(&cause, table.param_env)
+ .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
all_obligations.extend(obligations);
let inputs = supplied_sig
diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs
index 251e7f7cf6..308c01865a 100644
--- a/crates/hir-ty/src/infer/closure/analysis.rs
+++ b/crates/hir-ty/src/infer/closure/analysis.rs
@@ -43,11 +43,12 @@ impl<'db> HirPlace<'db> {
for p in &self.projections {
ty = p.projected_ty(
&ctx.table.infer_ctxt,
+ ctx.table.param_env,
ty,
|_, _, _| {
unreachable!("Closure field only happens in MIR");
},
- ctx.owner.module(ctx.db).krate(),
+ ctx.owner.module(ctx.db).krate(ctx.db),
);
}
ty
@@ -149,7 +150,7 @@ impl<'db> CapturedItem<'db> {
}
}
}
- if is_raw_identifier(&result, owner.module(db).krate().data(db).edition) {
+ if is_raw_identifier(&result, owner.module(db).krate(db).data(db).edition) {
result.insert_str(0, "r#");
}
result
@@ -839,11 +840,12 @@ impl<'db> InferenceContext<'_, 'db> {
for (i, p) in capture.place.projections.iter().enumerate() {
ty = p.projected_ty(
&self.table.infer_ctxt,
+ self.table.param_env,
ty,
|_, _, _| {
unreachable!("Closure field only happens in MIR");
},
- self.owner.module(self.db).krate(),
+ self.owner.module(self.db).krate(self.db),
);
if ty.is_raw_ptr() || ty.is_union() {
capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index df24148920..77c7155550 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -50,10 +50,9 @@ use rustc_type_ir::{
};
use smallvec::{SmallVec, smallvec};
use tracing::{debug, instrument};
-use triomphe::Arc;
use crate::{
- Adjust, Adjustment, AutoBorrow, PointerCast, TargetFeatures, TraitEnvironment,
+ Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures,
autoderef::Autoderef,
db::{HirDatabase, InternedClosureId},
infer::{
@@ -62,7 +61,7 @@ use crate::{
next_solver::{
Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper,
Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed,
- GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
+ GenericArgs, ParamEnv, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
TypingMode,
infer::{
DbInternerInferExt, InferCtxt, InferOk, InferResult,
@@ -77,7 +76,7 @@ use crate::{
trait CoerceDelegate<'db> {
fn infcx(&self) -> &InferCtxt<'db>;
- fn env(&self) -> &TraitEnvironment<'db>;
+ fn param_env(&self) -> ParamEnv<'db>;
fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget);
fn set_diverging(&mut self, diverging_ty: Ty<'db>);
@@ -137,8 +136,8 @@ where
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- self.delegate.env()
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.delegate.param_env()
}
#[inline]
@@ -169,7 +168,7 @@ where
fn unify_raw(&self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.infcx().commit_if_ok(|_| {
- let at = self.infcx().at(&self.cause, self.env().env);
+ let at = self.infcx().at(&self.cause, self.param_env());
let res = if self.use_lub {
at.lub(b, a)
@@ -329,7 +328,7 @@ where
obligations.push(Obligation::new(
self.interner(),
self.cause.clone(),
- self.env().env,
+ self.param_env(),
Binder::dummy(PredicateKind::Coerce(CoercePredicate {
a: source_ty,
b: target_ty,
@@ -381,7 +380,7 @@ where
let mut first_error = None;
let mut r_borrow_var = None;
- let mut autoderef = Autoderef::new_with_tracking(self.infcx(), self.env(), a);
+ let mut autoderef = Autoderef::new_with_tracking(self.infcx(), self.param_env(), a);
let mut found = None;
for (referent_ty, autoderefs) in autoderef.by_ref() {
@@ -684,7 +683,7 @@ where
let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new(
self.interner(),
cause,
- self.env().env,
+ self.param_env(),
TraitRef::new(
self.interner(),
coerce_unsized_did.into(),
@@ -975,8 +974,8 @@ impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> {
&self.0.table.infer_ctxt
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- &self.0.table.trait_env
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.0.table.param_env
}
#[inline]
@@ -1104,12 +1103,8 @@ impl<'db> InferenceContext<'_, 'db> {
match self.table.commit_if_ok(|table| {
// We need to eagerly handle nested obligations due to lazy norm.
let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
- let value = ocx.lub(
- &ObligationCause::new(),
- table.trait_env.env,
- prev_ty,
- new_ty,
- )?;
+ let value =
+ ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?;
if ocx.try_evaluate_obligations().is_empty() {
Ok(InferOk { value, obligations: ocx.into_pending_obligations() })
} else {
@@ -1152,7 +1147,7 @@ impl<'db> InferenceContext<'_, 'db> {
let sig = self
.table
.infer_ctxt
- .at(&ObligationCause::new(), self.table.trait_env.env)
+ .at(&ObligationCause::new(), self.table.param_env)
.lub(a_sig, b_sig)
.map(|ok| self.table.register_infer_ok(ok))?;
@@ -1231,7 +1226,7 @@ impl<'db> InferenceContext<'_, 'db> {
.commit_if_ok(|table| {
table
.infer_ctxt
- .at(&ObligationCause::new(), table.trait_env.env)
+ .at(&ObligationCause::new(), table.param_env)
.lub(prev_ty, new_ty)
})
.unwrap_err())
@@ -1483,7 +1478,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
//
// Another example is `break` with no argument expression.
assert!(expression_ty.is_unit(), "if let hack without unit type");
- icx.table.infer_ctxt.at(cause, icx.table.trait_env.env).eq(expected, found).map(
+ icx.table.infer_ctxt.at(cause, icx.table.param_env).eq(expected, found).map(
|infer_ok| {
icx.table.register_infer_ok(infer_ok);
expression_ty
@@ -1540,7 +1535,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
pub fn could_coerce<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
) -> bool {
coerce(db, env, tys).is_ok()
@@ -1548,7 +1543,7 @@ pub fn could_coerce<'db>(
struct HirCoercionDelegate<'a, 'db> {
infcx: &'a InferCtxt<'db>,
- env: &'a TraitEnvironment<'db>,
+ param_env: ParamEnv<'db>,
target_features: &'a TargetFeatures<'db>,
}
@@ -1558,8 +1553,8 @@ impl<'db> CoerceDelegate<'db> for HirCoercionDelegate<'_, 'db> {
self.infcx
}
#[inline]
- fn env(&self) -> &TraitEnvironment<'db> {
- self.env
+ fn param_env(&self) -> ParamEnv<'db> {
+ self.param_env
}
fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) {
(self.target_features, TargetFeatureIsSafeInTarget::No)
@@ -1573,7 +1568,7 @@ impl<'db> CoerceDelegate<'db> for HirCoercionDelegate<'_, 'db> {
fn coerce<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
) -> Result<(Vec<Adjustment<'db>>, Ty<'db>), TypeError<DbInterner<'db>>> {
let interner = DbInterner::new_with(db, env.krate);
@@ -1586,7 +1581,7 @@ fn coerce<'db>(
let mut coerce = Coerce {
delegate: HirCoercionDelegate {
infcx: &infcx,
- env: &env,
+ param_env: env.param_env,
target_features: &target_features,
},
cause,
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 01508b0f9b..4e1711e48e 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -4,7 +4,7 @@ use std::{iter::repeat_with, mem};
use either::Either;
use hir_def::{
- BlockId, FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId,
+ FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId,
expr_store::path::{GenericArgs as HirGenericArgs, Path},
hir::{
Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId,
@@ -23,7 +23,7 @@ use syntax::ast::RangeOp;
use tracing::debug;
use crate::{
- Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness, TraitEnvironment,
+ Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness,
autoderef::InferenceContextAutoderef,
consteval,
db::InternedCoroutine,
@@ -377,11 +377,11 @@ impl<'db> InferenceContext<'_, 'db> {
);
self.types.bool
}
- Expr::Block { statements, tail, label, id } => {
- self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
+ Expr::Block { statements, tail, label, id: _ } => {
+ self.infer_block(tgt_expr, statements, *tail, *label, expected)
}
- Expr::Unsafe { id, statements, tail } => {
- self.infer_block(tgt_expr, *id, statements, *tail, None, expected)
+ Expr::Unsafe { id: _, statements, tail } => {
+ self.infer_block(tgt_expr, statements, *tail, None, expected)
}
Expr::Const(id) => {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
@@ -389,8 +389,8 @@ impl<'db> InferenceContext<'_, 'db> {
})
.1
}
- Expr::Async { id, statements, tail } => {
- self.infer_async_block(tgt_expr, id, statements, tail)
+ Expr::Async { id: _, statements, tail } => {
+ self.infer_async_block(tgt_expr, statements, tail)
}
&Expr::Loop { body, label } => {
// FIXME: should be:
@@ -1167,7 +1167,6 @@ impl<'db> InferenceContext<'_, 'db> {
fn infer_async_block(
&mut self,
tgt_expr: ExprId,
- id: &Option<BlockId>,
statements: &[Statement],
tail: &Option<ExprId>,
) -> Ty<'db> {
@@ -1179,7 +1178,7 @@ impl<'db> InferenceContext<'_, 'db> {
// FIXME: We should handle async blocks like we handle closures
let expected = &Expectation::has_type(ret_ty);
let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
- let ty = this.infer_block(tgt_expr, *id, statements, *tail, None, expected);
+ let ty = this.infer_block(tgt_expr, statements, *tail, None, expected);
if let Some(target) = expected.only_has_type(&mut this.table) {
match this.coerce(tgt_expr.into(), ty, target, AllowTwoPhase::No, ExprIsRead::Yes) {
Ok(res) => res,
@@ -1447,7 +1446,6 @@ impl<'db> InferenceContext<'_, 'db> {
fn infer_block(
&mut self,
expr: ExprId,
- block_id: Option<BlockId>,
statements: &[Statement],
tail: Option<ExprId>,
label: Option<LabelId>,
@@ -1455,11 +1453,6 @@ impl<'db> InferenceContext<'_, 'db> {
) -> Ty<'db> {
let coerce_ty = expected.coercion_target_type(&mut self.table);
let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
- let prev_env = block_id.map(|block_id| {
- let prev_env = self.table.trait_env.clone();
- TraitEnvironment::with_block(&mut self.table.trait_env, block_id);
- prev_env
- });
let (break_ty, ty) =
self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| {
@@ -1566,9 +1559,6 @@ impl<'db> InferenceContext<'_, 'db> {
}
});
self.resolver.reset_to_guard(g);
- if let Some(prev_env) = prev_env {
- self.table.trait_env = prev_env;
- }
break_ty.unwrap_or(ty)
}
@@ -1974,7 +1964,7 @@ impl<'db> InferenceContext<'_, 'db> {
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = ObligationCause::new();
- ocx.sup(&origin, self.table.trait_env.env, expected_output, formal_output)?;
+ ocx.sup(&origin, self.table.param_env, expected_output, formal_output)?;
if !ocx.try_evaluate_obligations().is_empty() {
return Err(TypeError::Mismatch);
}
@@ -2066,7 +2056,7 @@ impl<'db> InferenceContext<'_, 'db> {
let formal_ty_error = this
.table
.infer_ctxt
- .at(&ObligationCause::new(), this.table.trait_env.env)
+ .at(&ObligationCause::new(), this.table.param_env)
.eq(formal_input_ty, coerced_ty);
// If neither check failed, the types are compatible
@@ -2143,7 +2133,7 @@ impl<'db> InferenceContext<'_, 'db> {
self.db,
GenericDefId::from_callable(self.db, fn_def.0),
);
- let param_env = self.table.trait_env.env;
+ let param_env = self.table.param_env;
self.table.register_predicates(clauses_as_obligations(
generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()),
ObligationCause::new(),
@@ -2162,7 +2152,7 @@ impl<'db> InferenceContext<'_, 'db> {
self.table.register_predicate(Obligation::new(
self.interner(),
ObligationCause::new(),
- self.table.trait_env.env,
+ self.table.param_env,
TraitRef::new(self.interner(), trait_.into(), substs),
));
}
diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs
index 6fbac8f5ae..8236de167f 100644
--- a/crates/hir-ty/src/infer/op.rs
+++ b/crates/hir-ty/src/infer/op.rs
@@ -343,7 +343,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
let obligation = Obligation::new(
self.interner(),
cause,
- self.table.trait_env.env,
+ self.table.param_env,
TraitRef::new_from_args(self.interner(), trait_did.into(), args),
);
let mut ocx = ObligationCtxt::new(self.infcx());
diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs
index ba4b53a0d7..ce4597f83d 100644
--- a/crates/hir-ty/src/infer/opaques.rs
+++ b/crates/hir-ty/src/infer/opaques.rs
@@ -136,7 +136,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
let cause = ObligationCause::new();
- let at = self.table.infer_ctxt.at(&cause, self.table.trait_env.env);
+ let at = self.table.infer_ctxt.at(&cause, self.table.param_env);
let hidden_type = match at.deeply_normalize(hidden_type) {
Ok(hidden_type) => hidden_type,
Err(_errors) => OpaqueHiddenType { ty: self.types.error },
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 6e3d15893f..301cbf462c 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -224,7 +224,7 @@ impl<'db> InferenceContext<'_, 'db> {
) {
let interner = self.interner();
let predicates = GenericPredicates::query_all(self.db, def);
- let param_env = self.table.trait_env.env;
+ let param_env = self.table.param_env;
self.table.register_predicates(clauses_as_obligations(
predicates.iter_instantiated_copied(interner, subst.as_slice()),
ObligationCause::new(),
@@ -343,7 +343,7 @@ impl<'db> InferenceContext<'_, 'db> {
self.table.register_predicate(Obligation::new(
self.interner(),
ObligationCause::new(),
- self.table.trait_env.env,
+ self.table.param_env,
trait_ref,
));
args
diff --git a/crates/hir-ty/src/infer/place_op.rs b/crates/hir-ty/src/infer/place_op.rs
index 9544fb449f..3ef5e5870a 100644
--- a/crates/hir-ty/src/infer/place_op.rs
+++ b/crates/hir-ty/src/infer/place_op.rs
@@ -124,7 +124,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
ctx.table.register_predicate(Obligation::new(
ctx.interner(),
ObligationCause::new(),
- ctx.table.trait_env.env,
+ ctx.table.param_env,
ClauseKind::ConstArgHasType(ct, ctx.types.usize),
));
self_ty = Ty::new_slice(ctx.interner(), element_ty);
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index bc3c46341c..a5060416a1 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -2,6 +2,7 @@
use std::fmt;
+use base_db::Crate;
use hir_def::{AdtId, DefWithBodyId, GenericParamId};
use hir_expand::name::Name;
use intern::sym;
@@ -12,15 +13,13 @@ use rustc_type_ir::{
solve::Certainty,
};
use smallvec::SmallVec;
-use triomphe::Arc;
use crate::{
- TraitEnvironment,
db::HirDatabase,
next_solver::{
AliasTy, Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg,
- GenericArgs, Goal, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty,
- TyKind, TypingMode,
+ GenericArgs, Goal, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef,
+ Ty, TyKind, TypingMode,
fulfill::{FulfillmentCtxt, NextSolverError},
infer::{
DbInternerInferExt, InferCtxt, InferOk, InferResult,
@@ -32,7 +31,8 @@ use crate::{
obligation_ctxt::ObligationCtxt,
},
traits::{
- FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt,
+ FnTrait, NextTraitSolveResult, ParamEnvAndCrate, next_trait_solve_canonical_in_ctxt,
+ next_trait_solve_in_ctxt,
},
};
@@ -89,7 +89,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> {
/// unresolved goal `T = U`.
pub fn could_unify<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
) -> bool {
could_unify_impl(db, env, tys, |ctxt| ctxt.try_evaluate_obligations())
@@ -101,7 +101,7 @@ pub fn could_unify<'db>(
/// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
pub fn could_unify_deeply<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
) -> bool {
could_unify_impl(db, env, tys, |ctxt| ctxt.evaluate_obligations_error_on_ambiguity())
@@ -109,14 +109,14 @@ pub fn could_unify_deeply<'db>(
fn could_unify_impl<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
select: for<'a> fn(&mut ObligationCtxt<'a, 'db>) -> Vec<NextSolverError<'db>>,
) -> bool {
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let cause = ObligationCause::dummy();
- let at = infcx.at(&cause, env.env);
+ let at = infcx.at(&cause, env.param_env);
let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys);
let mut ctxt = ObligationCtxt::new(&infcx);
let can_unify = at
@@ -129,7 +129,7 @@ fn could_unify_impl<'db>(
#[derive(Clone)]
pub(crate) struct InferenceTable<'db> {
pub(crate) db: &'db dyn HirDatabase,
- pub(crate) trait_env: Arc<TraitEnvironment<'db>>,
+ pub(crate) param_env: ParamEnv<'db>,
pub(crate) infer_ctxt: InferCtxt<'db>,
pub(super) fulfillment_cx: FulfillmentCtxt<'db>,
pub(super) diverging_type_vars: FxHashSet<Ty<'db>>,
@@ -145,10 +145,11 @@ impl<'db> InferenceTable<'db> {
/// Outside it, always pass `owner = None`.
pub(crate) fn new(
db: &'db dyn HirDatabase,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnv<'db>,
+ krate: Crate,
owner: Option<DefWithBodyId>,
) -> Self {
- let interner = DbInterner::new_with(db, trait_env.krate);
+ let interner = DbInterner::new_with(db, krate);
let typing_mode = match owner {
Some(owner) => TypingMode::typeck_for_body(interner, owner.into()),
// IDE things wants to reveal opaque types.
@@ -157,7 +158,7 @@ impl<'db> InferenceTable<'db> {
let infer_ctxt = interner.infer_ctxt().build(typing_mode);
InferenceTable {
db,
- trait_env,
+ param_env: trait_env,
fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt),
infer_ctxt,
diverging_type_vars: FxHashSet::default(),
@@ -170,7 +171,7 @@ impl<'db> InferenceTable<'db> {
}
pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'db>) -> bool {
- self.infer_ctxt.type_is_copy_modulo_regions(self.trait_env.env, ty)
+ self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty)
}
pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool {
@@ -272,7 +273,7 @@ impl<'db> InferenceTable<'db> {
pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> {
self.infer_ctxt
- .at(&ObligationCause::new(), self.trait_env.env)
+ .at(&ObligationCause::new(), self.param_env)
.structurally_normalize_ty(alias, &mut self.fulfillment_cx)
.unwrap_or(alias)
}
@@ -332,7 +333,7 @@ impl<'db> InferenceTable<'db> {
}
pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> {
- self.infer_ctxt.at(cause, self.trait_env.env)
+ self.infer_ctxt.at(cause, self.param_env)
}
pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> {
@@ -374,7 +375,7 @@ impl<'db> InferenceTable<'db> {
// in a reentrant borrow, causing an ICE.
let result = self
.infer_ctxt
- .at(&ObligationCause::misc(), self.trait_env.env)
+ .at(&ObligationCause::misc(), self.param_env)
.structurally_normalize_ty(ty, &mut self.fulfillment_cx);
match result {
Ok(normalized_ty) => normalized_ty,
@@ -422,14 +423,14 @@ impl<'db> InferenceTable<'db> {
/// choice (during e.g. method resolution or deref).
#[tracing::instrument(level = "debug", skip(self))]
pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult {
- let goal = Goal { param_env: self.trait_env.env, predicate };
+ let goal = Goal { param_env: self.param_env, predicate };
let canonicalized = self.canonicalize(goal);
next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized)
}
pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) {
- let goal = Goal { param_env: self.trait_env.env, predicate };
+ let goal = Goal { param_env: self.param_env, predicate };
self.register_obligation_in_env(goal)
}
@@ -486,7 +487,7 @@ impl<'db> InferenceTable<'db> {
self.register_predicate(Obligation::new(
self.interner(),
cause,
- self.trait_env.env,
+ self.param_env,
ClauseKind::WellFormed(term),
));
}
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index 5e742bba3e..075a7066db 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -7,14 +7,12 @@ use rustc_type_ir::{
TypeSuperVisitable, TypeVisitable, TypeVisitor,
inherent::{AdtDef, IntoKind},
};
-use triomphe::Arc;
use crate::{
- TraitEnvironment,
consteval::try_const_usize,
db::HirDatabase,
next_solver::{
- DbInterner, EarlyBinder, GenericArgs, Ty, TyKind,
+ DbInterner, EarlyBinder, GenericArgs, ParamEnv, Ty, TyKind,
infer::{InferCtxt, traits::ObligationCause},
obligation_ctxt::ObligationCtxt,
},
@@ -26,7 +24,7 @@ pub(crate) fn is_ty_uninhabited_from<'db>(
infcx: &InferCtxt<'db>,
ty: Ty<'db>,
target_mod: ModuleId,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
) -> bool {
let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env);
@@ -41,7 +39,7 @@ pub(crate) fn is_enum_variant_uninhabited_from<'db>(
variant: EnumVariantId,
subst: GenericArgs<'db>,
target_mod: ModuleId,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
) -> bool {
let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
@@ -56,7 +54,7 @@ struct UninhabitedFrom<'a, 'db> {
// guard for preventing stack overflow in non trivial non terminating types
max_depth: usize,
infcx: &'a InferCtxt<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
}
const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
@@ -78,7 +76,7 @@ impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> {
if matches!(ty.kind(), TyKind::Alias(..)) {
let mut ocx = ObligationCtxt::new(self.infcx);
- match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env.env, ty) {
+ match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env, ty) {
Ok(it) => ty = it,
Err(_) => return CONTINUE_OPAQUELY_INHABITED,
}
@@ -101,11 +99,7 @@ impl<'db> TypeVisitor<DbInterner<'db>> for UninhabitedFrom<'_, 'db> {
}
impl<'a, 'db> UninhabitedFrom<'a, 'db> {
- fn new(
- infcx: &'a InferCtxt<'db>,
- target_mod: ModuleId,
- env: Arc<TraitEnvironment<'db>>,
- ) -> Self {
+ fn new(infcx: &'a InferCtxt<'db>, target_mod: ModuleId, env: ParamEnv<'db>) -> Self {
Self { target_mod, recursive_ty: FxHashSet::default(), max_depth: 500, infcx, env }
}
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index 97660a67ef..4b20d6eb32 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -21,11 +21,11 @@ use rustc_type_ir::{
use triomphe::Arc;
use crate::{
- InferenceResult, TraitEnvironment,
+ InferenceResult, ParamEnvAndCrate,
consteval::try_const_usize,
db::HirDatabase,
next_solver::{
- DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
+ DbInterner, GenericArgs, Ty, TyKind, TypingMode,
infer::{DbInternerInferExt, traits::ObligationCause},
},
};
@@ -131,7 +131,7 @@ fn layout_of_simd_ty<'db>(
id: StructId,
repr_packed: bool,
args: &GenericArgs<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
dl: &TargetDataLayout,
) -> Result<Arc<Layout>, LayoutError> {
// Supported SIMD vectors are homogeneous ADTs with exactly one array field:
@@ -159,7 +159,7 @@ fn layout_of_simd_ty<'db>(
pub fn layout_of_ty_query<'db>(
db: &'db dyn HirDatabase,
ty: Ty<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError> {
let krate = trait_env.krate;
let interner = DbInterner::new_with(db, krate);
@@ -170,7 +170,7 @@ pub fn layout_of_ty_query<'db>(
let cx = LayoutCx::new(dl);
let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let cause = ObligationCause::dummy();
- let ty = infer_ctxt.at(&cause, ParamEnv::empty()).deeply_normalize(ty).unwrap_or(ty);
+ let ty = infer_ctxt.at(&cause, trait_env.param_env).deeply_normalize(ty).unwrap_or(ty);
let result = match ty.kind() {
TyKind::Adt(def, args) => {
match def.inner().id {
@@ -248,10 +248,8 @@ pub fn layout_of_ty_query<'db>(
let kind =
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
- let fields = tys
- .iter()
- .map(|k| db.layout_of_ty(k, trait_env.clone()))
- .collect::<Result<Vec<_>, _>>()?;
+ let fields =
+ tys.iter().map(|k| db.layout_of_ty(k, trait_env)).collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
let fields = fields.iter().collect::<IndexVec<_, _>>();
cx.calc.univariant(&fields, &ReprOptions::default(), kind)?
@@ -329,7 +327,7 @@ pub fn layout_of_ty_query<'db>(
.map(|it| {
let ty =
it.ty.instantiate(interner, args.split_closure_args_untupled().parent_args);
- db.layout_of_ty(ty, trait_env.clone())
+ db.layout_of_ty(ty, trait_env)
})
.collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
@@ -362,7 +360,7 @@ pub fn layout_of_ty_query<'db>(
pub(crate) fn layout_of_ty_cycle_result<'db>(
_: &dyn HirDatabase,
_: Ty<'db>,
- _: Arc<TraitEnvironment<'db>>,
+ _: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError> {
Err(LayoutError::RecursiveTypeWithoutIndirection)
}
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index ecebf7935d..cf2d0989fd 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -13,7 +13,7 @@ use smallvec::SmallVec;
use triomphe::Arc;
use crate::{
- TraitEnvironment,
+ ParamEnvAndCrate,
db::HirDatabase,
layout::{Layout, LayoutCx, LayoutError, field_ty},
next_solver::GenericArgs,
@@ -23,7 +23,7 @@ pub fn layout_of_adt_query<'db>(
db: &'db dyn HirDatabase,
def: AdtId,
args: GenericArgs<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError> {
let krate = trait_env.krate;
let Ok(target) = db.target_data_layout(krate) else {
@@ -34,7 +34,7 @@ pub fn layout_of_adt_query<'db>(
let handle_variant = |def: VariantId, var: &VariantFields| {
var.fields()
.iter()
- .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &args), trait_env.clone()))
+ .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &args), trait_env))
.collect::<Result<Vec<_>, _>>()
};
let (variants, repr, is_special_no_niche) = match def {
@@ -99,7 +99,7 @@ pub(crate) fn layout_of_adt_cycle_result<'db>(
_: &'db dyn HirDatabase,
_def: AdtId,
_args: GenericArgs<'db>,
- _trait_env: Arc<TraitEnvironment<'db>>,
+ _trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<Layout>, LayoutError> {
Err(LayoutError::RecursiveTypeWithoutIndirection)
}
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index 878813a696..be6a76478a 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -1,6 +1,6 @@
use base_db::target::TargetData;
use either::Either;
-use hir_def::db::DefDatabase;
+use hir_def::{HasModule, db::DefDatabase};
use project_model::{Sysroot, toolchain_info::QueryConfig};
use rustc_hash::FxHashMap;
use rustc_type_ir::inherent::GenericArgs as _;
@@ -9,7 +9,7 @@ use test_fixture::WithFixture;
use triomphe::Arc;
use crate::{
- InferenceResult,
+ InferenceResult, ParamEnvAndCrate,
db::HirDatabase,
layout::{Layout, LayoutError},
next_solver::{DbInterner, GenericArgs},
@@ -45,7 +45,7 @@ fn eval_goal(
.find_map(|file_id| {
let module_id = db.module_for_file(file_id.file_id(&db));
let def_map = module_id.def_map(&db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
let adt_or_type_alias_id = scope.declarations().find_map(|x| match x {
hir_def::ModuleDefId::AdtId(x) => {
let name = match x {
@@ -90,13 +90,15 @@ fn eval_goal(
),
Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(),
};
- db.layout_of_ty(
- goal_ty,
- db.trait_environment(match adt_or_type_alias_id {
- Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
- Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
- }),
- )
+ let param_env = db.trait_environment(match adt_or_type_alias_id {
+ Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
+ Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
+ });
+ let krate = match adt_or_type_alias_id {
+ Either::Left(it) => it.krate(&db),
+ Either::Right(it) => it.krate(&db),
+ };
+ db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate })
})
}
@@ -116,7 +118,7 @@ fn eval_expr(
crate::attach_db(&db, || {
let module_id = db.module_for_file(file_id.file_id(&db));
let def_map = module_id.def_map(&db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
let function_id = scope
.declarations()
.find_map(|x| match x {
@@ -139,7 +141,9 @@ fn eval_expr(
.0;
let infer = InferenceResult::for_body(&db, function_id.into());
let goal_ty = infer.type_of_binding[b];
- db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))
+ let param_env = db.trait_environment(function_id.into());
+ let krate = function_id.krate(&db);
+ db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate })
})
}
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 6d3adec6a8..5ebe87c5d5 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -2,6 +2,8 @@
//! information and various assists.
#![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)]
// FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but
// temporarily switched to crates.io versions due to hardships that working on them from rustc
@@ -67,7 +69,6 @@ use rustc_type_ir::{
};
use syntax::ast::{ConstArg, make};
use traits::FnTrait;
-use triomphe::Arc;
use crate::{
db::HirDatabase,
@@ -94,7 +95,7 @@ pub use lower::{
};
pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db};
pub use target_feature::TargetFeatures;
-pub use traits::{TraitEnvironment, check_orphan_rules};
+pub use traits::{ParamEnvAndCrate, check_orphan_rules};
pub use utils::{
TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits,
is_fn_unsafe_to_call, target_feature_is_safe_in_target,
@@ -474,10 +475,10 @@ where
/// To be used from `hir` only.
pub fn callable_sig_from_fn_trait<'db>(
self_ty: Ty<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
db: &'db dyn HirDatabase,
) -> Option<(FnTrait, PolyFnSig<'db>)> {
- let mut table = InferenceTable::new(db, trait_env.clone(), None);
+ let mut table = InferenceTable::new(db, trait_env.param_env, trait_env.krate, None);
let lang_items = table.interner().lang_items();
let fn_once_trait = FnTrait::FnOnce.get_id(lang_items)?;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index cfd2a06b2a..dd34bbe2fd 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -53,7 +53,7 @@ use tracing::debug;
use triomphe::{Arc, ThinArc};
use crate::{
- FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
+ FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind,
consteval::intern_const_ref,
db::{HirDatabase, InternedOpaqueTyId},
generics::{Generics, generics, trait_self_param_idx},
@@ -1743,10 +1743,9 @@ impl<'db> GenericPredicates<'db> {
pub(crate) fn trait_environment_for_body_query(
db: &dyn HirDatabase,
def: DefWithBodyId,
-) -> Arc<TraitEnvironment<'_>> {
+) -> ParamEnv<'_> {
let Some(def) = def.as_generic_def_id(db) else {
- let krate = def.module(db).krate();
- return TraitEnvironment::empty(krate);
+ return ParamEnv::empty();
};
db.trait_environment(def)
}
@@ -1754,24 +1753,15 @@ pub(crate) fn trait_environment_for_body_query(
pub(crate) fn trait_environment_query<'db>(
db: &'db dyn HirDatabase,
def: GenericDefId,
-) -> Arc<TraitEnvironment<'db>> {
+) -> ParamEnv<'db> {
let module = def.module(db);
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
let predicates = GenericPredicates::query_all(db, def);
- let traits_in_scope = predicates
- .iter_identity_copied()
- .filter_map(|pred| match pred.kind().skip_binder() {
- ClauseKind::Trait(tr) => Some((tr.self_ty(), tr.def_id().0)),
- _ => None,
- })
- .collect();
let clauses = rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied());
let clauses = Clauses::new_from_iter(interner, clauses);
- let env = ParamEnv { clauses };
// FIXME: We should normalize projections here, like rustc does.
-
- TraitEnvironment::new(module.krate(), module.containing_block(), traits_in_scope, env)
+ ParamEnv { clauses }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -2289,7 +2279,7 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>(
name: &Name,
) -> Option<(TraitRef<'db>, TypeAliasId)> {
let module = trait_ref.def_id.0.module(db);
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| {
let trait_id = t.as_ref().skip_binder().def_id.0;
let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?;
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 9a6adedb99..868ae00329 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -32,13 +32,13 @@ use stdx::impl_from;
use triomphe::Arc;
use crate::{
- TraitEnvironment, all_super_traits,
+ all_super_traits,
db::HirDatabase,
infer::{InferenceContext, unify::InferenceTable},
lower::GenericPredicates,
next_solver::{
- Binder, ClauseKind, DbInterner, FnSig, GenericArgs, PredicateKind, SimplifiedType,
- SolverDefId, TraitRef, Ty, TyKind, TypingMode,
+ Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
+ SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode,
infer::{
BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk,
select::ImplSource,
@@ -47,6 +47,7 @@ use crate::{
obligation_ctxt::ObligationCtxt,
util::clauses_as_obligations,
},
+ traits::ParamEnvAndCrate,
};
pub use self::probe::{
@@ -75,7 +76,7 @@ impl MethodResolutionUnstableFeatures {
pub struct MethodResolutionContext<'a, 'db> {
pub infcx: &'a InferCtxt<'db>,
pub resolver: &'a Resolver<'db>,
- pub env: &'a TraitEnvironment<'db>,
+ pub param_env: ParamEnv<'db>,
pub traits_in_scope: &'a FxHashSet<TraitId>,
pub edition: Edition,
pub unstable_features: &'a MethodResolutionUnstableFeatures,
@@ -194,7 +195,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> {
let ctx = MethodResolutionContext {
infcx: &self.table.infer_ctxt,
resolver: &self.resolver,
- env: &self.table.trait_env,
+ param_env: self.table.param_env,
traits_in_scope,
edition: self.edition,
unstable_features: &self.unstable_features,
@@ -264,7 +265,7 @@ impl<'db> InferenceTable<'db> {
let obligation = Obligation::new(
self.interner(),
cause,
- self.trait_env.env,
+ self.param_env,
TraitRef::new_from_args(self.interner(), trait_def_id.into(), args),
);
@@ -322,7 +323,7 @@ impl<'db> InferenceTable<'db> {
let bounds = clauses_as_obligations(
bounds.iter_instantiated_copied(interner, args.as_slice()),
ObligationCause::new(),
- self.trait_env.env,
+ self.param_env,
);
obligations.extend(bounds);
@@ -336,7 +337,7 @@ impl<'db> InferenceTable<'db> {
obligations.push(Obligation::new(
interner,
obligation.cause.clone(),
- self.trait_env.env,
+ self.param_env,
Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(ty.into()))),
));
}
@@ -350,7 +351,7 @@ impl<'db> InferenceTable<'db> {
pub fn lookup_impl_const<'db>(
infcx: &InferCtxt<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
const_id: ConstId,
subs: GenericArgs<'db>,
) -> (ConstId, GenericArgs<'db>) {
@@ -380,7 +381,7 @@ pub fn lookup_impl_const<'db>(
/// call the method using the vtable.
pub fn is_dyn_method<'db>(
interner: DbInterner<'db>,
- _env: Arc<TraitEnvironment<'db>>,
+ _env: ParamEnv<'db>,
func: FunctionId,
fn_subst: GenericArgs<'db>,
) -> Option<usize> {
@@ -415,7 +416,7 @@ pub fn is_dyn_method<'db>(
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
pub(crate) fn lookup_impl_method_query<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
func: FunctionId,
fn_subst: GenericArgs<'db>,
) -> (FunctionId, GenericArgs<'db>) {
@@ -433,11 +434,15 @@ pub(crate) fn lookup_impl_method_query<'db>(
);
let name = &db.function_signature(func).name;
- let Some((impl_fn, impl_subst)) =
- lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env, name).and_then(|assoc| {
- if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
- })
- else {
+ let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(
+ &infcx,
+ trait_ref,
+ env.param_env,
+ name,
+ )
+ .and_then(|assoc| {
+ if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
+ }) else {
return (func, fn_subst);
};
@@ -453,10 +458,10 @@ pub(crate) fn lookup_impl_method_query<'db>(
fn lookup_impl_assoc_item_for_trait_ref<'db>(
infcx: &InferCtxt<'db>,
trait_ref: TraitRef<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
name: &Name,
) -> Option<(AssocItemId, GenericArgs<'db>)> {
- let (impl_id, impl_subst) = find_matching_impl(infcx, &env, trait_ref)?;
+ let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
let item =
impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
@@ -468,13 +473,12 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>(
pub(crate) fn find_matching_impl<'db>(
infcx: &InferCtxt<'db>,
- env: &TraitEnvironment<'db>,
+ env: ParamEnv<'db>,
trait_ref: TraitRef<'db>,
) -> Option<(ImplId, GenericArgs<'db>)> {
- let trait_ref =
- infcx.at(&ObligationCause::dummy(), env.env).deeply_normalize(trait_ref).ok()?;
+ let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?;
- let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env.env, trait_ref);
+ let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref);
let selection = infcx.select(&obligation).ok()??;
@@ -629,7 +633,7 @@ impl InherentImpls {
block: Option<BlockId>,
for_each: &mut dyn FnMut(&InherentImpls),
) {
- let blocks = std::iter::successors(block, |block| block.loc(db).module.containing_block());
+ let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
for_each(Self::for_crate(db, krate));
}
@@ -794,7 +798,7 @@ impl TraitImpls {
block: Option<BlockId>,
for_each: &mut dyn FnMut(&TraitImpls),
) {
- let blocks = std::iter::successors(block, |block| block.loc(db).module.containing_block());
+ let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each);
}
@@ -816,7 +820,7 @@ impl TraitImpls {
// This breaks when they are equal (both will stop immediately), therefore we handle this case
// specifically.
let blocks_iter = |block: Option<BlockId>| {
- std::iter::successors(block, |block| block.loc(db).module.containing_block())
+ std::iter::successors(block, |block| block.loc(db).module.block(db))
};
let for_each_block = |current_block: Option<BlockId>, other_block: Option<BlockId>| {
blocks_iter(current_block)
diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs
index 570dd63a50..6d6515a457 100644
--- a/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/crates/hir-ty/src/method_resolution/confirm.rs
@@ -507,7 +507,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
GenericPredicates::query_all(self.db(), def_id.into())
.iter_instantiated_copied(self.interner(), all_args),
ObligationCause::new(),
- self.ctx.table.trait_env.env,
+ self.ctx.table.param_env,
);
let sig =
diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs
index adc144ce11..6af47ab68b 100644
--- a/crates/hir-ty/src/method_resolution/probe.rs
+++ b/crates/hir-ty/src/method_resolution/probe.rs
@@ -334,7 +334,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> {
.infcx
.instantiate_query_response_and_region_obligations(
&ObligationCause::new(),
- self.env.env,
+ self.param_env,
&orig_values,
ty,
)
@@ -394,7 +394,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> {
// converted to, in order to find out which of those methods might actually
// be callable.
let mut autoderef_via_deref =
- Autoderef::new(infcx, self.env, self_ty).include_raw_pointers();
+ Autoderef::new(infcx, self.param_env, self_ty).include_raw_pointers();
let mut reached_raw_pointer = false;
let arbitrary_self_types_enabled = self.unstable_features.arbitrary_self_types
@@ -403,7 +403,7 @@ impl<'a, 'db> MethodResolutionContext<'a, 'db> {
let reachable_via_deref =
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
- let mut autoderef_via_receiver = Autoderef::new(infcx, self.env, self_ty)
+ let mut autoderef_via_receiver = Autoderef::new(infcx, self.param_env, self_ty)
.include_raw_pointers()
.use_receiver_trait();
let steps = autoderef_via_receiver
@@ -835,7 +835,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
#[inline]
fn param_env(&self) -> ParamEnv<'db> {
- self.ctx.env.env
+ self.ctx.param_env
}
/// When we're looking up a method by path (UFCS), we relate the receiver
@@ -980,8 +980,8 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
};
InherentImpls::for_each_crate_and_block(
self.db(),
- module.krate(),
- module.containing_block(),
+ module.krate(self.db()),
+ module.block(self.db()),
&mut |impls| {
for &impl_def_id in impls.for_self_ty(self_ty) {
self.assemble_inherent_impl_probe(impl_def_id, receiver_steps);
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index f47e3b7a30..836c20a433 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -157,6 +157,7 @@ impl<'db, V: PartialEq> ProjectionElem<'db, V> {
pub fn projected_ty(
&self,
infcx: &InferCtxt<'db>,
+ env: ParamEnv<'db>,
mut base: Ty<'db>,
closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>,
krate: Crate,
@@ -173,8 +174,6 @@ impl<'db, V: PartialEq> ProjectionElem<'db, V> {
if matches!(base.kind(), TyKind::Alias(..)) {
let mut ocx = ObligationCtxt::new(infcx);
- // FIXME: we should get this from caller
- let env = ParamEnv::empty();
match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) {
Ok(it) => base = it,
Err(_) => return Ty::new_error(interner, ErrorGuaranteed),
@@ -977,15 +976,13 @@ pub enum Rvalue<'db> {
UnaryOp(UnOp, Operand<'db>),
/// Computes the discriminant of the place, returning it as an integer of type
- /// [`discriminant_ty`]. Returns zero for types without discriminant.
+ /// `discriminant_ty`. Returns zero for types without discriminant.
///
/// The validity requirements for the underlying value are undecided for this rvalue, see
/// [#91095]. Note too that the value of the discriminant is not the same thing as the
- /// variant index; use [`discriminant_for_variant`] to convert.
+ /// variant index; use `discriminant_for_variant` to convert.
///
- /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
- /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
Discriminant(Place<'db>),
/// Creates an aggregate value, like a tuple or struct.
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 2d2fc03dcc..b39c9bc065 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -12,12 +12,12 @@ use stdx::never;
use triomphe::Arc;
use crate::{
- InferenceResult, TraitEnvironment,
+ InferenceResult,
db::{HirDatabase, InternedClosure, InternedClosureId},
display::DisplayTarget,
mir::OperandKind,
next_solver::{
- DbInterner, GenericArgs, Ty, TypingMode,
+ DbInterner, GenericArgs, ParamEnv, Ty, TypingMode,
infer::{DbInternerInferExt, InferCtxt},
},
};
@@ -97,7 +97,7 @@ pub fn borrowck_query<'db>(
) -> Result<Arc<[BorrowckResult<'db>]>, MirLowerError<'db>> {
let _p = tracing::info_span!("borrowck_query").entered();
let module = def.module(db);
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
let env = db.trait_environment_for_body(def);
let mut res = vec![];
// This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`.
@@ -106,9 +106,9 @@ pub fn borrowck_query<'db>(
// FIXME(next-solver): Opaques.
let infcx = interner.infer_ctxt().build(typing_mode);
res.push(BorrowckResult {
- mutability_of_locals: mutability_of_locals(&infcx, &body),
- moved_out_of_ref: moved_out_of_ref(&infcx, &env, &body),
- partially_moved: partially_moved(&infcx, &env, &body),
+ mutability_of_locals: mutability_of_locals(&infcx, env, &body),
+ moved_out_of_ref: moved_out_of_ref(&infcx, env, &body),
+ partially_moved: partially_moved(&infcx, env, &body),
borrow_regions: borrow_regions(db, &body),
mir_body: body,
});
@@ -131,7 +131,7 @@ fn make_fetch_closure_field<'db>(
fn moved_out_of_ref<'db>(
infcx: &InferCtxt<'db>,
- env: &TraitEnvironment<'db>,
+ env: ParamEnv<'db>,
body: &MirBody<'db>,
) -> Vec<MovedOutOfRef<'db>> {
let db = infcx.interner.db;
@@ -146,13 +146,14 @@ fn moved_out_of_ref<'db>(
}
ty = proj.projected_ty(
infcx,
+ env,
ty,
make_fetch_closure_field(db),
- body.owner.module(db).krate(),
+ body.owner.module(db).krate(db),
);
}
if is_dereference_of_ref
- && !infcx.type_is_copy_modulo_regions(env.env, ty)
+ && !infcx.type_is_copy_modulo_regions(env, ty)
&& !ty.references_non_lt_error()
{
result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty });
@@ -231,7 +232,7 @@ fn moved_out_of_ref<'db>(
fn partially_moved<'db>(
infcx: &InferCtxt<'db>,
- env: &TraitEnvironment<'db>,
+ env: ParamEnv<'db>,
body: &MirBody<'db>,
) -> Vec<PartiallyMoved<'db>> {
let db = infcx.interner.db;
@@ -242,12 +243,13 @@ fn partially_moved<'db>(
for proj in p.projection.lookup(&body.projection_store) {
ty = proj.projected_ty(
infcx,
+ env,
ty,
make_fetch_closure_field(db),
- body.owner.module(db).krate(),
+ body.owner.module(db).krate(db),
);
}
- if !infcx.type_is_copy_modulo_regions(env.env, ty) && !ty.references_non_lt_error() {
+ if !infcx.type_is_copy_modulo_regions(env, ty) && !ty.references_non_lt_error() {
result.push(PartiallyMoved { span, ty, local: p.local });
}
}
@@ -374,6 +376,7 @@ enum ProjectionCase {
fn place_case<'db>(
infcx: &InferCtxt<'db>,
+ env: ParamEnv<'db>,
body: &MirBody<'db>,
lvalue: &Place<'db>,
) -> ProjectionCase {
@@ -395,9 +398,10 @@ fn place_case<'db>(
}
ty = proj.projected_ty(
infcx,
+ env,
ty,
make_fetch_closure_field(db),
- body.owner.module(db).krate(),
+ body.owner.module(db).krate(db),
);
}
if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct }
@@ -535,6 +539,7 @@ fn record_usage_for_operand<'db>(
fn mutability_of_locals<'db>(
infcx: &InferCtxt<'db>,
+ env: ParamEnv<'db>,
body: &MirBody<'db>,
) -> ArenaMap<LocalId<'db>, MutabilityReason> {
let db = infcx.interner.db;
@@ -547,7 +552,7 @@ fn mutability_of_locals<'db>(
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(place, value) => {
- match place_case(infcx, body, place) {
+ match place_case(infcx, env, body, place) {
ProjectionCase::Direct => {
if ever_init_map.get(place.local).copied().unwrap_or_default() {
push_mut_span(place.local, statement.span, &mut result);
@@ -596,7 +601,7 @@ fn mutability_of_locals<'db>(
},
p,
) = value
- && place_case(infcx, body, p) != ProjectionCase::Indirect
+ && place_case(infcx, env, body, p) != ProjectionCase::Indirect
{
push_mut_span(p.local, statement.span, &mut result);
}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 3418689027..3b4913cae3 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -34,7 +34,7 @@ use syntax::{SyntaxNodePtr, TextRange};
use triomphe::Arc;
use crate::{
- CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, TraitEnvironment,
+ CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, ParamEnvAndCrate,
consteval::{self, ConstEvalError, try_const_usize},
db::{HirDatabase, InternedClosure, InternedClosureId},
display::{ClosureStyle, DisplayTarget, HirDisplay},
@@ -165,7 +165,7 @@ enum MirOrDynIndex<'db> {
pub struct Evaluator<'db> {
db: &'db dyn HirDatabase,
- trait_env: Arc<TraitEnvironment<'db>>,
+ param_env: ParamEnvAndCrate<'db>,
target_data_layout: Arc<TargetDataLayout>,
stack: Vec<u8>,
heap: Vec<u8>,
@@ -594,7 +594,7 @@ pub fn interpret_mir<'db>(
// a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
// (and probably should) do better here, for example by excluding bindings outside of the target expression.
assert_placeholder_ty_is_unused: bool,
- trait_env: Option<Arc<TraitEnvironment<'db>>>,
+ trait_env: Option<ParamEnvAndCrate<'db>>,
) -> Result<'db, (Result<'db, Const<'db>>, MirOutput)> {
let ty = body.locals[return_slot()].ty;
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
@@ -632,10 +632,10 @@ impl<'db> Evaluator<'db> {
db: &'db dyn HirDatabase,
owner: DefWithBodyId,
assert_placeholder_ty_is_unused: bool,
- trait_env: Option<Arc<TraitEnvironment<'db>>>,
+ trait_env: Option<ParamEnvAndCrate<'db>>,
) -> Result<'db, Evaluator<'db>> {
let module = owner.module(db);
- let crate_id = module.krate();
+ let crate_id = module.krate(db);
let target_data_layout = match db.target_data_layout(crate_id) {
Ok(target_data_layout) => target_data_layout,
Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)),
@@ -654,7 +654,10 @@ impl<'db> Evaluator<'db> {
static_locations: Default::default(),
db,
random_state: oorandom::Rand64::new(0),
- trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)),
+ param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate {
+ param_env: db.trait_environment_for_body(owner),
+ krate: crate_id,
+ }),
crate_id,
stdout: vec![],
stderr: vec![],
@@ -719,6 +722,7 @@ impl<'db> Evaluator<'db> {
let (ty, proj) = pair;
let r = proj.projected_ty(
&self.infcx,
+ self.param_env.param_env,
ty,
|c, subst, f| {
let InternedClosure(def, _) = self.db.lookup_intern_closure(c);
@@ -864,7 +868,7 @@ impl<'db> Evaluator<'db> {
}
let r = self
.db
- .layout_of_ty(ty, self.trait_env.clone())
+ .layout_of_ty(ty, self.param_env)
.map_err(|e| MirEvalError::LayoutError(e, ty))?;
self.layout_cache.borrow_mut().insert(ty, r.clone());
Ok(r)
@@ -1927,18 +1931,17 @@ impl<'db> Evaluator<'db> {
let mut id = const_id.0;
let mut subst = subst;
if let hir_def::GeneralConstId::ConstId(c) = id {
- let (c, s) = lookup_impl_const(&self.infcx, self.trait_env.clone(), c, subst);
+ let (c, s) = lookup_impl_const(&self.infcx, self.param_env.param_env, c, subst);
id = hir_def::GeneralConstId::ConstId(c);
subst = s;
}
result_owner = match id {
- GeneralConstId::ConstId(const_id) => self
- .db
- .const_eval(const_id, subst, Some(self.trait_env.clone()))
- .map_err(|e| {
+ GeneralConstId::ConstId(const_id) => {
+ self.db.const_eval(const_id, subst, Some(self.param_env)).map_err(|e| {
let name = id.name(self.db);
MirEvalError::ConstEvalError(name, Box::new(e))
- })?,
+ })?
+ }
GeneralConstId::StaticId(static_id) => {
self.db.const_eval_static(static_id).map_err(|e| {
let name = id.name(self.db);
@@ -2331,7 +2334,7 @@ impl<'db> Evaluator<'db> {
let ty = ocx
.structurally_normalize_ty(
&ObligationCause::dummy(),
- this.trait_env.env,
+ this.param_env.param_env,
ty,
)
.map_err(|_| MirEvalError::NotSupported("couldn't normalize".to_owned()))?;
@@ -2510,7 +2513,7 @@ impl<'db> Evaluator<'db> {
) -> Result<'db, Option<StackFrame<'db>>> {
let mir_body = self
.db
- .monomorphized_mir_body_for_closure(closure, generic_args, self.trait_env.clone())
+ .monomorphized_mir_body_for_closure(closure, generic_args, self.param_env)
.map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?;
let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some()
{
@@ -2606,16 +2609,19 @@ impl<'db> Evaluator<'db> {
}
let (def, generic_args) = pair;
let r = if let Some(self_ty_idx) =
- is_dyn_method(self.interner(), self.trait_env.clone(), def, generic_args)
+ is_dyn_method(self.interner(), self.param_env.param_env, def, generic_args)
{
MirOrDynIndex::Dyn(self_ty_idx)
} else {
- let (imp, generic_args) =
- self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args);
+ let (imp, generic_args) = self.db.lookup_impl_method(
+ ParamEnvAndCrate { param_env: self.param_env.param_env, krate: self.crate_id },
+ def,
+ generic_args,
+ );
let mir_body = self
.db
- .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone())
+ .monomorphized_mir_body(imp.into(), generic_args, self.param_env)
.map_err(|e| {
MirEvalError::InFunction(
Box::new(MirEvalError::MirLowerError(imp, e)),
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 591c12ec24..42c11113ee 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -840,7 +840,7 @@ impl<'db> Evaluator<'db> {
"size_of generic arg is not provided".into(),
));
};
- let result = match has_drop_glue(&self.infcx, ty, self.trait_env.clone()) {
+ let result = match has_drop_glue(&self.infcx, ty, self.param_env.param_env) {
DropGlue::HasDropGlue => true,
DropGlue::None => false,
DropGlue::DependOnParams => {
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index bb2afb2f00..c13b76c125 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -1,4 +1,4 @@
-use hir_def::db::DefDatabase;
+use hir_def::{HasModule, db::DefDatabase};
use hir_expand::EditionedFileId;
use span::Edition;
use syntax::{TextRange, TextSize};
@@ -20,7 +20,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
let interner = DbInterner::new_no_crate(db);
let module_id = db.module_for_file(file_id.file_id(db));
let def_map = module_id.def_map(db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
let func_id = scope
.declarations()
.find_map(|x| match x {
@@ -40,7 +40,10 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
.monomorphized_mir_body(
func_id.into(),
GenericArgs::new_from_iter(interner, []),
- db.trait_environment(func_id.into()),
+ crate::ParamEnvAndCrate {
+ param_env: db.trait_environment(func_id.into()),
+ krate: func_id.krate(db),
+ },
)
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
@@ -87,7 +90,7 @@ fn check_pass_and_stdio(
line_index(range.end())
)
};
- let krate = db.module_for_file(file_id.file_id(&db)).krate();
+ let krate = db.module_for_file(file_id.file_id(&db)).krate(&db);
e.pretty_print(
&mut err,
&db,
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 190b2f99cc..5bce4222a4 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -25,7 +25,7 @@ use syntax::TextRange;
use triomphe::Arc;
use crate::{
- Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment,
+ Adjust, Adjustment, AutoBorrow, CallableDefId, ParamEnvAndCrate,
consteval::ConstEvalError,
db::{HirDatabase, InternedClosure, InternedClosureId},
display::{DisplayTarget, HirDisplay, hir_display_with_store},
@@ -42,7 +42,7 @@ use crate::{
TupleFieldId, Ty, UnOp, VariantId, return_slot,
},
next_solver::{
- Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst,
+ Const, DbInterner, ParamConst, ParamEnv, Region, TyKind, TypingMode, UnevaluatedConst,
infer::{DbInternerInferExt, InferCtxt},
},
traits::FnTrait,
@@ -81,7 +81,7 @@ struct MirLowerCtx<'a, 'db> {
infer: &'a InferenceResult<'db>,
resolver: Resolver<'db>,
drop_scopes: Vec<DropScope<'db>>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
infcx: InferCtxt<'db>,
}
@@ -302,7 +302,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
};
let resolver = owner.resolver(db);
let env = db.trait_environment_for_body(owner);
- let interner = DbInterner::new_with(db, env.krate);
+ let interner = DbInterner::new_with(db, resolver.krate());
// FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body?
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -1462,7 +1462,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
}
fn lower_literal_to_operand(&mut self, ty: Ty<'db>, l: &Literal) -> Result<'db, Operand<'db>> {
- let size = || self.db.layout_of_ty(ty, self.env.clone()).map(|it| it.size.bytes_usize());
+ let size = || {
+ self.db
+ .layout_of_ty(ty, ParamEnvAndCrate { param_env: self.env, krate: self.krate() })
+ .map(|it| it.size.bytes_usize())
+ };
const USIZE_SIZE: usize = size_of::<usize>();
let bytes: Box<[_]> = match l {
hir_def::hir::Literal::String(b) => {
@@ -1799,7 +1803,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
&self.infcx,
self.infer[expr_id],
self.owner.module(self.db),
- self.env.clone(),
+ self.env,
)
}
@@ -2070,7 +2074,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
span: MirSpan,
) {
for &l in scope.locals.iter().rev() {
- if !self.infcx.type_is_copy_modulo_regions(self.env.env, self.result.locals[l].ty) {
+ if !self.infcx.type_is_copy_modulo_regions(self.env, self.result.locals[l].ty) {
let prev = std::mem::replace(current, self.new_basic_block());
self.set_terminator(
prev,
diff --git a/crates/hir-ty/src/mir/lower/tests.rs b/crates/hir-ty/src/mir/lower/tests.rs
index 38fc7ad78a..73399dab7f 100644
--- a/crates/hir-ty/src/mir/lower/tests.rs
+++ b/crates/hir-ty/src/mir/lower/tests.rs
@@ -1,3 +1,4 @@
+use hir_def::DefWithBodyId;
use test_fixture::WithFixture;
use crate::{db::HirDatabase, setup_tracing, test_db::TestDB};
@@ -9,7 +10,7 @@ fn lower_mir(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let file_id = *file_ids.last().unwrap();
let module_id = db.module_for_file(file_id.file_id(&db));
let def_map = module_id.def_map(&db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
let funcs = scope.declarations().filter_map(|x| match x {
hir_def::ModuleDefId::FunctionId(it) => Some(it),
_ => None,
@@ -49,3 +50,61 @@ fn foo() {
"#,
);
}
+
+fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+ let _tracing = setup_tracing();
+ let (db, file_ids) = TestDB::with_many_files(ra_fixture);
+ crate::attach_db(&db, || {
+ let file_id = *file_ids.last().unwrap();
+ let module_id = db.module_for_file(file_id.file_id(&db));
+ let def_map = module_id.def_map(&db);
+ let scope = &def_map[module_id].scope;
+
+ let mut bodies: Vec<DefWithBodyId> = Vec::new();
+
+ for decl in scope.declarations() {
+ if let hir_def::ModuleDefId::FunctionId(f) = decl {
+ bodies.push(f.into());
+ }
+ }
+
+ for impl_id in scope.impls() {
+ let impl_items = impl_id.impl_items(&db);
+ for (_, item) in impl_items.items.iter() {
+ if let hir_def::AssocItemId::FunctionId(f) = item {
+ bodies.push((*f).into());
+ }
+ }
+ }
+
+ for body in bodies {
+ let _ = db.borrowck(body);
+ }
+ })
+}
+
+#[test]
+fn regression_21173_const_generic_impl_with_assoc_type() {
+ check_borrowck(
+ r#"
+pub trait Tr {
+ type Assoc;
+ fn f(&self, handle: Self::Assoc) -> i32;
+}
+
+pub struct ConstGeneric<const N: usize>;
+
+impl<const N: usize> Tr for &ConstGeneric<N> {
+ type Assoc = AssocTy;
+
+ fn f(&self, a: Self::Assoc) -> i32 {
+ a.x
+ }
+}
+
+pub struct AssocTy {
+ x: i32,
+}
+ "#,
+ );
+}
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index 1f73d5cd31..b67365c344 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -14,9 +14,11 @@ use rustc_type_ir::{
};
use triomphe::Arc;
-use crate::next_solver::{Const, ConstKind, Region, RegionKind};
use crate::{
- TraitEnvironment,
+ ParamEnvAndCrate,
+ next_solver::{Const, ConstKind, Region, RegionKind},
+};
+use crate::{
db::{HirDatabase, InternedClosureId},
next_solver::{
DbInterner, GenericArgs, Ty, TyKind, TypingMode,
@@ -30,7 +32,7 @@ use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind,
struct Filler<'db> {
infcx: InferCtxt<'db>,
- trait_env: Arc<TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
subst: GenericArgs<'db>,
}
@@ -53,7 +55,11 @@ impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> {
let mut ocx = ObligationCtxt::new(&self.infcx);
let ty = ocx
- .structurally_normalize_ty(&ObligationCause::dummy(), self.trait_env.env, ty)
+ .structurally_normalize_ty(
+ &ObligationCause::dummy(),
+ self.trait_env.param_env,
+ ty,
+ )
.map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?;
ty.try_super_fold_with(self)
}
@@ -93,11 +99,7 @@ impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> {
}
impl<'db> Filler<'db> {
- fn new(
- db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
- subst: GenericArgs<'db>,
- ) -> Self {
+ fn new(db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, subst: GenericArgs<'db>) -> Self {
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
Self { infcx, trait_env: env, subst }
@@ -210,7 +212,7 @@ pub fn monomorphized_mir_body_query<'db>(
db: &'db dyn HirDatabase,
owner: DefWithBodyId,
subst: GenericArgs<'db>,
- trait_env: Arc<crate::TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
let mut filler = Filler::new(db, trait_env, subst);
let body = db.mir_body(owner)?;
@@ -223,7 +225,7 @@ pub(crate) fn monomorphized_mir_body_cycle_result<'db>(
_db: &'db dyn HirDatabase,
_: DefWithBodyId,
_: GenericArgs<'db>,
- _: Arc<crate::TraitEnvironment<'db>>,
+ _: ParamEnvAndCrate<'db>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
Err(MirLowerError::Loop)
}
@@ -232,7 +234,7 @@ pub fn monomorphized_mir_body_for_closure_query<'db>(
db: &'db dyn HirDatabase,
closure: InternedClosureId,
subst: GenericArgs<'db>,
- trait_env: Arc<crate::TraitEnvironment<'db>>,
+ trait_env: ParamEnvAndCrate<'db>,
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
let mut filler = Filler::new(db, trait_env, subst);
let body = db.mir_body_for_closure(closure)?;
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 443191423a..14b8a61088 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -402,7 +402,7 @@ impl<'db> InferCtxt<'db> {
self.evaluate_obligation(obligation).may_apply()
}
- /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
+ /// See the comment on `GeneralAutoderef::overloaded_deref_ty`
/// for more details.
pub fn predicate_may_hold_opaque_types_jank(
&self,
@@ -532,7 +532,7 @@ impl<'db> InferCtxt<'db> {
})
}
- /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
+ /// See the comment on `GeneralAutoderef::overloaded_deref_ty`
/// for more details.
pub fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'db, Predicate<'db>>) -> bool {
<&SolverContext<'db>>::from(self).root_goal_may_hold_opaque_types_jank(goal)
diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs
index 4f000c24cc..3409de17a1 100644
--- a/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -36,10 +36,6 @@ pub struct ObligationCause {
}
impl ObligationCause {
- #[expect(
- clippy::new_without_default,
- reason = "`new` is temporary, eventually we will provide span etc. here"
- )]
#[inline]
pub fn new() -> ObligationCause {
ObligationCause { _private: () }
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 2e52dcea6c..8b24a20a5b 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -690,15 +690,10 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
interner: DbInterner<'db>,
sizedness: SizedTraitKind,
) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> {
- if self.is_struct() {
- let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?;
-
- let constraint_ty = sizedness_constraint_for_ty(interner, sizedness, tail_ty)?;
-
- Some(EarlyBinder::bind(constraint_ty))
- } else {
- None
- }
+ let tail_ty = self.struct_tail_ty(interner)?;
+ tail_ty
+ .map_bound(|tail_ty| sizedness_constraint_for_ty(interner, sizedness, tail_ty))
+ .transpose()
}
fn destructor(
@@ -1109,14 +1104,7 @@ impl<'db> Interner for DbInterner<'db> {
fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> {
match def_id {
- SolverDefId::TypeAliasId(id) => {
- use hir_def::Lookup;
- match id.lookup(self.db()).container {
- ItemContainerId::ImplId(it) => it,
- _ => panic!("assoc ty value should be in impl"),
- };
- self.db().ty(id.into())
- }
+ SolverDefId::TypeAliasId(id) => self.db().ty(id.into()),
SolverDefId::AdtId(id) => self.db().ty(id.into()),
// FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc.
//
@@ -1694,7 +1682,7 @@ impl<'db> Interner for DbInterner<'db> {
mut f: impl FnMut(Self::ImplId),
) {
let krate = self.krate.expect("trait solving requires setting `DbInterner::krate`");
- let trait_block = trait_def_id.0.loc(self.db).container.containing_block();
+ let trait_block = trait_def_id.0.loc(self.db).container.block(self.db);
let mut consider_impls_for_simplified_type = |simp: SimplifiedType| {
let type_block = simp.def().and_then(|def_id| {
let module = match def_id {
@@ -1713,7 +1701,7 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::EnumVariantId(_)
| SolverDefId::Ctor(_) => return None,
};
- module.containing_block()
+ module.block(self.db)
});
TraitImpls::for_each_crate_and_block_trait_and_type(
self.db,
@@ -1828,7 +1816,7 @@ impl<'db> Interner for DbInterner<'db> {
fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, mut f: impl FnMut(Self::ImplId)) {
let Some(krate) = self.krate else { return };
- let block = trait_def_id.0.loc(self.db).container.containing_block();
+ let block = trait_def_id.0.loc(self.db).container.block(self.db);
TraitImpls::for_each_crate_and_block(self.db, krate, block, &mut |impls| {
for &impl_ in impls.blanket_impls(trait_def_id.0) {
diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs
index 7cc3af748a..783966ee1e 100644
--- a/crates/hir-ty/src/next_solver/predicate.rs
+++ b/crates/hir-ty/src/next_solver/predicate.rs
@@ -427,6 +427,10 @@ impl<'db> ParamEnv<'db> {
pub fn empty() -> Self {
ParamEnv { clauses: Clauses::new_from_iter(DbInterner::conjure(), []) }
}
+
+ pub fn clauses(self) -> Clauses<'db> {
+ self.clauses
+ }
}
impl<'db> rustc_type_ir::inherent::ParamEnv<DbInterner<'db>> for ParamEnv<'db> {
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index b5ed770e16..40a3f17cf1 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -177,45 +177,52 @@ impl<'db> SolverDelegate for SolverContext<'db> {
impl_id: ImplIdWrapper,
) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
let impl_items = impl_id.0.impl_items(self.0.interner.db());
- let id = match trait_assoc_def_id {
- SolverDefId::TypeAliasId(trait_assoc_id) => {
- let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
- impl_items
- .items
- .iter()
- .find_map(|(impl_assoc_name, impl_assoc_id)| {
- if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
- && *impl_assoc_name == trait_assoc_data.name
- {
- Some(impl_assoc_id)
- } else {
- None
- }
- })
- .map(SolverDefId::TypeAliasId)
- }
- SolverDefId::ConstId(trait_assoc_id) => {
- let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
- let trait_assoc_name = trait_assoc_data
- .name
- .as_ref()
- .expect("unnamed consts should not get passed to the solver");
- impl_items
- .items
- .iter()
- .find_map(|(impl_assoc_name, impl_assoc_id)| {
- if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
- && impl_assoc_name == trait_assoc_name
- {
- Some(impl_assoc_id)
- } else {
- None
- }
- })
- .map(SolverDefId::ConstId)
- }
- _ => panic!("Unexpected SolverDefId"),
- };
+ let id =
+ match trait_assoc_def_id {
+ SolverDefId::TypeAliasId(trait_assoc_id) => {
+ let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
+ impl_items
+ .items
+ .iter()
+ .find_map(|(impl_assoc_name, impl_assoc_id)| {
+ if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
+ && *impl_assoc_name == trait_assoc_data.name
+ {
+ Some(impl_assoc_id)
+ } else {
+ None
+ }
+ })
+ .or_else(|| {
+ if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None }
+ })
+ .map(SolverDefId::TypeAliasId)
+ }
+ SolverDefId::ConstId(trait_assoc_id) => {
+ let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
+ let trait_assoc_name = trait_assoc_data
+ .name
+ .as_ref()
+ .expect("unnamed consts should not get passed to the solver");
+ impl_items
+ .items
+ .iter()
+ .find_map(|(impl_assoc_name, impl_assoc_id)| {
+ if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
+ && impl_assoc_name == trait_assoc_name
+ {
+ Some(impl_assoc_id)
+ } else {
+ None
+ }
+ })
+ .or_else(|| {
+ if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None }
+ })
+ .map(SolverDefId::ConstId)
+ }
+ _ => panic!("Unexpected SolverDefId"),
+ };
Ok(id)
}
@@ -225,7 +232,9 @@ impl<'db> SolverDelegate for SolverContext<'db> {
_src: Ty<'db>,
_assume: <Self::Interner as rustc_type_ir::Interner>::Const,
) -> Result<Certainty, NoSolution> {
- unimplemented!()
+ // It's better to return some value while not fully implement
+ // then panic in the mean time
+ Ok(Certainty::Yes)
}
fn evaluate_const(
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index c0a7c9adc4..ff89f8e059 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -656,7 +656,7 @@ impl<'db> Ty<'db> {
}
TyKind::Coroutine(coroutine_id, _args) => {
let InternedCoroutine(owner, _) = coroutine_id.0.loc(db);
- let krate = owner.module(db).krate();
+ let krate = owner.module(db).krate(db);
if let Some(future_trait) = hir_def::lang_item::lang_items(db, krate).Future {
// This is only used by type walking.
// Parameters will be walked outside, and projection predicate is not used.
diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs
index 972c8e2da7..bc4b5fdbfc 100644
--- a/crates/hir-ty/src/next_solver/util.rs
+++ b/crates/hir-ty/src/next_solver/util.rs
@@ -422,12 +422,10 @@ pub fn sizedness_constraint_for_ty<'db>(
.next_back()
.and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)),
- Adt(adt, args) => {
- let tail_ty =
- EarlyBinder::bind(adt.all_field_tys(interner).skip_binder().into_iter().last()?)
- .instantiate(interner, args);
+ Adt(adt, args) => adt.struct_tail_ty(interner).and_then(|tail_ty| {
+ let tail_ty = tail_ty.instantiate(interner, args);
sizedness_constraint_for_ty(interner, sizedness, tail_ty)
- }
+ }),
Placeholder(..) | Bound(..) | Infer(..) => {
panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty")
diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs
index 0b84ce13a3..4c6b585016 100644
--- a/crates/hir-ty/src/opaques.rs
+++ b/crates/hir-ty/src/opaques.rs
@@ -118,11 +118,11 @@ pub(crate) fn tait_hidden_types<'db>(
let loc = type_alias.loc(db);
let module = loc.module(db);
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
let mut ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy();
- let param_env = db.trait_environment(type_alias.into()).env;
+ let param_env = db.trait_environment(type_alias.into());
let defining_bodies = tait_defining_bodies(db, &loc);
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
index 0241751e82..9ae9a8e2a9 100644
--- a/crates/hir-ty/src/specialization.rs
+++ b/crates/hir-ty/src/specialization.rs
@@ -1,6 +1,6 @@
//! Impl specialization related things
-use hir_def::{ImplId, nameres::crate_def_map};
+use hir_def::{HasModule, ImplId, nameres::crate_def_map};
use intern::sym;
use rustc_type_ir::inherent::SliceLike;
use tracing::debug;
@@ -46,7 +46,7 @@ fn specializes_query(
parent_impl_def_id: ImplId,
) -> bool {
let trait_env = db.trait_environment(specializing_impl_def_id.into());
- let interner = DbInterner::new_with(db, trait_env.krate);
+ let interner = DbInterner::new_with(db, specializing_impl_def_id.krate(db));
let specializing_impl_signature = db.impl_signature(specializing_impl_def_id);
let parent_impl_signature = db.impl_signature(parent_impl_def_id);
@@ -70,7 +70,7 @@ fn specializes_query(
// create a parameter environment corresponding to an identity instantiation of the specializing impl,
// i.e. the most generic instantiation of the specializing impl.
- let param_env = trait_env.env;
+ let param_env = trait_env;
// Create an infcx, taking the predicates of the specializing impl as assumptions:
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -148,7 +148,7 @@ pub(crate) fn specializes(
// `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]`
// is an internal feature, std is not using it for specialization nor is likely to
// ever use it, and we don't have the span information necessary to replicate that.
- let def_map = crate_def_map(db, module.krate());
+ let def_map = crate_def_map(db, module.krate(db));
if !def_map.is_unstable_feature_enabled(&sym::specialization)
&& !def_map.is_unstable_feature_enabled(&sym::min_specialization)
{
diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs
index 7044ca5d23..7bd314cb8e 100644
--- a/crates/hir-ty/src/test_db.rs
+++ b/crates/hir-ty/src/test_db.rs
@@ -138,9 +138,9 @@ impl TestDB {
let file_id = file_id.into();
for &krate in self.relevant_crates(file_id).iter() {
let crate_def_map = crate_def_map(self, krate);
- for (local_id, data) in crate_def_map.modules() {
+ for (module_id, data) in crate_def_map.modules() {
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
- return Some(crate_def_map.module_id(local_id));
+ return Some(module_id);
}
}
}
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index 1acb0b82b1..a31353f1e3 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -16,7 +16,7 @@ mod traits;
use base_db::{Crate, SourceDatabase};
use expect_test::Expect;
use hir_def::{
- AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax,
+ AssocItemId, DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, SyntheticSyntax,
db::DefDatabase,
expr_store::{Body, BodySourceMap},
hir::{ExprId, Pat, PatId},
@@ -114,7 +114,7 @@ fn check_impl(
None => continue,
};
let def_map = module.def_map(&db);
- visit_module(&db, def_map, module.local_id, &mut |it| {
+ visit_module(&db, def_map, module, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -122,7 +122,7 @@ fn check_impl(
ModuleDefId::StaticId(it) => it.into(),
_ => return,
};
- defs.push((def, module.krate()))
+ defs.push((def, module.krate(&db)))
});
}
defs.sort_by_key(|(def, _)| match def {
@@ -412,7 +412,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let def_map = module.def_map(&db);
let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
- visit_module(&db, def_map, module.local_id, &mut |it| {
+ visit_module(&db, def_map, module, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -420,7 +420,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
ModuleDefId::StaticId(it) => it.into(),
_ => return,
};
- defs.push((def, module.krate()))
+ defs.push((def, module.krate(&db)))
});
defs.sort_by_key(|(def, _)| match def {
DefWithBodyId::FunctionId(it) => {
@@ -454,7 +454,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
pub(crate) fn visit_module(
db: &TestDB,
crate_def_map: &DefMap,
- module_id: LocalModuleId,
+ module_id: ModuleId,
cb: &mut dyn FnMut(ModuleDefId),
) {
visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
@@ -517,7 +517,7 @@ pub(crate) fn visit_module(
}
}
}
- ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it.local_id, cb),
+ ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it, cb),
_ => (),
}
}
@@ -593,7 +593,7 @@ fn salsa_bug() {
crate::attach_db(&db, || {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
InferenceResult::for_body(
&db,
match def {
@@ -637,7 +637,7 @@ fn salsa_bug() {
crate::attach_db(&db, || {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
InferenceResult::for_body(
&db,
match def {
diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs
index ef71681636..ff55ff54ce 100644
--- a/crates/hir-ty/src/tests/closure_captures.rs
+++ b/crates/hir-ty/src/tests/closure_captures.rs
@@ -24,7 +24,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
let def_map = module.def_map(&db);
let mut defs = Vec::new();
- visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it));
+ visit_module(&db, def_map, module, &mut |it| defs.push(it));
let mut captures_info = Vec::new();
for def in defs {
@@ -75,7 +75,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
let capture_ty = capture
.ty
.skip_binder()
- .display_test(db, DisplayTarget::from_crate(db, module.krate()))
+ .display_test(db, DisplayTarget::from_crate(db, module.krate(db)))
.to_string();
let spans = capture
.spans()
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index fd564a300d..7b0c1d3544 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -22,7 +22,7 @@ fn foo() -> i32 {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
InferenceResult::for_body(&db, it.into());
}
@@ -66,7 +66,7 @@ fn foo() -> i32 {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
InferenceResult::for_body(&db, it.into());
}
@@ -109,7 +109,7 @@ fn baz() -> i32 {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
InferenceResult::for_body(&db, it.into());
}
@@ -178,7 +178,7 @@ fn baz() -> i32 {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
InferenceResult::for_body(&db, it.into());
}
@@ -232,7 +232,7 @@ $0",
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -268,7 +268,7 @@ pub struct NewStruct {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -303,7 +303,7 @@ $0",
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -340,7 +340,7 @@ pub enum SomeEnum {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -375,7 +375,7 @@ $0",
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -409,7 +409,7 @@ fn bar() -> f32 {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -448,7 +448,7 @@ $0",
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -490,7 +490,7 @@ impl SomeStruct {
|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let _crate_def_map = module.def_map(&db);
- TraitImpls::for_crate(&db, module.krate());
+ TraitImpls::for_crate(&db, module.krate(&db));
},
&[("TraitImpls::for_crate_", 1)],
expect_test::expect![[r#"
@@ -546,7 +546,7 @@ fn main() {
let module = db.module_for_file(file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
let mut defs: Vec<DefWithBodyId> = vec![];
- visit_module(&db, crate_def_map, module.local_id, &mut |it| {
+ visit_module(&db, crate_def_map, module, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -643,7 +643,7 @@ fn main() {
let crate_def_map = module.def_map(&db);
let mut defs: Vec<DefWithBodyId> = vec![];
- visit_module(&db, crate_def_map, module.local_id, &mut |it| {
+ visit_module(&db, crate_def_map, module, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 274d33a211..c8ed8aa258 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -2229,3 +2229,32 @@ fn test(x: *mut u8) {
"#,
);
}
+
+#[test]
+fn unsized_struct() {
+ check_types(
+ r#"
+//- minicore: sized, phantom_data
+use core::marker::PhantomData;
+
+const UI_DEV_CREATE: Ioctl = Ioctl(PhantomData);
+
+struct Ioctl<T: ?Sized = NoArgs>(PhantomData<T>);
+
+struct NoArgs([u8]);
+
+impl<T> Ioctl<T> {
+ fn ioctl(self) {}
+}
+
+impl Ioctl<NoArgs> {
+ fn ioctl(self) -> u32 { 0 }
+}
+
+fn main() {
+ UI_DEV_CREATE.ioctl();
+ // ^^^^^^^^^^^^^^^^^^^^^ u32
+}
+ "#,
+ );
+}
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index 5c1f85cb2a..e11cc85e7f 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -230,6 +230,62 @@ fn main() {
debug(&1);
}"#,
);
+
+ // toolchains <= 1.88.0, before sized-hierarchy.
+ check_no_mismatches(
+ r#"
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T: ?Sized> {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+
+trait Foo {
+ fn bar(&self) -> u32 {
+ 0xCAFE
+ }
+}
+
+fn debug(_: &dyn Foo) {}
+
+impl Foo for i32 {}
+
+fn main() {
+ debug(&1);
+}"#,
+ );
}
#[test]
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 677e35775d..a54c0a799d 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -5079,3 +5079,23 @@ fn foo(base_layer_two: &dyn BaseLayerOne) {
"#,
);
}
+
+#[test]
+fn default_assoc_types() {
+ check_types(
+ r#"
+trait Trait<T> {
+ type Assoc<U> = (T, U);
+ fn method(self) -> Self::Assoc<i32> { loop {} }
+}
+
+struct Struct<T>(T);
+impl<T> Trait<((), T)> for Struct<T> {}
+
+fn foo(v: Struct<f32>) {
+ v.method();
+ // ^^^^^^^^^^ (((), f32), i32)
+}
+ "#,
+ );
+}
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 1462f1e317..2f8c31ec60 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -4,7 +4,7 @@ use std::hash::Hash;
use base_db::Crate;
use hir_def::{
- AdtId, AssocItemId, BlockId, HasModule, ImplId, Lookup, TraitId,
+ AdtId, AssocItemId, HasModule, ImplId, Lookup, TraitId,
lang_item::LangItems,
nameres::DefMap,
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
@@ -17,7 +17,6 @@ use rustc_type_ir::{
inherent::{AdtDef, BoundExistentialPredicates, IntoKind, Span as _},
solve::Certainty,
};
-use triomphe::Arc;
use crate::{
db::HirDatabase,
@@ -29,60 +28,22 @@ use crate::{
},
};
-/// A set of clauses that we assume to be true. E.g. if we are inside this function:
-/// ```rust
-/// fn foo<T: Default>(t: T) {}
-/// ```
-/// we assume that `T: Default`.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TraitEnvironment<'db> {
+/// Type for `hir`, because commonly we want both param env and a crate in an exported API.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ParamEnvAndCrate<'db> {
+ pub param_env: ParamEnv<'db>,
pub krate: Crate,
- pub block: Option<BlockId>,
- // FIXME make this a BTreeMap
- traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
- pub env: ParamEnv<'db>,
-}
-
-impl<'db> TraitEnvironment<'db> {
- pub fn empty(krate: Crate) -> Arc<Self> {
- Arc::new(TraitEnvironment {
- krate,
- block: None,
- traits_from_clauses: Box::default(),
- env: ParamEnv::empty(),
- })
- }
-
- pub fn new(
- krate: Crate,
- block: Option<BlockId>,
- traits_from_clauses: Box<[(Ty<'db>, TraitId)]>,
- env: ParamEnv<'db>,
- ) -> Arc<Self> {
- Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
- }
-
- // pub fn with_block(self: &mut Arc<Self>, block: BlockId) {
- pub fn with_block(this: &mut Arc<Self>, block: BlockId) {
- Arc::make_mut(this).block = Some(block);
- }
-
- pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator<Item = TraitId> + '_ {
- self.traits_from_clauses
- .iter()
- .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id))
- }
}
/// This should be used in `hir` only.
pub fn structurally_normalize_ty<'db>(
infcx: &InferCtxt<'db>,
ty: Ty<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnv<'db>,
) -> Ty<'db> {
let TyKind::Alias(..) = ty.kind() else { return ty };
let mut ocx = ObligationCtxt::new(infcx);
- let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty);
+ let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, ty).unwrap_or(ty);
ty.replace_infer_with_error(infcx.interner)
}
@@ -192,7 +153,7 @@ impl FnTrait {
pub fn implements_trait_unique<'db>(
ty: Ty<'db>,
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
trait_: TraitId,
) -> bool {
implements_trait_unique_impl(db, env, trait_, &mut |infcx| {
@@ -203,7 +164,7 @@ pub fn implements_trait_unique<'db>(
/// This should not be used in `hir-ty`, only in `hir`.
pub fn implements_trait_unique_with_args<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
trait_: TraitId,
args: GenericArgs<'db>,
) -> bool {
@@ -212,7 +173,7 @@ pub fn implements_trait_unique_with_args<'db>(
fn implements_trait_unique_impl<'db>(
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
trait_: TraitId,
create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>,
) -> bool {
@@ -222,7 +183,7 @@ fn implements_trait_unique_impl<'db>(
let args = create_args(&infcx);
let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args);
- let goal = Goal::new(interner, env.env, trait_ref);
+ let goal = Goal::new(interner, env.param_env, trait_ref);
let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal);
matches!(result, Ok((_, Certainty::Yes)))
@@ -246,10 +207,10 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id
| TyKind::Uint(_)
| TyKind::Float(_) => def_map.is_rustc_coherence_is_core(),
- TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate() == def_map.krate(),
+ TyKind::Adt(adt_def, _) => adt_def.def_id().0.module(db).krate(db) == def_map.krate(),
TyKind::Dynamic(it, _) => it
.principal_def_id()
- .is_some_and(|trait_id| trait_id.0.module(db).krate() == def_map.krate()),
+ .is_some_and(|trait_id| trait_id.0.module(db).krate(db) == def_map.krate()),
_ => true,
};
@@ -322,12 +283,12 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool
return true;
};
- let local_crate = impl_.lookup(db).container.krate();
+ let local_crate = impl_.lookup(db).container.krate(db);
let is_local = |tgt_crate| tgt_crate == local_crate;
let trait_ref = impl_trait.instantiate_identity();
let trait_id = trait_ref.def_id.0;
- if is_local(trait_id.module(db).krate()) {
+ if is_local(trait_id.module(db).krate(db)) {
// trait to be implemented is local
return true;
}
@@ -361,10 +322,10 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool
// FIXME: param coverage
// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
let is_not_orphan = trait_ref.args.types().any(|ty| match unwrap_fundamental(ty).kind() {
- TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate()),
+ TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().0.module(db).krate(db)),
TyKind::Error(_) => true,
TyKind::Dynamic(it, _) => {
- it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate()))
+ it.principal_def_id().is_some_and(|trait_id| is_local(trait_id.0.module(db).krate(db)))
}
_ => false,
});
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index df9d53f3e5..5c0af6dafb 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -874,7 +874,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
let mut defs: Vec<GenericDefId> = Vec::new();
let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap();
let def_map = module.def_map(&db);
- crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| {
+ crate::tests::visit_module(&db, def_map, module, &mut |it| {
defs.push(match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::AdtId(it) => it.into(),
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 5e716c6df1..d1056f31e1 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -3,8 +3,7 @@
use cfg::CfgExpr;
use either::Either;
use hir_def::{
- AssocItemId, AttrDefId, FieldId, InternedModuleId, LifetimeParamId, ModuleDefId,
- TypeOrConstParamId,
+ AssocItemId, AttrDefId, FieldId, LifetimeParamId, ModuleDefId, TypeOrConstParamId,
attrs::{AttrFlags, Docs, IsInnerDoc},
expr_store::path::Path,
item_scope::ItemInNs,
@@ -213,8 +212,8 @@ impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];
impl HasAttrs for Module {
#[inline]
- fn attr_id(self, db: &dyn HirDatabase) -> AttrsOwner {
- AttrsOwner::AttrDef(AttrDefId::ModuleId(InternedModuleId::new(db, self.id)))
+ fn attr_id(self, _: &dyn HirDatabase) -> AttrsOwner {
+ AttrsOwner::AttrDef(AttrDefId::ModuleId(self.id))
}
}
@@ -243,7 +242,7 @@ impl HasAttrs for AssocItem {
impl HasAttrs for crate::Crate {
#[inline]
fn attr_id(self, db: &dyn HirDatabase) -> AttrsOwner {
- self.root_module().attr_id(db)
+ self.root_module(db).attr_id(db)
}
}
@@ -274,7 +273,6 @@ fn resolve_doc_path_on_(
) -> Option<DocLinkDef> {
let resolver = match attr_id {
AttrsOwner::AttrDef(AttrDefId::ModuleId(it)) => {
- let it = it.loc(db);
if is_inner_doc.yes() {
it.resolver(db)
} else if let Some(parent) = Module::from(it).parent(db) {
@@ -412,9 +410,7 @@ fn resolve_impl_trait_item<'db>(
ns: Option<Namespace>,
) -> Option<DocLinkDef> {
let krate = ty.krate(db);
- let environment = resolver
- .generic_def()
- .map_or_else(|| crate::TraitEnvironment::empty(krate.id), |d| db.trait_environment(d));
+ let environment = crate::param_env_from_resolver(db, &resolver);
let traits_in_scope = resolver.traits_in_scope(db);
// `ty.iterate_path_candidates()` require a scope, which is not available when resolving
@@ -428,7 +424,7 @@ fn resolve_impl_trait_item<'db>(
let ctx = MethodResolutionContext {
infcx: &infcx,
resolver: &resolver,
- env: &environment,
+ param_env: environment.param_env,
traits_in_scope: &traits_in_scope,
edition: krate.edition(db),
unstable_features: &unstable_features,
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index 64d97b3f2a..3021ccf402 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -4,42 +4,5 @@
//!
//! But we need this for at least LRU caching at the query level.
pub use hir_def::db::DefDatabase;
-// AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
-// BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
-// CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
-// DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
-// ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
-// FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
-// FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
-// GenericParamsWithSourceMapQuery, ImplItemsWithDiagnosticsQuery, ImportMapQuery,
-// IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
-// InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
-// InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
-// InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
-// InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
-// InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
-// MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
-// StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitItemsWithDiagnosticsQuery,
-// TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
-// };
pub use hir_expand::db::ExpandDatabase;
-// AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
-// ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
-// ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
-// RealSpanMapQuery,
pub use hir_ty::db::HirDatabase;
-// AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
-// CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
-// ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
-// FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
-// GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
-// ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
-// InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
-// InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
-// InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
-// MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
-// MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
-// TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
-// TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
-// TypeAliasImplTraitsQuery, ValueTyQuery,
-// };
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 10a1fa12e0..d0d8c4877d 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -13,7 +13,7 @@ use hir_ty::{
GenericPredicates,
db::HirDatabase,
display::{
- HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault,
+ HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault,
hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
},
next_solver::ClauseKind,
@@ -29,7 +29,7 @@ use crate::{
};
impl<'db> HirDisplay<'db> for Function {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let db = f.db;
let data = db.function_signature(self.id);
let container = self.as_assoc_item(db).map(|it| it.container(db));
@@ -185,19 +185,18 @@ impl<'db> HirDisplay<'db> for Function {
}
}
-fn write_impl_header<'db>(
- impl_: &Impl,
- f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result {
let db = f.db;
f.write_str("impl")?;
let def_id = GenericDefId::ImplId(impl_.id);
write_generic_params(def_id, f)?;
- if let Some(trait_) = impl_.trait_(db) {
- let trait_data = db.trait_signature(trait_.id);
- write!(f, " {} for", trait_data.name.display(db, f.edition()))?;
+ let impl_data = db.impl_signature(impl_.id);
+ if let Some(target_trait) = &impl_data.target_trait {
+ f.write_char(' ')?;
+ hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?;
+ f.write_str(" for")?;
}
f.write_char(' ')?;
@@ -207,7 +206,7 @@ fn write_impl_header<'db>(
}
impl<'db> HirDisplay<'db> for SelfParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let data = f.db.function_signature(self.func);
let param = *data.params.first().unwrap();
match &data.store[param] {
@@ -233,7 +232,7 @@ impl<'db> HirDisplay<'db> for SelfParam {
}
impl<'db> HirDisplay<'db> for Adt {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self {
Adt::Struct(it) => it.hir_fmt(f),
Adt::Union(it) => it.hir_fmt(f),
@@ -243,7 +242,7 @@ impl<'db> HirDisplay<'db> for Adt {
}
impl<'db> HirDisplay<'db> for Struct {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let module_id = self.module(f.db).id;
// FIXME: Render repr if its set explicitly?
write_visibility(module_id, self.visibility(f.db), f)?;
@@ -284,7 +283,7 @@ impl<'db> HirDisplay<'db> for Struct {
}
impl<'db> HirDisplay<'db> for Enum {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("enum ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -301,7 +300,7 @@ impl<'db> HirDisplay<'db> for Enum {
}
impl<'db> HirDisplay<'db> for Union {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("union ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -322,7 +321,7 @@ fn write_fields<'db>(
limit: usize,
in_line: bool,
f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
let count = fields.len().min(limit);
let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') };
f.write_char(if !has_where_clause { ' ' } else { separator })?;
@@ -355,7 +354,7 @@ fn write_variants<'db>(
has_where_clause: bool,
limit: usize,
f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
let count = variants.len().min(limit);
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
if count == 0 {
@@ -391,7 +390,7 @@ fn write_variants<'db>(
}
impl<'db> HirDisplay<'db> for Field {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
@@ -399,14 +398,14 @@ impl<'db> HirDisplay<'db> for Field {
}
impl<'db> HirDisplay<'db> for TupleField {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
}
}
impl<'db> HirDisplay<'db> for Variant {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
let data = self.id.fields(f.db);
match data.shape {
@@ -436,19 +435,19 @@ impl<'db> HirDisplay<'db> for Variant {
}
impl<'db> HirDisplay<'db> for Type<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
self.ty.hir_fmt(f)
}
}
impl<'db> HirDisplay<'db> for TypeNs<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
self.ty.hir_fmt(f)
}
}
impl<'db> HirDisplay<'db> for ExternCrateDecl {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
f.write_str("extern crate ")?;
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
@@ -460,7 +459,7 @@ impl<'db> HirDisplay<'db> for ExternCrateDecl {
}
impl<'db> HirDisplay<'db> for GenericParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self {
GenericParam::TypeParam(it) => it.hir_fmt(f),
GenericParam::ConstParam(it) => it.hir_fmt(f),
@@ -470,7 +469,7 @@ impl<'db> HirDisplay<'db> for GenericParam {
}
impl<'db> HirDisplay<'db> for TypeOrConstParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.split(f.db) {
either::Either::Left(it) => it.hir_fmt(f),
either::Either::Right(it) => it.hir_fmt(f),
@@ -479,7 +478,7 @@ impl<'db> HirDisplay<'db> for TypeOrConstParam {
}
impl<'db> HirDisplay<'db> for TypeParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let params = f.db.generic_params(self.id.parent());
let param_data = &params[self.id.local_id()];
let krate = self.id.parent().krate(f.db).id;
@@ -541,22 +540,19 @@ impl<'db> HirDisplay<'db> for TypeParam {
}
impl<'db> HirDisplay<'db> for LifetimeParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))
}
}
impl<'db> HirDisplay<'db> for ConstParam {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?;
self.ty(f.db).hir_fmt(f)
}
}
-fn write_generic_params<'db>(
- def: GenericDefId,
- f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
let (params, store) = f.db.generic_params_and_store(def);
if params.iter_lt().next().is_none()
&& params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
@@ -614,10 +610,7 @@ fn write_generic_params<'db>(
Ok(())
}
-fn write_where_clause<'db>(
- def: GenericDefId,
- f: &mut HirFormatter<'_, 'db>,
-) -> Result<bool, HirDisplayError> {
+fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result<bool> {
let (params, store) = f.db.generic_params_and_store(def);
if !has_disaplayable_predicates(f.db, &params, &store) {
return Ok(false);
@@ -649,7 +642,7 @@ fn write_where_predicates<'db>(
params: &GenericParams,
store: &ExpressionStore,
f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+) -> Result {
use WherePredicate::*;
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
@@ -710,7 +703,7 @@ fn write_where_predicates<'db>(
}
impl<'db> HirDisplay<'db> for Const {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let db = f.db;
let container = self.as_assoc_item(db).map(|it| it.container(db));
let mut module = self.module(db);
@@ -731,7 +724,7 @@ impl<'db> HirDisplay<'db> for Const {
}
impl<'db> HirDisplay<'db> for Static {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.static_signature(self.id);
f.write_str("static ")?;
@@ -745,13 +738,13 @@ impl<'db> HirDisplay<'db> for Static {
}
impl<'db> HirDisplay<'db> for TraitRef<'db> {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
self.trait_ref.hir_fmt(f)
}
}
impl<'db> HirDisplay<'db> for Trait {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
// FIXME(trait-alias) needs special handling to print the equal sign
write_trait_header(self, f)?;
let def_id = GenericDefId::TraitId(self.id);
@@ -790,10 +783,7 @@ impl<'db> HirDisplay<'db> for Trait {
}
}
-fn write_trait_header<'db>(
- trait_: &Trait,
- f: &mut HirFormatter<'_, 'db>,
-) -> Result<(), HirDisplayError> {
+fn write_trait_header<'db>(trait_: &Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
let data = f.db.trait_signature(trait_.id);
if data.flags.contains(TraitFlags::UNSAFE) {
@@ -808,7 +798,7 @@ fn write_trait_header<'db>(
}
impl<'db> HirDisplay<'db> for TypeAlias {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.type_alias_signature(self.id);
write!(f, "type {}", data.name.display(f.db, f.edition()))?;
@@ -831,7 +821,7 @@ impl<'db> HirDisplay<'db> for TypeAlias {
}
impl<'db> HirDisplay<'db> for Module {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.parent(f.db) {
Some(m) => write_visibility(m.id, self.visibility(f.db), f)?,
None => {
@@ -849,7 +839,7 @@ impl<'db> HirDisplay<'db> for Module {
}
impl<'db> HirDisplay<'db> for Crate {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.display_name(f.db) {
Some(name) => write!(f, "extern crate {name}"),
None => f.write_str("extern crate {unknown}"),
@@ -858,7 +848,7 @@ impl<'db> HirDisplay<'db> for Crate {
}
impl<'db> HirDisplay<'db> for Macro {
- fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
+ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
match self.id {
hir_def::MacroId::Macro2Id(_) => f.write_str("macro"),
hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 6f427d728b..1aa7994001 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -20,7 +20,7 @@ use crate::{
pub trait HasSource {
type Ast;
/// Fetches the definition's source node.
- /// Using [`crate::Semantics::source`] is preferred when working with [`crate::Semantics`],
+ /// Using [`crate::SemanticsImpl::source`] is preferred when working with [`crate::Semantics`],
/// as that caches the parsed file in the semantics' cache.
///
/// The current some implementations can return `InFile` instead of `Option<InFile>`.
@@ -35,23 +35,23 @@ impl Module {
/// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].definition_source(db)
+ def_map[self.id].definition_source(db)
}
/// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
pub fn definition_source_range(self, db: &dyn HirDatabase) -> InFile<TextRange> {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].definition_source_range(db)
+ def_map[self.id].definition_source_range(db)
}
pub fn definition_source_file_id(self, db: &dyn HirDatabase) -> HirFileId {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].definition_source_file_id()
+ def_map[self.id].definition_source_file_id()
}
pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
let def_map = self.id.def_map(db);
- match def_map[self.id.local_id].origin {
+ match def_map[self.id].origin {
ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
_ => false,
}
@@ -59,7 +59,7 @@ impl Module {
pub fn as_source_file_id(self, db: &dyn HirDatabase) -> Option<EditionedFileId> {
let def_map = self.id.def_map(db);
- match def_map[self.id.local_id].origin {
+ match def_map[self.id].origin {
ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition, .. } => {
Some(definition)
}
@@ -69,21 +69,21 @@ impl Module {
pub fn is_inline(self, db: &dyn HirDatabase) -> bool {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].origin.is_inline()
+ def_map[self.id].origin.is_inline()
}
/// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
/// `None` for the crate root.
pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].declaration_source(db)
+ def_map[self.id].declaration_source(db)
}
/// Returns a text range which declares this module, either a `mod foo;` or a `mod foo {}`.
/// `None` for the crate root.
pub fn declaration_source_range(self, db: &dyn HirDatabase) -> Option<InFile<TextRange>> {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].declaration_source_range(db)
+ def_map[self.id].declaration_source_range(db)
}
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2146e4db77..a50a736ccd 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -48,11 +48,11 @@ use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin};
use either::Either;
use hir_def::{
- AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, CrateRootModuleId,
- DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId,
- GenericParamId, HasModule, ImplId, InternedModuleId, ItemContainerId, LifetimeParamId,
- LocalFieldId, Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId,
- TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
+ AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+ EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
+ HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
+ MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId,
+ TypeParamId, UnionId,
attrs::AttrFlags,
expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
hir::{
@@ -76,7 +76,7 @@ use hir_expand::{
AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind,
};
use hir_ty::{
- GenericPredicates, InferenceResult, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
+ GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic,
ValueTyDefId, all_super_traits, autoderef, check_orphan_rules,
consteval::try_const_usize,
db::{InternedClosureId, InternedCoroutineId},
@@ -89,7 +89,7 @@ use hir_ty::{
mir::{MutBorrowKind, interpret_mir},
next_solver::{
AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
- PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode,
+ ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode,
infer::{DbInternerInferExt, InferCtxt},
},
traits::{self, is_inherent_impl_coherent, structurally_normalize_ty},
@@ -117,8 +117,8 @@ pub use crate::{
diagnostics::*,
has_source::HasSource,
semantics::{
- PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo,
- VisibleTraits,
+ LintAttr, PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope,
+ TypeInfo, VisibleTraits,
},
};
@@ -258,13 +258,13 @@ impl Crate {
.flatten()
}
- pub fn root_module(self) -> Module {
- Module { id: CrateRootModuleId::from(self.id).into() }
+ pub fn root_module(self, db: &dyn HirDatabase) -> Module {
+ Module { id: crate_def_map(db, self.id).root_module_id() }
}
pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
let def_map = crate_def_map(db, self.id);
- def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
+ def_map.modules().map(|(id, _)| id.into()).collect()
}
pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
@@ -520,7 +520,7 @@ impl ModuleDef {
impl HasCrate for ModuleDef {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
match self.module(db) {
- Some(module) => module.krate(),
+ Some(module) => module.krate(db),
None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()),
}
}
@@ -550,29 +550,29 @@ impl Module {
}
/// Returns the crate this module is part of.
- pub fn krate(self) -> Crate {
- Crate { id: self.id.krate() }
+ pub fn krate(self, db: &dyn HirDatabase) -> Crate {
+ Crate { id: self.id.krate(db) }
}
/// Topmost parent of this module. Every module has a `crate_root`, but some
/// might be missing `krate`. This can happen if a module's file is not included
/// in the module tree of any target in `Cargo.toml`.
pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
- let def_map = crate_def_map(db, self.id.krate());
- Module { id: def_map.crate_root().into() }
+ let def_map = crate_def_map(db, self.id.krate(db));
+ Module { id: def_map.crate_root(db) }
}
- pub fn is_crate_root(self) -> bool {
- DefMap::ROOT == self.id.local_id
+ pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
+ self.crate_root(db) == self
}
/// Iterates over all child modules.
pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
let def_map = self.id.def_map(db);
- let children = def_map[self.id.local_id]
+ let children = def_map[self.id]
.children
.values()
- .map(|module_id| Module { id: def_map.module_id(*module_id) })
+ .map(|module_id| Module { id: *module_id })
.collect::<Vec<_>>();
children.into_iter()
}
@@ -580,14 +580,14 @@ impl Module {
/// Finds a parent module.
pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
let def_map = self.id.def_map(db);
- let parent_id = def_map.containing_module(self.id.local_id)?;
+ let parent_id = def_map.containing_module(self.id)?;
Some(Module { id: parent_id })
}
/// Finds nearest non-block ancestor `Module` (`self` included).
pub fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module {
let mut id = self.id;
- while id.is_block_module() {
+ while id.is_block_module(db) {
id = id.containing_module(db).expect("block without parent module");
}
Module { id }
@@ -609,7 +609,7 @@ impl Module {
db: &dyn HirDatabase,
visible_from: Option<Module>,
) -> Vec<(Name, ScopeDef)> {
- self.id.def_map(db)[self.id.local_id]
+ self.id.def_map(db)[self.id]
.scope
.entries()
.filter_map(|(name, def)| {
@@ -646,19 +646,19 @@ impl Module {
style_lints: bool,
) {
let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered();
- let edition = self.id.krate().data(db).edition;
+ let edition = self.id.krate(db).data(db).edition;
let def_map = self.id.def_map(db);
for diag in def_map.diagnostics() {
- if diag.in_module != self.id.local_id {
+ if diag.in_module != self.id {
// FIXME: This is accidentally quadratic.
continue;
}
emit_def_diagnostic(db, acc, diag, edition, def_map.krate());
}
- if !self.id.is_block_module() {
+ if !self.id.is_block_module(db) {
// These are reported by the body of block modules
- let scope = &def_map[self.id.local_id].scope;
+ let scope = &def_map[self.id].scope;
scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc));
}
@@ -666,7 +666,7 @@ impl Module {
match def {
ModuleDef::Module(m) => {
// Only add diagnostics from inline modules
- if def_map[m.id.local_id].origin.is_inline() {
+ if def_map[m.id].origin.is_inline() {
m.diagnostics(db, acc, style_lints)
}
acc.extend(def.diagnostics(db, style_lints))
@@ -765,7 +765,7 @@ impl Module {
}
self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m));
- let interner = DbInterner::new_with(db, self.id.krate());
+ let interner = DbInterner::new_with(db, self.id.krate(db));
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
let mut impl_assoc_items_scratch = vec![];
@@ -790,7 +790,7 @@ impl Module {
let ast_id_map = db.ast_id_map(file_id);
for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() {
- emit_def_diagnostic(db, acc, diag, edition, loc.container.krate());
+ emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db));
}
if impl_signature.target_trait.is_none()
@@ -939,7 +939,7 @@ impl Module {
pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
let def_map = self.id.def_map(db);
- let scope = &def_map[self.id.local_id].scope;
+ let scope = &def_map[self.id].scope;
scope
.declarations()
.map(ModuleDef::from)
@@ -949,13 +949,13 @@ impl Module {
pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
let def_map = self.id.def_map(db);
- let scope = &def_map[self.id.local_id].scope;
+ let scope = &def_map[self.id].scope;
scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| it.into()).collect()
}
pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
let def_map = self.id.def_map(db);
- def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
+ def_map[self.id].scope.impls().map(Impl::from).collect()
}
/// Finds a path that can be used to refer to the given item from within
@@ -990,7 +990,7 @@ impl Module {
#[inline]
pub fn doc_keyword(self, db: &dyn HirDatabase) -> Option<Symbol> {
- AttrFlags::doc_keyword(db, InternedModuleId::new(db, self.id))
+ AttrFlags::doc_keyword(db, self.id)
}
/// Whether it has `#[path = "..."]` attribute.
@@ -1196,7 +1196,7 @@ fn precise_macro_call_location(
impl HasVisibility for Module {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let def_map = self.id.def_map(db);
- let module_data = &def_map[self.id.local_id];
+ let module_data = &def_map[self.id];
module_data.visibility
}
}
@@ -1245,7 +1245,7 @@ impl TupleField {
.get(self.index as usize)
.copied()
.unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed));
- Type { env: db.trait_environment_for_body(self.owner), ty }
+ Type { env: body_param_env_from_has_crate(db, self.owner), ty }
}
}
@@ -1322,13 +1322,16 @@ impl Field {
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
db.layout_of_ty(
self.ty(db).ty,
- db.trait_environment(match hir_def::VariantId::from(self.parent) {
- hir_def::VariantId::EnumVariantId(id) => {
- GenericDefId::AdtId(id.lookup(db).parent.into())
- }
- hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
- hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
- }),
+ param_env_from_has_crate(
+ db,
+ match hir_def::VariantId::from(self.parent) {
+ hir_def::VariantId::EnumVariantId(id) => {
+ GenericDefId::AdtId(id.lookup(db).parent.into())
+ }
+ hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
+ hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
+ },
+ ),
)
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
}
@@ -1538,7 +1541,7 @@ impl Enum {
pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
let interner = DbInterner::new_no_crate(db);
Type::new_for_crate(
- self.id.lookup(db).container.krate(),
+ self.id.lookup(db).container.krate(db),
match EnumSignature::variant_body_type(db, self.id) {
layout::IntegerType::Pointer(sign) => match sign {
true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize),
@@ -1745,13 +1748,12 @@ impl Adt {
}
pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
- let env = db.trait_environment(self.into());
let interner = DbInterner::new_no_crate(db);
let adt_id = AdtId::from(self);
let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| {
GenericArg::error_from_id(interner, id)
});
- db.layout_of_adt(adt_id, args, env)
+ db.layout_of_adt(adt_id, args, param_env_from_has_crate(db, adt_id))
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap()))
}
@@ -1925,7 +1927,7 @@ impl DefWithBody {
pub fn debug_mir(self, db: &dyn HirDatabase) -> String {
let body = db.mir_body(self.id());
match body {
- Ok(body) => body.pretty_print(db, self.module(db).krate().to_display_target(db)),
+ Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)),
Err(e) => format!("error:\n{e:?}"),
}
}
@@ -1936,7 +1938,7 @@ impl DefWithBody {
acc: &mut Vec<AnyDiagnostic<'db>>,
style_lints: bool,
) {
- let krate = self.module(db).id.krate();
+ let krate = self.module(db).id.krate(db);
let (body, source_map) = db.body_with_source_map(self.into());
let sig_source_map = match self {
@@ -1950,7 +1952,7 @@ impl DefWithBody {
};
for (_, def_map) in body.blocks(db) {
- Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
+ Module { id: def_map.root_module_id() }.diagnostics(db, acc, style_lints);
}
expr_store_diagnostics(db, acc, &source_map);
@@ -2276,7 +2278,7 @@ impl Function {
}
pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
- let environment = db.trait_environment(self.id.into());
+ let environment = param_env_from_has_crate(db, self.id);
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
let callable_sig =
db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
@@ -2285,7 +2287,7 @@ impl Function {
.iter()
.enumerate()
.map(|(idx, ty)| {
- let ty = Type { env: environment.clone(), ty };
+ let ty = Type { env: environment, ty };
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
})
.collect()
@@ -2301,7 +2303,7 @@ impl Function {
}
pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
- let environment = db.trait_environment(self.id.into());
+ let environment = param_env_from_has_crate(db, self.id);
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
let callable_sig =
db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
@@ -2312,7 +2314,7 @@ impl Function {
.enumerate()
.skip(skip)
.map(|(idx, ty)| {
- let ty = Type { env: environment.clone(), ty };
+ let ty = Type { env: environment, ty };
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
})
.collect()
@@ -2324,7 +2326,7 @@ impl Function {
db: &'db dyn HirDatabase,
generics: impl Iterator<Item = Type<'db>>,
) -> Vec<Param<'db>> {
- let environment = db.trait_environment(self.id.into());
+ let environment = param_env_from_has_crate(db, self.id);
let interner = DbInterner::new_no_crate(db);
let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty));
let callable_sig =
@@ -2336,7 +2338,7 @@ impl Function {
.enumerate()
.skip(skip)
.map(|(idx, ty)| {
- let ty = Type { env: environment.clone(), ty };
+ let ty = Type { env: environment, ty };
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
})
.collect()
@@ -2396,7 +2398,7 @@ impl Function {
/// is this a `fn main` or a function with an `export_name` of `main`?
pub fn is_main(self, db: &dyn HirDatabase) -> bool {
self.exported_main(db)
- || self.module(db).is_crate_root() && db.function_signature(self.id).name == sym::main
+ || self.module(db).is_crate_root(db) && db.function_signature(self.id).name == sym::main
}
/// Is this a function with an `export_name` of `main`?
@@ -2471,7 +2473,10 @@ impl Function {
let body = db.monomorphized_mir_body(
self.id.into(),
GenericArgs::new_from_iter(interner, []),
- db.trait_environment(self.id.into()),
+ ParamEnvAndCrate {
+ param_env: db.trait_environment(self.id.into()),
+ krate: self.id.module(db).krate(db),
+ },
)?;
let (result, output) = interpret_mir(db, body, false, None)?;
let mut text = match result {
@@ -2613,7 +2618,7 @@ impl SelfParam {
// FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
let callable_sig =
db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder();
- let environment = db.trait_environment(self.func.into());
+ let environment = param_env_from_has_crate(db, self.func);
let ty = callable_sig.inputs().as_slice()[0];
Type { env: environment, ty }
}
@@ -2628,7 +2633,7 @@ impl SelfParam {
let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty));
let callable_sig =
db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder();
- let environment = db.trait_environment(self.func.into());
+ let environment = param_env_from_has_crate(db, self.func);
let ty = callable_sig.inputs().as_slice()[0];
Type { env: environment, ty }
}
@@ -2652,7 +2657,7 @@ impl ExternCrateDecl {
pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
let loc = self.id.lookup(db);
- let krate = loc.container.krate();
+ let krate = loc.container.krate(db);
let name = self.name(db);
if name == sym::self_ {
Some(krate.into())
@@ -3234,8 +3239,8 @@ impl ItemInNs {
/// Returns the crate defining this item (or `None` if `self` is built-in).
pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
match self {
- ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()),
- ItemInNs::Macros(id) => Some(id.module(db).krate()),
+ ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate(db)),
+ ItemInNs::Macros(id) => Some(id.module(db).krate(db)),
}
}
@@ -3687,11 +3692,11 @@ impl GenericDef {
pub struct GenericSubstitution<'db> {
def: GenericDefId,
subst: GenericArgs<'db>,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
}
impl<'db> GenericSubstitution<'db> {
- fn new(def: GenericDefId, subst: GenericArgs<'db>, env: Arc<TraitEnvironment<'db>>) -> Self {
+ fn new(def: GenericDefId, subst: GenericArgs<'db>, env: ParamEnvAndCrate<'db>) -> Self {
Self { def, subst, env }
}
@@ -3737,9 +3742,7 @@ impl<'db> GenericSubstitution<'db> {
.zip(type_params);
container_params
.chain(self_params)
- .filter_map(|(ty, name)| {
- Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
- })
+ .filter_map(|(ty, name)| Some((name?.symbol().clone(), Type { ty, env: self.env })))
.collect()
}
}
@@ -4320,7 +4323,7 @@ impl Impl {
}
pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec<Impl> {
- module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect()
+ module.id.def_map(db)[module.id].scope.impls().map(Into::into).collect()
}
/// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type",
@@ -4345,15 +4348,13 @@ impl Impl {
if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) {
InherentImpls::for_each_crate_and_block(
db,
- module.krate(),
- module.containing_block(),
+ module.krate(db),
+ module.block(db),
&mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)),
);
- std::iter::successors(module.containing_block(), |block| {
- block.loc(db).module.containing_block()
- })
- .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
- .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls));
+ std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
+ .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
+ .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls));
for &krate in &**db.all_crates() {
TraitImpls::for_crate(db, krate)
.for_self_ty(&simplified_ty, &mut extend_with_impls);
@@ -4373,10 +4374,10 @@ impl Impl {
let mut handle_impls = |impls: &TraitImpls| {
impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from)));
};
- for krate in module.krate().transitive_rev_deps(db) {
+ for krate in module.krate(db).transitive_rev_deps(db) {
handle_impls(TraitImpls::for_crate(db, krate));
}
- if let Some(block) = module.containing_block()
+ if let Some(block) = module.block(db)
&& let Some(impls) = TraitImpls::for_block(db, block)
{
handle_impls(impls);
@@ -4428,7 +4429,7 @@ impl Impl {
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
let module_id = self.id.lookup(db).container;
(
- crate_def_map(db, module_id.krate())[module_id.local_id]
+ module_id.def_map(db)[module_id]
.scope
.derive_macro_invoc(ast_id, derive_attr_index)?,
derive_index,
@@ -4459,7 +4460,7 @@ impl Impl {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TraitRef<'db> {
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
trait_ref: hir_ty::next_solver::TraitRef<'db>,
}
@@ -4469,9 +4470,7 @@ impl<'db> TraitRef<'db> {
resolver: &Resolver<'_>,
trait_ref: hir_ty::next_solver::TraitRef<'db>,
) -> Self {
- let env = resolver
- .generic_def()
- .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
+ let env = param_env_from_resolver(db, resolver);
TraitRef { env, trait_ref }
}
@@ -4481,7 +4480,7 @@ impl<'db> TraitRef<'db> {
pub fn self_ty(&self) -> TypeNs<'_> {
let ty = self.trait_ref.self_ty();
- TypeNs { env: self.env.clone(), ty }
+ TypeNs { env: self.env, ty }
}
/// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the
@@ -4492,7 +4491,7 @@ impl<'db> TraitRef<'db> {
.as_slice()
.get(idx)
.and_then(|arg| arg.ty())
- .map(|ty| TypeNs { env: self.env.clone(), ty })
+ .map(|ty| TypeNs { env: self.env, ty })
}
}
@@ -4556,11 +4555,8 @@ impl<'db> Closure<'db> {
let owner = db.lookup_intern_closure(id).0;
let infer = InferenceResult::for_body(db, owner);
let (captures, _) = infer.closure_info(id);
- let env = db.trait_environment_for_body(owner);
- captures
- .iter()
- .map(|capture| Type { env: env.clone(), ty: capture.ty(db, self.subst) })
- .collect()
+ let env = body_param_env_from_has_crate(db, owner);
+ captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect()
}
pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait {
@@ -4768,7 +4764,7 @@ impl CaptureUsageSource {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Type<'db> {
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
ty: Ty<'db>,
}
@@ -4786,21 +4782,17 @@ impl<'db> Type<'db> {
resolver: &Resolver<'_>,
ty: Ty<'db>,
) -> Self {
- let environment = resolver
- .generic_def()
- .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
+ let environment = param_env_from_resolver(db, resolver);
Type { env: environment, ty }
}
pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty<'db>) -> Self {
- Type { env: TraitEnvironment::empty(krate), ty }
+ Type { env: empty_param_env(krate), ty }
}
fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self {
let resolver = lexical_env.resolver(db);
- let environment = resolver
- .generic_def()
- .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
+ let environment = param_env_from_resolver(db, &resolver);
Type { env: environment, ty }
}
@@ -4856,7 +4848,7 @@ impl<'db> Type<'db> {
pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self {
let tys = tys.iter().map(|it| it.ty);
let interner = DbInterner::conjure();
- Type { env: TraitEnvironment::empty(krate), ty: Ty::new_tup_from_iter(interner, tys) }
+ Type { env: empty_param_env(krate), ty: Ty::new_tup_from_iter(interner, tys) }
}
pub fn is_unit(&self) -> bool {
@@ -5046,7 +5038,7 @@ impl<'db> Type<'db> {
})
.or(lang_items.Future)?;
- if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) {
+ if !traits::implements_trait_unique(self.ty, db, self.env, trait_) {
return None;
}
@@ -5077,7 +5069,7 @@ impl<'db> Type<'db> {
let Some(iterator_trait) = lang_items.Iterator else {
return false;
};
- traits::implements_trait_unique(self.ty, db, self.env.clone(), iterator_trait)
+ traits::implements_trait_unique(self.ty, db, self.env, iterator_trait)
}
/// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type
@@ -5089,7 +5081,7 @@ impl<'db> Type<'db> {
Some(into_iter_trait.id)
})?;
- if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) {
+ if !traits::implements_trait_unique(self.ty, db, self.env, trait_) {
return None;
}
@@ -5110,7 +5102,7 @@ impl<'db> Type<'db> {
None => return false,
};
- traits::implements_trait_unique(self.ty, db, self.env.clone(), fnonce_trait)
+ traits::implements_trait_unique(self.ty, db, self.env, fnonce_trait)
}
// FIXME: Find better API that also handles const generics
@@ -5121,7 +5113,7 @@ impl<'db> Type<'db> {
trait_.id.into(),
std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)),
);
- traits::implements_trait_unique_with_args(db, self.env.clone(), trait_.id, args)
+ traits::implements_trait_unique_with_args(db, self.env, trait_.id, args)
}
pub fn normalize_trait_assoc_type(
@@ -5144,7 +5136,7 @@ impl<'db> Type<'db> {
);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
- let ty = structurally_normalize_ty(&infcx, projection, self.env.clone());
+ let ty = structurally_normalize_ty(&infcx, projection, self.env.param_env);
if ty.is_ty_error() { None } else { Some(self.derived(ty)) }
}
@@ -5166,8 +5158,7 @@ impl<'db> Type<'db> {
// This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db),
_ => {
- let (fn_trait, sig) =
- hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?;
+ let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(self.ty, self.env, db)?;
return Some(Callable {
ty: self.clone(),
sig,
@@ -5291,7 +5282,7 @@ impl<'db> Type<'db> {
let interner = DbInterner::new_no_crate(db);
// There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty);
- autoderef(db, self.env.clone(), canonical)
+ autoderef(db, self.env, canonical)
}
// This would be nicer if it just returned an iterator, but that runs into
@@ -5336,8 +5327,8 @@ impl<'db> Type<'db> {
if let Some(module) = method_resolution::simplified_type_module(db, &simplified_type) {
InherentImpls::for_each_crate_and_block(
db,
- module.krate(),
- module.containing_block(),
+ module.krate(db),
+ module.block(db),
&mut |impls| {
handle_impls(impls.for_self_ty(&simplified_type));
},
@@ -5473,17 +5464,15 @@ impl<'db> Type<'db> {
f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R,
) -> R {
let module = resolver.module();
- let interner = DbInterner::new_with(db, module.krate());
+ let interner = DbInterner::new_with(db, module.krate(db));
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
let unstable_features =
MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map());
- let environment = resolver
- .generic_def()
- .map_or_else(|| TraitEnvironment::empty(module.krate()), |d| db.trait_environment(d));
+ let environment = param_env_from_resolver(db, resolver);
let ctx = MethodResolutionContext {
infcx: &infcx,
resolver,
- env: &environment,
+ param_env: environment.param_env,
traits_in_scope,
edition: resolver.krate().data(db).edition,
unstable_features: &unstable_features,
@@ -5704,7 +5693,13 @@ impl<'db> Type<'db> {
.filter(|ty| matches!(ty.kind(), TyKind::Param(_)))
.flat_map(|ty| {
self.env
- .traits_in_scope_from_clauses(ty)
+ .param_env
+ .clauses()
+ .iter()
+ .filter_map(move |pred| match pred.kind().skip_binder() {
+ ClauseKind::Trait(tr) if tr.self_ty() == ty => Some(tr.def_id().0),
+ _ => None,
+ })
.flat_map(|t| hir_ty::all_super_traits(db, t))
})
.map(Trait::from)
@@ -5728,7 +5723,7 @@ impl<'db> Type<'db> {
}
fn derived(&self, ty: Ty<'db>) -> Self {
- Type { env: self.env.clone(), ty }
+ Type { env: self.env, ty }
}
/// Visits every type, including generic arguments, in this type. `callback` is called with type
@@ -5736,7 +5731,7 @@ impl<'db> Type<'db> {
pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) {
struct Visitor<'db, F> {
db: &'db dyn HirDatabase,
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
callback: F,
visited: FxHashSet<Ty<'db>>,
}
@@ -5751,7 +5746,7 @@ impl<'db> Type<'db> {
return;
}
- (self.callback)(Type { env: self.env.clone(), ty });
+ (self.callback)(Type { env: self.env, ty });
if let Some(bounds) = ty.impl_trait_bounds(self.db) {
bounds.visit_with(self);
@@ -5761,8 +5756,7 @@ impl<'db> Type<'db> {
}
}
- let mut visitor =
- Visitor { db, env: self.env.clone(), callback, visited: FxHashSet::default() };
+ let mut visitor = Visitor { db, env: self.env, callback, visited: FxHashSet::default() };
self.ty.visit_with(&mut visitor);
}
/// Check if type unifies with another type.
@@ -5772,7 +5766,7 @@ impl<'db> Type<'db> {
pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool {
let interner = DbInterner::new_no_crate(db);
let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty));
- hir_ty::could_unify(db, self.env.clone(), &tys)
+ hir_ty::could_unify(db, self.env, &tys)
}
/// Check if type unifies with another type eagerly making sure there are no unresolved goals.
@@ -5782,13 +5776,13 @@ impl<'db> Type<'db> {
pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool {
let interner = DbInterner::new_no_crate(db);
let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty));
- hir_ty::could_unify_deeply(db, self.env.clone(), &tys)
+ hir_ty::could_unify_deeply(db, self.env, &tys)
}
pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool {
let interner = DbInterner::new_no_crate(db);
let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, to.ty));
- hir_ty::could_coerce(db, self.env.clone(), &tys)
+ hir_ty::could_coerce(db, self.env, &tys)
}
pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option<TypeParam> {
@@ -5807,34 +5801,32 @@ impl<'db> Type<'db> {
}
pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> {
- db.layout_of_ty(self.ty, self.env.clone())
+ db.layout_of_ty(self.ty, self.env)
.map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
}
pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue {
let interner = DbInterner::new_with(db, self.env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
- hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.clone())
+ hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.param_env)
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeNs<'db> {
- env: Arc<TraitEnvironment<'db>>,
+ env: ParamEnvAndCrate<'db>,
ty: Ty<'db>,
}
impl<'db> TypeNs<'db> {
fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self {
let resolver = lexical_env.resolver(db);
- let environment = resolver
- .generic_def()
- .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
+ let environment = param_env_from_resolver(db, &resolver);
TypeNs { env: environment, ty }
}
pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> {
- Type { env: self.env.clone(), ty: self.ty }
+ Type { env: self.env, ty: self.ty }
}
// FIXME: Find better API that also handles const generics
@@ -6146,12 +6138,12 @@ impl ScopeDef {
pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
match self {
- ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()),
- ScopeDef::GenericParam(it) => Some(it.module(db).krate()),
+ ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate(db)),
+ ScopeDef::GenericParam(it) => Some(it.module(db).krate(db)),
ScopeDef::ImplSelfType(_) => None,
- ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()),
- ScopeDef::Local(it) => Some(it.module(db).krate()),
- ScopeDef::Label(it) => Some(it.module(db).krate()),
+ ScopeDef::AdtSelfType(it) => Some(it.module(db).krate(db)),
+ ScopeDef::Local(it) => Some(it.module(db).krate(db)),
+ ScopeDef::Label(it) => Some(it.module(db).krate(db)),
ScopeDef::Unknown => None,
}
}
@@ -6211,61 +6203,61 @@ pub trait HasCrate {
impl<T: hir_def::HasModule> HasCrate for T {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate().into()
+ self.module(db).krate(db).into()
}
}
impl HasCrate for AssocItem {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Struct {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Union {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Enum {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Field {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.parent_def(db).module(db).krate()
+ self.parent_def(db).module(db).krate(db)
}
}
impl HasCrate for Variant {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Function {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Const {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for TypeAlias {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
@@ -6277,37 +6269,37 @@ impl HasCrate for Type<'_> {
impl HasCrate for Macro {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Trait {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Static {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Adt {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Impl {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
- self.module(db).krate()
+ self.module(db).krate(db)
}
}
impl HasCrate for Module {
- fn krate(&self, _: &dyn HirDatabase) -> Crate {
- Module::krate(*self)
+ fn krate(&self, db: &dyn HirDatabase) -> Crate {
+ Module::krate(*self, db)
}
}
@@ -6325,8 +6317,8 @@ impl HasContainer for Module {
fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
// FIXME: handle block expressions as modules (their parent is in a different DefMap)
let def_map = self.id.def_map(db);
- match def_map[self.id.local_id].parent {
- Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }),
+ match def_map[self.id].parent {
+ Some(parent_id) => ItemContainer::Module(Module { id: parent_id }),
None => ItemContainer::Crate(def_map.krate().into()),
}
}
@@ -6485,7 +6477,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
.filter_map(|&krate| {
let segments = segments.clone();
let mut def_map = crate_def_map(db, krate);
- let mut module = &def_map[DefMap::ROOT];
+ let mut module = &def_map[def_map.root_module_id()];
let mut segments = segments.with_position().peekable();
while let Some((_, segment)) = segments.next_if(|&(position, _)| {
!matches!(position, itertools::Position::Last | itertools::Position::Only)
@@ -6499,7 +6491,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
_ => None,
})?;
def_map = res.def_map(db);
- module = &def_map[res.local_id];
+ module = &def_map[res];
}
let (_, item_name) = segments.next()?;
let res = module.scope.get(&Name::new_symbol_root(item_name));
@@ -6546,5 +6538,35 @@ fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId)
})
}
+fn param_env_from_resolver<'db>(
+ db: &'db dyn HirDatabase,
+ resolver: &Resolver<'_>,
+) -> ParamEnvAndCrate<'db> {
+ ParamEnvAndCrate {
+ param_env: resolver
+ .generic_def()
+ .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def)),
+ krate: resolver.krate(),
+ }
+}
+
+fn param_env_from_has_crate<'db>(
+ db: &'db dyn HirDatabase,
+ id: impl hir_def::HasModule + Into<GenericDefId> + Copy,
+) -> ParamEnvAndCrate<'db> {
+ ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) }
+}
+
+fn body_param_env_from_has_crate<'db>(
+ db: &'db dyn HirDatabase,
+ id: impl hir_def::HasModule + Into<DefWithBodyId> + Copy,
+) -> ParamEnvAndCrate<'db> {
+ ParamEnvAndCrate { param_env: db.trait_environment_for_body(id.into()), krate: id.krate(db) }
+}
+
+fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> {
+ ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }
+}
+
pub use hir_ty::next_solver;
pub use hir_ty::setup_tracing;
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 82e60bff5e..b15e642daa 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -39,8 +39,8 @@ use smallvec::{SmallVec, smallvec};
use span::{FileId, SyntaxContext};
use stdx::{TupleExt, always};
use syntax::{
- AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
- TextSize,
+ AstNode, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind, SyntaxNode,
+ SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize,
algo::skip_trivia_token,
ast::{self, HasAttrs as _, HasGenericParams},
};
@@ -174,6 +174,15 @@ impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
}
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum LintAttr {
+ Allow,
+ Expect,
+ Warn,
+ Deny,
+ Forbid,
+}
+
// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
// find actual use within the rust-analyzer project itself, it exists to enable the use
// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
@@ -254,6 +263,59 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
.filter_map(ast::NameLike::cast)
}
+ pub fn lint_attrs(
+ &self,
+ krate: Crate,
+ item: ast::AnyHasAttrs,
+ ) -> impl DoubleEndedIterator<Item = (LintAttr, SmolStr)> {
+ let mut cfg_options = None;
+ let cfg_options = || *cfg_options.get_or_insert_with(|| krate.id.cfg_options(self.db));
+ let mut result = Vec::new();
+ hir_expand::attrs::expand_cfg_attr::<Infallible>(
+ ast::attrs_including_inner(&item),
+ cfg_options,
+ |attr, _, _, _| {
+ let hir_expand::attrs::Meta::TokenTree { path, tt } = attr else {
+ return ControlFlow::Continue(());
+ };
+ if path.segments.len() != 1 {
+ return ControlFlow::Continue(());
+ }
+ let lint_attr = match path.segments[0].text() {
+ "allow" => LintAttr::Allow,
+ "expect" => LintAttr::Expect,
+ "warn" => LintAttr::Warn,
+ "deny" => LintAttr::Deny,
+ "forbid" => LintAttr::Forbid,
+ _ => return ControlFlow::Continue(()),
+ };
+ let mut lint = SmolStrBuilder::new();
+ for token in
+ tt.syntax().children_with_tokens().filter_map(SyntaxElement::into_token)
+ {
+ match token.kind() {
+ T![:] | T![::] => lint.push_str(token.text()),
+ kind if kind.is_any_identifier() => lint.push_str(token.text()),
+ T![,] => {
+ let lint = mem::replace(&mut lint, SmolStrBuilder::new()).finish();
+ if !lint.is_empty() {
+ result.push((lint_attr, lint));
+ }
+ }
+ _ => {}
+ }
+ }
+ let lint = lint.finish();
+ if !lint.is_empty() {
+ result.push((lint_attr, lint));
+ }
+
+ ControlFlow::Continue(())
+ },
+ );
+ result.into_iter()
+ }
+
pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
self.imp.resolve_range_pat(range_pat).map(Struct::from)
}
@@ -380,13 +442,13 @@ impl<'db> SemanticsImpl<'db> {
/// If not crate is found for the file, try to return the last crate in topological order.
pub fn first_crate(&self, file: FileId) -> Option<Crate> {
match self.file_to_module_defs(file).next() {
- Some(module) => Some(module.krate()),
+ Some(module) => Some(module.krate(self.db)),
None => self.db.all_crates().last().copied().map(Into::into),
}
}
pub fn attach_first_edition_opt(&self, file: FileId) -> Option<EditionedFileId> {
- let krate = self.file_to_module_defs(file).next()?.krate();
+ let krate = self.file_to_module_defs(file).next()?.krate(self.db);
Some(EditionedFileId::new(self.db, file, krate.edition(self.db), krate.id))
}
@@ -416,8 +478,8 @@ impl<'db> SemanticsImpl<'db> {
match file_id {
HirFileId::FileId(file_id) => {
let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
- let def_map = crate_def_map(self.db, module.krate().id);
- match def_map[module.id.local_id].origin {
+ let def_map = crate_def_map(self.db, module.krate(self.db).id);
+ match def_map[module.id].origin {
ModuleOrigin::CrateRoot { .. } => None,
ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
let file_id = declaration_tree_id.file_id();
@@ -443,7 +505,7 @@ impl<'db> SemanticsImpl<'db> {
/// the `SyntaxNode` of the *definition* file, not of the *declaration*.
pub fn module_definition_node(&self, module: Module) -> InFile<SyntaxNode> {
let def_map = module.id.def_map(self.db);
- let definition = def_map[module.id.local_id].origin.definition_source(self.db);
+ let definition = def_map[module.id].origin.definition_source(self.db);
let definition = definition.map(|it| it.node());
let root_node = find_root(&definition.value);
self.cache(root_node, definition.file_id);
@@ -472,7 +534,7 @@ impl<'db> SemanticsImpl<'db> {
let file_id = self.find_file(attr.syntax()).file_id;
let krate = match file_id {
HirFileId::FileId(file_id) => {
- self.file_to_module_defs(file_id.file_id(self.db)).next()?.krate().id
+ self.file_to_module_defs(file_id.file_id(self.db)).next()?.krate(self.db).id
}
HirFileId::MacroFile(macro_file) => self.db.lookup_intern_macro_call(macro_file).krate,
};
diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs
index 165ac7e4a0..c1f72debe5 100644
--- a/crates/hir/src/semantics/child_by_source.rs
+++ b/crates/hir/src/semantics/child_by_source.rs
@@ -20,7 +20,6 @@ use hir_def::{
},
hir::generics::GenericParams,
item_scope::ItemScope,
- nameres::DefMap,
src::{HasChildSource, HasSource},
};
@@ -87,7 +86,7 @@ impl ChildBySource for ImplId {
impl ChildBySource for ModuleId {
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
let def_map = self.def_map(db);
- let module_data = &def_map[self.local_id];
+ let module_data = &def_map[*self];
module_data.scope.child_by_source_to(db, res, file_id);
}
}
@@ -226,7 +225,7 @@ impl ChildBySource for DefWithBodyId {
for (block, def_map) in body.blocks(db) {
// All block expressions are merged into the same map, because they logically all add
// inner items to the containing `DefWithBodyId`.
- def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id);
+ def_map[def_map.root].scope.child_by_source_to(db, res, file_id);
res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db), block);
}
}
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 44df4d8fc8..2574059927 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -183,11 +183,7 @@ impl SourceToDefCtx<'_, '_> {
// Note: `mod` declarations in block modules cannot be supported here
let crate_def_map = crate_def_map(self.db, crate_id);
let n_mods = mods.len();
- let modules = |file| {
- crate_def_map
- .modules_for_file(self.db, file)
- .map(|local_id| crate_def_map.module_id(local_id))
- };
+ let modules = |file| crate_def_map.modules_for_file(self.db, file);
mods.extend(modules(file));
if mods.len() == n_mods {
mods.extend(
@@ -239,8 +235,8 @@ impl SourceToDefCtx<'_, '_> {
let child_name = src.value.name()?.as_name();
let def_map = parent_module.def_map(self.db);
- let &child_id = def_map[parent_module.local_id].children.get(&child_name)?;
- Some(def_map.module_id(child_id))
+ let &child_id = def_map[parent_module].children.get(&child_name)?;
+ Some(child_id)
}
pub(super) fn source_file_to_def(&mut self, src: InFile<&ast::SourceFile>) -> Option<ModuleId> {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8144b2f737..901c9e1575 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -29,7 +29,7 @@ use hir_expand::{
name::{AsName, Name},
};
use hir_ty::{
- Adjustment, InferenceResult, LifetimeElisionKind, TraitEnvironment, TyLoweringContext,
+ Adjustment, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext,
diagnostics::{
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
unsafe_operations,
@@ -37,7 +37,8 @@ use hir_ty::{
lang_items::lang_items_for_bin_op,
method_resolution::{self, CandidateId},
next_solver::{
- DbInterner, ErrorGuaranteed, GenericArgs, Ty, TyKind, TypingMode, infer::DbInternerInferExt,
+ DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
+ infer::DbInternerInferExt,
},
traits::structurally_normalize_ty,
};
@@ -227,10 +228,15 @@ impl<'db> SourceAnalyzer<'db> {
})
}
- fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment<'db>> {
- self.body_().map(|(def, ..)| def).map_or_else(
- || TraitEnvironment::empty(self.resolver.krate()),
- |def| db.trait_environment_for_body(def),
+ fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> {
+ ParamEnvAndCrate { param_env, krate: self.resolver.krate() }
+ }
+
+ fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> {
+ self.param_and(
+ self.body_()
+ .map(|(def, ..)| def)
+ .map_or_else(ParamEnv::empty, |def| db.trait_environment_for_body(def)),
)
}
@@ -827,7 +833,7 @@ impl<'db> SourceAnalyzer<'db> {
let mut container = Either::Right(container.ty);
for field_name in offset_of_expr.fields() {
if let Either::Right(container) = &mut container {
- *container = structurally_normalize_ty(&infcx, *container, trait_env.clone());
+ *container = structurally_normalize_ty(&infcx, *container, trait_env.param_env);
}
let handle_variants =
|variant: VariantId, subst: GenericArgs<'db>, container: &mut _| {
@@ -1412,7 +1418,7 @@ impl<'db> SourceAnalyzer<'db> {
Some(it) => it,
None => return (func, substs),
};
- let env = db.trait_environment_for_body(owner);
+ let env = self.param_and(db.trait_environment_for_body(owner));
db.lookup_impl_method(env, func, substs)
}
@@ -1426,10 +1432,10 @@ impl<'db> SourceAnalyzer<'db> {
Some(it) => it,
None => return (const_id, subs),
};
- let env = db.trait_environment_for_body(owner);
+ let env = self.param_and(db.trait_environment_for_body(owner));
let interner = DbInterner::new_with(db, env.krate);
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
- method_resolution::lookup_impl_const(&infcx, env, const_id, subs)
+ method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs)
}
fn lang_items<'a>(&self, db: &'a dyn HirDatabase) -> &'a LangItems {
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index 1530e697a3..073142670d 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -1,5 +1,7 @@
//! File symbol extraction.
+use std::marker::PhantomData;
+
use base_db::FxIndexSet;
use either::Either;
use hir_def::{
@@ -25,7 +27,7 @@ use crate::{HasCrate, Module, ModuleDef, Semantics};
/// The actual data that is stored in the index. It should be as compact as
/// possible.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FileSymbol {
+pub struct FileSymbol<'db> {
pub name: Symbol,
pub def: ModuleDef,
pub loc: DeclarationLocation,
@@ -35,6 +37,7 @@ pub struct FileSymbol {
pub is_assoc: bool,
pub is_import: bool,
pub do_not_complete: Complete,
+ _marker: PhantomData<&'db ()>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -61,9 +64,9 @@ struct SymbolCollectorWork {
parent: Option<Name>,
}
-pub struct SymbolCollector<'a> {
- db: &'a dyn HirDatabase,
- symbols: FxIndexSet<FileSymbol>,
+pub struct SymbolCollector<'db> {
+ db: &'db dyn HirDatabase,
+ symbols: FxIndexSet<FileSymbol<'db>>,
work: Vec<SymbolCollectorWork>,
current_container_name: Option<Symbol>,
collect_pub_only: bool,
@@ -83,10 +86,10 @@ impl<'a> SymbolCollector<'a> {
}
pub fn new_module(
- db: &dyn HirDatabase,
+ db: &'a dyn HirDatabase,
module: Module,
collect_pub_only: bool,
- ) -> Box<[FileSymbol]> {
+ ) -> Box<[FileSymbol<'a>]> {
let mut symbol_collector = SymbolCollector::new(db, collect_pub_only);
symbol_collector.collect(module);
symbol_collector.finish()
@@ -105,7 +108,7 @@ impl<'a> SymbolCollector<'a> {
}
}
- pub fn finish(self) -> Box<[FileSymbol]> {
+ pub fn finish(self) -> Box<[FileSymbol<'a>]> {
self.symbols.into_iter().collect()
}
@@ -217,6 +220,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: true,
do_not_complete: Complete::Yes,
+ _marker: PhantomData,
});
};
@@ -251,11 +255,12 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete: Complete::Yes,
+ _marker: PhantomData,
});
};
let def_map = module_id.def_map(self.db);
- let scope = &def_map[module_id.local_id].scope;
+ let scope = &def_map[module_id].scope;
for impl_id in scope.impls() {
self.collect_from_impl(impl_id);
@@ -329,10 +334,7 @@ impl<'a> SymbolCollector<'a> {
// Descend into the blocks and enqueue collection of all modules within.
for (_, def_map) in body.blocks(self.db) {
for (id, _) in def_map.modules() {
- self.work.push(SymbolCollectorWork {
- module_id: def_map.module_id(id),
- parent: name.clone(),
- });
+ self.work.push(SymbolCollectorWork { module_id: id, parent: name.clone() });
}
}
}
@@ -431,6 +433,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc,
is_import: false,
do_not_complete,
+ _marker: PhantomData,
});
}
}
@@ -444,6 +447,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc,
is_import: false,
do_not_complete,
+ _marker: PhantomData,
});
do_not_complete
@@ -451,7 +455,7 @@ impl<'a> SymbolCollector<'a> {
fn push_module(&mut self, module_id: ModuleId, name: &Name) {
let def_map = module_id.def_map(self.db);
- let module_data = &def_map[module_id.local_id];
+ let module_data = &def_map[module_id];
let Some(declaration) = module_data.origin.declaration() else { return };
let module = declaration.to_node(self.db);
let Some(name_node) = module.name() else { return };
@@ -477,6 +481,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete,
+ _marker: PhantomData,
});
}
}
@@ -490,6 +495,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete,
+ _marker: PhantomData,
});
}
}
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index 979ec8c49f..05a89e7652 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -762,7 +762,7 @@ pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>(
.filter(|_| should_continue())
.map(|params| {
let tys: Vec<Type<'_>> = params.iter().map(|it| it.ty(db)).collect();
- let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
+ let tuple_ty = Type::new_tuple(module.krate(db).into(), &tys);
let expr = Expr::Tuple { ty: tuple_ty.clone(), params };
lookup.insert(tuple_ty, iter::once(expr.clone()));
diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index e970bb7167..65ca1ceae1 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -130,7 +130,7 @@ fn add_missing_impl_members_inner(
if let IgnoreAssocItems::DocHiddenAttrPresent = ignore_items {
// Relax condition for local crates.
let db = ctx.db();
- if trait_.module(db).krate().origin(db).is_local() {
+ if trait_.module(db).krate(db).origin(db).is_local() {
ign_item = IgnoreAssocItems::No;
}
}
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 248ce2ad61..10c3ff0e4d 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -92,24 +92,25 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
bool,
bool,
) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
- let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
+ let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db()));
let variants = enum_def.variants(ctx.db());
- let has_hidden_variants =
- variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
+ let has_hidden_variants = variants
+ .iter()
+ .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db())));
let missing_pats = variants
.into_iter()
.filter_map(|variant| {
Some((
build_pat(ctx, &make, module, variant, cfg)?,
- variant.should_be_hidden(ctx.db(), module.krate()),
+ variant.should_be_hidden(ctx.db(), module.krate(ctx.db())),
))
})
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
- let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option();
+ let option_enum = FamousDefs(&ctx.sema, module.krate(ctx.db())).core_option_Option();
let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
{
// Match `Some` variant first.
@@ -120,8 +121,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
};
(missing_pats.peekable(), is_non_exhaustive, has_hidden_variants)
} else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
- let is_non_exhaustive =
- enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate()));
+ let is_non_exhaustive = enum_defs
+ .iter()
+ .any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db())));
let mut n_arms = 1;
let variants_of_enums: Vec<Vec<ExtendedVariant>> = enum_defs
@@ -145,7 +147,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
let has_hidden_variants = variants_of_enums
.iter()
.flatten()
- .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
+ .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db())));
let missing_pats = variants_of_enums
.into_iter()
@@ -154,7 +156,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
.map(|variants| {
let is_hidden = variants
.iter()
- .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
+ .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db())));
let patterns = variants
.into_iter()
.filter_map(|variant| build_pat(ctx, &make, module, variant, cfg));
@@ -170,15 +172,16 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
} else if let Some((enum_def, len)) =
resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref())
{
- let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
+ let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate(ctx.db()));
let variants = enum_def.variants(ctx.db());
if len.pow(variants.len() as u32) > 256 {
return None;
}
- let has_hidden_variants =
- variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
+ let has_hidden_variants = variants
+ .iter()
+ .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db())));
let variants_of_enums = vec![variants; len];
@@ -189,7 +192,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
.map(|variants| {
let is_hidden = variants
.iter()
- .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
+ .any(|variant| variant.should_be_hidden(ctx.db(), module.krate(ctx.db())));
let patterns = variants
.into_iter()
.filter_map(|variant| build_pat(ctx, &make, module, variant, cfg));
@@ -401,7 +404,7 @@ impl ExtendedVariant {
fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool {
match self {
ExtendedVariant::Variant { variant: var, .. } => {
- var.attrs(db).is_doc_hidden() && var.module(db).krate() != krate
+ var.attrs(db).is_doc_hidden() && var.module(db).krate(db) != krate
}
_ => false,
}
@@ -424,7 +427,7 @@ impl ExtendedEnum {
fn is_non_exhaustive(&self, db: &RootDatabase, krate: Crate) -> bool {
match self {
ExtendedEnum::Enum { enum_: e, .. } => {
- e.attrs(db).is_non_exhaustive() && e.module(db).krate() != krate
+ e.attrs(db).is_non_exhaustive() && e.module(db).krate(db) != krate
}
_ => false,
}
@@ -502,7 +505,7 @@ fn build_pat(
let db = ctx.db();
match var {
ExtendedVariant::Variant { variant: var, use_self } => {
- let edition = module.krate().edition(db);
+ let edition = module.krate(db).edition(db);
let path = if use_self {
make::path_from_segments(
[
diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs
index 3281adbcc3..d193e8a9d8 100644
--- a/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -260,7 +260,7 @@ fn validate_method_call_expr(
let receiver = method_call.receiver()?;
let it_type = sema.type_of_expr(&receiver)?.adjusted();
let module = sema.scope(receiver.syntax())?.module();
- let krate = module.krate();
+ let krate = module.krate(ctx.db());
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
it_type.impls_trait(sema.db, iter_trait, &[]).then_some((name_ref, arg_expr))
diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
index bb6a10d40b..cc2bf81749 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -114,7 +114,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
proposed_imports.sort_by_key(|import| {
Reverse(relevance_score(ctx, import, expected.as_ref(), current_module.as_ref()))
});
- let edition = current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
+ let edition =
+ current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT);
let group_label = group_label(import_assets.import_candidate());
for import in proposed_imports {
@@ -316,11 +317,11 @@ fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Modu
let distinct_length = current_path.len() + item_path.len() - 2 * prefix_length;
// cost of importing from another crate
- let crate_boundary_cost = if current.krate() == item.krate() {
+ let crate_boundary_cost = if current.krate(db) == item.krate(db) {
0
- } else if item.krate().origin(db).is_local() {
+ } else if item.krate(db).origin(db).is_local() {
2
- } else if item.krate().is_builtin(db) {
+ } else if item.krate(db).is_builtin(db) {
3
} else {
4
diff --git a/crates/ide-assists/src/handlers/bind_unused_param.rs b/crates/ide-assists/src/handlers/bind_unused_param.rs
index 1b24f7fe7f..771e80bb92 100644
--- a/crates/ide-assists/src/handlers/bind_unused_param.rs
+++ b/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -33,7 +33,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
return None;
}
- let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
+ let func = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?;
let stmt_list = func.body()?.stmt_list()?;
let l_curly_range = stmt_list.l_curly_token()?.text_range();
let r_curly_range = stmt_list.r_curly_token()?.text_range();
@@ -179,4 +179,16 @@ fn foo($0_x: i32, y: i32) {}
"#,
);
}
+
+ #[test]
+ fn not_applicable_closure() {
+ check_assist_not_applicable(
+ bind_unused_param,
+ r#"
+fn foo() {
+ let _ = |$0x| 2;
+}
+"#,
+ );
+ }
}
diff --git a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index 2ad1336237..1ae5f64917 100644
--- a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
+++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -329,7 +329,7 @@ fn augment_references_with_imports(
) -> Vec<FileReferenceWithImport> {
let mut visited_modules = FxHashSet::default();
- let edition = target_module.krate().edition(ctx.db());
+ let edition = target_module.krate(ctx.db()).edition(ctx.db());
references
.into_iter()
.filter_map(|FileReference { range, name, .. }| {
@@ -345,8 +345,9 @@ fn augment_references_with_imports(
ImportScope::find_insert_use_container(name.syntax(), &ctx.sema).and_then(
|import_scope| {
- let cfg =
- ctx.config.find_path_config(ctx.sema.is_nightly(target_module.krate()));
+ let cfg = ctx.config.find_path_config(
+ ctx.sema.is_nightly(target_module.krate(ctx.sema.db)),
+ );
let path = ref_module
.find_use_path(
ctx.sema.db,
diff --git a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index 156286d564..d64e9ceda2 100644
--- a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -1,11 +1,8 @@
-use hir::{
- Name,
- sym::{self},
-};
+use hir::{Name, sym};
use ide_db::{famous_defs::FamousDefs, syntax_helpers::suggest_name};
use syntax::{
AstNode,
- ast::{self, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
+ ast::{self, HasAttrs, HasLoopBody, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
syntax_editor::Position,
};
@@ -82,6 +79,18 @@ pub(crate) fn convert_for_loop_to_while_let(
Some(iterable),
);
let indent = IndentLevel::from_node(for_loop.syntax());
+
+ if let Some(label) = for_loop.label() {
+ let label = label.syntax().clone_for_update();
+ editor.insert(Position::before(for_loop.syntax()), make.whitespace(" "));
+ editor.insert(Position::before(for_loop.syntax()), label);
+ }
+ crate::utils::insert_attributes(
+ for_loop.syntax(),
+ &mut editor,
+ for_loop.attrs().map(|it| it.clone_for_update()),
+ );
+
editor.insert(
Position::before(for_loop.syntax()),
make::tokens::whitespace(format!("\n{indent}").as_str()),
@@ -150,7 +159,7 @@ fn impls_core_iter(sema: &hir::Semantics<'_, ide_db::RootDatabase>, iterable: &a
let module = sema.scope(iterable.syntax())?.module();
- let krate = module.krate();
+ let krate = module.krate(sema.db);
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
cov_mark::hit!(test_already_impls_iterator);
Some(it_typ.impls_trait(sema.db, iter_trait, &[]))
@@ -187,6 +196,56 @@ fn main() {
}
#[test]
+ fn each_to_for_with_label() {
+ check_assist(
+ convert_for_loop_to_while_let,
+ r"
+fn main() {
+ let mut x = vec![1, 2, 3];
+ 'a: for $0v in x {
+ v *= 2;
+ break 'a;
+ };
+}",
+ r"
+fn main() {
+ let mut x = vec![1, 2, 3];
+ let mut tmp = x.into_iter();
+ 'a: while let Some(v) = tmp.next() {
+ v *= 2;
+ break 'a;
+ };
+}",
+ )
+ }
+
+ #[test]
+ fn each_to_for_with_attributes() {
+ check_assist(
+ convert_for_loop_to_while_let,
+ r"
+fn main() {
+ let mut x = vec![1, 2, 3];
+ #[allow(unused)]
+ #[deny(unsafe_code)]
+ for $0v in x {
+ v *= 2;
+ };
+}",
+ r"
+fn main() {
+ let mut x = vec![1, 2, 3];
+ let mut tmp = x.into_iter();
+ #[allow(unused)]
+ #[deny(unsafe_code)]
+ while let Some(v) = tmp.next() {
+ v *= 2;
+ };
+}",
+ )
+ }
+
+ #[test]
fn each_to_for_for_in_range() {
check_assist(
convert_for_loop_to_while_let,
diff --git a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
index 7d8b763d8b..6a74d21451 100644
--- a/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
+++ b/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
@@ -64,7 +64,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
let tail_expr = from_fn.body()?.tail_expr()?;
if resolve_target_trait(&ctx.sema, &impl_)?
- != FamousDefs(&ctx.sema, module.krate()).core_convert_From()?
+ != FamousDefs(&ctx.sema, module.krate(ctx.db())).core_convert_From()?
{
return None;
}
diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs
index 8f02d28b82..e330102423 100644
--- a/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -39,11 +39,11 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
let module = ctx.sema.scope(impl_.syntax())?.module();
let trait_ = resolve_target_trait(&ctx.sema, &impl_)?;
- if trait_ != FamousDefs(&ctx.sema, module.krate()).core_convert_Into()? {
+ if trait_ != FamousDefs(&ctx.sema, module.krate(ctx.db())).core_convert_Into()? {
return None;
}
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
let src_type_path = {
let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?;
@@ -53,7 +53,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
};
mod_path_to_ast(
&module.find_path(ctx.db(), src_type_def, cfg)?,
- module.krate().edition(ctx.db()),
+ module.krate(ctx.db()).edition(ctx.db()),
)
};
diff --git a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index c8a244b213..2eea4f71ed 100644
--- a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -3,7 +3,7 @@ use ide_db::famous_defs::FamousDefs;
use stdx::format_to;
use syntax::{
AstNode,
- ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, make},
+ ast::{self, HasArgList, HasLoopBody, edit_in_place::Indent, syntax_factory::SyntaxFactory},
};
use crate::{AssistContext, AssistId, Assists};
@@ -57,18 +57,22 @@ pub(crate) fn convert_iter_for_each_to_for(
"Replace this `Iterator::for_each` with a for loop",
range,
|builder| {
+ let make = SyntaxFactory::with_mappings();
let indent =
stmt.as_ref().map_or_else(|| method.indent_level(), ast::ExprStmt::indent_level);
let block = match body {
- ast::Expr::BlockExpr(block) => block,
- _ => make::block_expr(Vec::new(), Some(body)),
- }
- .clone_for_update();
+ ast::Expr::BlockExpr(block) => block.clone_for_update(),
+ _ => make.block_expr(Vec::new(), Some(body)),
+ };
block.reindent_to(indent);
- let expr_for_loop = make::expr_for_loop(param, receiver, block);
- builder.replace(range, expr_for_loop.to_string())
+ let expr_for_loop = make.expr_for_loop(param, receiver, block);
+
+ let target_node = stmt.as_ref().map_or(method.syntax(), AstNode::syntax);
+ let mut editor = builder.make_editor(target_node);
+ editor.replace(target_node, expr_for_loop.syntax());
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
},
)
}
@@ -186,7 +190,7 @@ fn impls_core_iter(sema: &hir::Semantics<'_, ide_db::RootDatabase>, iterable: &a
let module = sema.scope(iterable.syntax())?.module();
- let krate = module.krate();
+ let krate = module.krate(sema.db);
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
cov_mark::hit!(test_already_impls_iterator);
Some(it_typ.impls_trait(sema.db, iter_trait, &[]))
@@ -214,7 +218,7 @@ fn validate_method_call_expr(
let it_type = sema.type_of_expr(&receiver)?.adjusted();
let module = sema.scope(receiver.syntax())?.module();
- let krate = module.krate();
+ let krate = module.krate(ctx.db());
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
it_type.impls_trait(sema.db, iter_trait, &[]).then_some((expr, receiver))
diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
index 9876e14203..0e5e6185d0 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
@@ -199,7 +199,8 @@ fn augment_references_with_imports(
{
visited_modules.insert(ref_module);
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(ref_module.krate()));
+ let cfg =
+ ctx.config.find_path_config(ctx.sema.is_nightly(ref_module.krate(ctx.sema.db)));
let import_scope =
ImportScope::find_insert_use_container(new_name.syntax(), &ctx.sema);
let path = ref_module
@@ -211,7 +212,10 @@ fn augment_references_with_imports(
)
.map(|mod_path| {
make::path_concat(
- mod_path_to_ast(&mod_path, target_module.krate().edition(ctx.db())),
+ mod_path_to_ast(
+ &mod_path,
+ target_module.krate(ctx.db()).edition(ctx.db()),
+ ),
make::path_from_text(struct_name),
)
});
diff --git a/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/crates/ide-assists/src/handlers/convert_while_to_loop.rs
index dbe3ee0ed6..9fd8b4b315 100644
--- a/crates/ide-assists/src/handlers/convert_while_to_loop.rs
+++ b/crates/ide-assists/src/handlers/convert_while_to_loop.rs
@@ -1,6 +1,5 @@
use std::iter;
-use either::Either;
use ide_db::syntax_helpers::node_ext::is_pattern_cond;
use syntax::{
AstNode, T,
@@ -9,6 +8,7 @@ use syntax::{
edit::{AstNodeEdit, IndentLevel},
make,
},
+ syntax_editor::{Element, Position},
};
use crate::{
@@ -44,43 +44,53 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
let while_body = while_expr.loop_body()?;
let while_cond = while_expr.condition()?;
+ let l_curly = while_body.stmt_list()?.l_curly_token()?;
let target = while_expr.syntax().text_range();
acc.add(
AssistId::refactor_rewrite("convert_while_to_loop"),
"Convert while to loop",
target,
- |edit| {
+ |builder| {
+ let mut edit = builder.make_editor(while_expr.syntax());
let while_indent_level = IndentLevel::from_node(while_expr.syntax());
let break_block = make::block_expr(
iter::once(make::expr_stmt(make::expr_break(None, None)).into()),
None,
)
- .indent(while_indent_level);
- let block_expr = if is_pattern_cond(while_cond.clone()) {
- let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
+ .indent(IndentLevel(1));
+
+ edit.replace_all(
+ while_kw.syntax_element()..=while_cond.syntax().syntax_element(),
+ vec![make::token(T![loop]).syntax_element()],
+ );
+
+ if is_pattern_cond(while_cond.clone()) {
+ let then_branch = while_body.reset_indent().indent(IndentLevel(1));
+ let if_expr = make::expr_if(while_cond, then_branch, Some(break_block.into()));
let stmts = iter::once(make::expr_stmt(if_expr.into()).into());
- make::block_expr(stmts, None)
+ let block_expr = make::block_expr(stmts, None);
+ edit.replace(while_body.syntax(), block_expr.indent(while_indent_level).syntax());
} else {
let if_cond = invert_boolean_expression_legacy(while_cond);
- let if_expr = make::expr_if(if_cond, break_block, None).syntax().clone().into();
- let elements = while_body.stmt_list().map_or_else(
- || Either::Left(iter::empty()),
- |stmts| {
- Either::Right(stmts.syntax().children_with_tokens().filter(|node_or_tok| {
- // Filter out the trailing expr
- !node_or_tok
- .as_node()
- .is_some_and(|node| ast::Expr::can_cast(node.kind()))
- }))
- },
+ let if_expr = make::expr_if(if_cond, break_block, None).indent(while_indent_level);
+ if !while_body.syntax().text().contains_char('\n') {
+ edit.insert(
+ Position::after(&l_curly),
+ make::tokens::whitespace(&format!("\n{while_indent_level}")),
+ );
+ }
+ edit.insert_all(
+ Position::after(&l_curly),
+ vec![
+ make::tokens::whitespace(&format!("\n{}", while_indent_level + 1)).into(),
+ if_expr.syntax().syntax_element(),
+ ],
);
- make::hacky_block_expr(iter::once(if_expr).chain(elements), while_body.tail_expr())
};
- let replacement = make::expr_loop(block_expr.indent(while_indent_level));
- edit.replace(target, replacement.syntax().text())
+ builder.add_file_edits(ctx.vfs_file_id(), edit);
},
)
}
@@ -116,6 +126,110 @@ fn main() {
}
#[test]
+ fn convert_with_label() {
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ 'x: while$0 cond {
+ foo();
+ break 'x
+ }
+}
+"#,
+ r#"
+fn main() {
+ 'x: loop {
+ if !cond {
+ break;
+ }
+ foo();
+ break 'x
+ }
+}
+"#,
+ );
+
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ 'x: while$0 let Some(x) = cond {
+ foo();
+ break 'x
+ }
+}
+"#,
+ r#"
+fn main() {
+ 'x: loop {
+ if let Some(x) = cond {
+ foo();
+ break 'x
+ } else {
+ break;
+ }
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_with_attributes() {
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ #[allow(unused)]
+ while$0 cond {
+ foo();
+ break 'x
+ }
+}
+"#,
+ r#"
+fn main() {
+ #[allow(unused)]
+ loop {
+ if !cond {
+ break;
+ }
+ foo();
+ break 'x
+ }
+}
+"#,
+ );
+
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ #[allow(unused)]
+ #[deny(unsafe_code)]
+ while$0 let Some(x) = cond {
+ foo();
+ }
+}
+"#,
+ r#"
+fn main() {
+ #[allow(unused)]
+ #[deny(unsafe_code)]
+ loop {
+ if let Some(x) = cond {
+ foo();
+ } else {
+ break;
+ }
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn convert_busy_wait() {
check_assist(
convert_while_to_loop,
@@ -186,6 +300,76 @@ fn main() {
}
#[test]
+ fn indentation() {
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ {
+ {
+ while$0 cond {
+ foo(
+ "xxx",
+ );
+ }
+ }
+ }
+}
+"#,
+ r#"
+fn main() {
+ {
+ {
+ loop {
+ if !cond {
+ break;
+ }
+ foo(
+ "xxx",
+ );
+ }
+ }
+ }
+}
+"#,
+ );
+
+ check_assist(
+ convert_while_to_loop,
+ r#"
+fn main() {
+ {
+ {
+ while$0 let Some(_) = foo() {
+ bar(
+ "xxx",
+ );
+ }
+ }
+ }
+}
+"#,
+ r#"
+fn main() {
+ {
+ {
+ loop {
+ if let Some(_) = foo() {
+ bar(
+ "xxx",
+ );
+ } else {
+ break;
+ }
+ }
+ }
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn ignore_cursor_in_body() {
check_assist_not_applicable(
convert_while_to_loop,
diff --git a/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 46f210804d..bb5d112210 100644
--- a/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -88,13 +88,14 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None };
let module = ctx.sema.scope(ident_pat.syntax())?.module();
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db())));
let struct_def = hir::ModuleDef::from(struct_type);
let kind = struct_type.kind(ctx.db());
let struct_def_path = module.find_path(ctx.db(), struct_def, cfg)?;
let is_non_exhaustive = struct_def.attrs(ctx.db())?.is_non_exhaustive();
- let is_foreign_crate = struct_def.module(ctx.db()).is_some_and(|m| m.krate() != module.krate());
+ let is_foreign_crate =
+ struct_def.module(ctx.db()).is_some_and(|m| m.krate(ctx.db()) != module.krate(ctx.db()));
let fields = struct_type.fields(ctx.db());
let n_fields = fields.len();
@@ -148,7 +149,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
names_in_scope,
need_record_field_name,
is_ref,
- edition: module.krate().edition(ctx.db()),
+ edition: module.krate(ctx.db()).edition(ctx.db()),
})
}
diff --git a/crates/ide-assists/src/handlers/expand_glob_import.rs b/crates/ide-assists/src/handlers/expand_glob_import.rs
index 4b6d0b3785..7eca4d3f2a 100644
--- a/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -152,8 +152,10 @@ fn build_expanded_import(
(false, current_module)
} else {
match get_export_visibility_kind(&use_item) {
- VisibilityKind::Pub => (true, current_module.krate().root_module()),
- VisibilityKind::PubCrate => (false, current_module.krate().root_module()),
+ VisibilityKind::Pub => (true, current_module.krate(ctx.db()).root_module(ctx.db())),
+ VisibilityKind::PubCrate => {
+ (false, current_module.krate(ctx.db()).root_module(ctx.db()))
+ }
_ => (false, current_module),
}
};
@@ -167,7 +169,7 @@ fn build_expanded_import(
let names_to_import = find_names_to_import(filtered_defs, imported_defs);
let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
let path = make::ext::ident_path(
- &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(),
+ &n.display(ctx.db(), current_module.krate(ctx.db()).edition(ctx.db())).to_string(),
);
make::use_tree(path, None, None, false)
}))
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 44d020a1b4..4b7314be46 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -206,10 +206,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
{
let scope = builder.make_import_scope_mut(scope);
let control_flow_enum =
- FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow();
+ FamousDefs(&ctx.sema, module.krate(ctx.db())).core_ops_ControlFlow();
if let Some(control_flow_enum) = control_flow_enum {
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg =
+ ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
let mod_path = module.find_use_path(
ctx.sema.db,
ModuleDef::from(control_flow_enum),
diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 2cec3296c8..386652a422 100644
--- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -400,7 +400,8 @@ fn process_references(
let segment = builder.make_mut(segment);
let scope_node = builder.make_syntax_mut(scope_node);
if !visited_modules.contains(&module) {
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg =
+ ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
let mod_path = module.find_use_path(
ctx.sema.db,
*enum_module_def,
diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs
index 55de537deb..0fd8057a39 100644
--- a/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -59,7 +59,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
let (vis_owner, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?;
- let missing_visibility = if current_module.krate() == target_module.krate() {
+ let missing_visibility = if current_module.krate(ctx.db()) == target_module.krate(ctx.db()) {
make::visibility_pub_crate()
} else {
make::visibility_pub()
@@ -70,7 +70,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
Some(name) => {
format!(
"Change visibility of {} to {missing_visibility}",
- name.display(ctx.db(), current_module.krate().edition(ctx.db()))
+ name.display(ctx.db(), current_module.krate(ctx.db()).edition(ctx.db()))
)
}
};
diff --git a/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
index 056edb00b6..b4a17c376a 100644
--- a/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
@@ -75,7 +75,7 @@ fn existing_default_impl(
) -> Option<()> {
let variant = sema.to_def(variant)?;
let enum_ = variant.parent_enum(sema.db);
- let krate = enum_.module(sema.db).krate();
+ let krate = enum_.module(sema.db).krate(sema.db);
let default_trait = FamousDefs(sema, krate).core_default_Default()?;
let enum_type = enum_.ty(sema.db);
diff --git a/crates/ide-assists/src/handlers/generate_default_from_new.rs b/crates/ide-assists/src/handlers/generate_default_from_new.rs
index 47233fb399..48400d436a 100644
--- a/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -137,7 +137,7 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
};
let ty = impl_def.self_ty(db);
- let krate = impl_def.module(db).krate();
+ let krate = impl_def.module(db).krate(ctx.db());
let default = FamousDefs(&ctx.sema, krate).core_default_Default();
let default_trait = match default {
Some(value) => value,
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index b2e791abf7..c1eb1a74ec 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -57,7 +57,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
let strukt_name = strukt.name()?;
let current_module = ctx.sema.scope(strukt.syntax())?.module();
- let current_edition = current_module.krate().edition(ctx.db());
+ let current_edition = current_module.krate(ctx.db()).edition(ctx.db());
let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() {
Some(field) => {
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index e87dde5b8e..921f04f2a5 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -14,15 +14,15 @@ use ide_db::{
};
use itertools::Itertools;
use syntax::{
- AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
+ AstNode, Edition, SmolStr, SyntaxElement, SyntaxKind, ToSmolStr,
ast::{
self, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs,
HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
WherePred,
edit::{self, AstNodeEdit},
- make,
+ syntax_factory::SyntaxFactory,
},
- ted::{self, Position},
+ syntax_editor::SyntaxEditor,
};
// Assist: generate_delegate_trait
@@ -124,7 +124,7 @@ impl Field {
let db = ctx.sema.db;
let module = ctx.sema.file_to_module_def(ctx.vfs_file_id())?;
- let edition = module.krate().edition(ctx.db());
+ let edition = module.krate(ctx.db()).edition(ctx.db());
let (name, range, ty) = match f {
Either::Left(f) => {
@@ -169,10 +169,15 @@ enum Delegee {
}
impl Delegee {
+ fn trait_(&self) -> &hir::Trait {
+ match self {
+ Delegee::Bound(it) | Delegee::Impls(it, _) => it,
+ }
+ }
+
fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
let mut s = String::new();
-
- let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
+ let it = self.trait_();
for m in it.module(db).path_to_root(db).iter().rev() {
if let Some(name) = m.name(db) {
@@ -201,15 +206,12 @@ impl Struct {
let db = ctx.db();
for (index, delegee) in field.impls.iter().enumerate() {
- let trait_ = match delegee {
- Delegee::Bound(b) => b,
- Delegee::Impls(i, _) => i,
- };
+ let trait_ = delegee.trait_();
// Skip trait that has `Self` type, which cannot be delegated
//
// See [`test_self_ty`]
- if has_self_type(*trait_, ctx).is_some() {
+ if has_self_type(*trait_, ctx) {
continue;
}
@@ -254,9 +256,10 @@ fn generate_impl(
delegee: &Delegee,
edition: Edition,
) -> Option<ast::Impl> {
+ let make = SyntaxFactory::without_mappings();
let db = ctx.db();
let ast_strukt = &strukt.strukt;
- let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string()));
+ let strukt_ty = make.ty_path(make.ident_path(&strukt.name.to_string())).into();
let strukt_params = ast_strukt.generic_param_list();
match delegee {
@@ -264,7 +267,7 @@ fn generate_impl(
let bound_def = ctx.sema.source(delegee.to_owned())?.value;
let bound_params = bound_def.generic_param_list();
- let delegate = make::impl_trait(
+ let delegate = make.impl_trait(
None,
delegee.is_unsafe(db),
bound_params.clone(),
@@ -272,33 +275,28 @@ fn generate_impl(
strukt_params.clone(),
strukt_params.map(|params| params.to_generic_args()),
delegee.is_auto(db),
- make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
+ make.ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
strukt_ty,
bound_def.where_clause(),
ast_strukt.where_clause(),
None,
- )
- .clone_for_update();
+ );
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
let qualified_path_type =
- make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
+ make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
- let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
- if let Some(ai) = bound_def.assoc_item_list() {
+ // Collect assoc items
+ let assoc_items: Option<Vec<ast::AssocItem>> = bound_def.assoc_item_list().map(|ai| {
ai.assoc_items()
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
- .for_each(|item| {
- let assoc = process_assoc_item(
- item.clone_for_update(),
- qualified_path_type.clone(),
- field_name,
- );
- if let Some(assoc) = assoc {
- delegate_assoc_items.add_item(assoc);
- }
- });
- };
+ .filter_map(|item| {
+ process_assoc_item(item, qualified_path_type.clone(), field_name)
+ })
+ .collect()
+ });
+
+ let delegate = finalize_delegate(&make, &delegate, assoc_items, false)?;
let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
let source_scope = ctx.sema.scope(bound_def.syntax())?;
@@ -324,7 +322,7 @@ fn generate_impl(
.and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args));
(field_ty, where_clause)
}
- None => (field_ty.clone_for_update(), None),
+ None => (field_ty.clone(), None),
};
// 2) Handle instantiated generics in `field_ty`.
@@ -347,38 +345,38 @@ fn generate_impl(
);
// 2.2) Generate generic args applied on impl.
- let transform_args = generate_args_for_impl(
+ let (transform_args, trait_gen_params) = generate_args_for_impl(
old_impl_params,
&old_impl.self_ty()?,
&field_ty,
- &trait_gen_params,
+ trait_gen_params,
&old_impl_trait_args,
);
// 2.3) Instantiate generics with `transform_impl`, this step also
// remove unused params.
- let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| {
- let trait_args = &mut trait_args.clone_for_update();
- if let Some(new_args) = transform_impl(
- ctx,
- ast_strukt,
- &old_impl,
- &transform_args,
- trait_args.clone_subtree(),
- ) {
- *trait_args = new_args.clone_subtree();
- Some(new_args)
- } else {
- None
- }
- });
+ let trait_gen_args =
+ old_impl.trait_()?.generic_arg_list().and_then(|mut trait_args| {
+ let trait_args = &mut trait_args;
+ if let Some(new_args) = transform_impl(
+ ctx,
+ ast_strukt,
+ &old_impl,
+ &transform_args,
+ trait_args.clone_subtree(),
+ ) {
+ *trait_args = new_args.clone_subtree();
+ Some(new_args)
+ } else {
+ None
+ }
+ });
let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
- let path_type =
- make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
+ let path_type = make.ty(&trait_.name(db).display_no_db(edition).to_smolstr());
let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
// 3) Generate delegate trait impl
- let delegate = make::impl_trait(
+ let delegate = make.impl_trait(
None,
trait_.is_unsafe(db),
trait_gen_params,
@@ -388,34 +386,27 @@ fn generate_impl(
trait_.is_auto(db),
path_type,
strukt_ty,
- old_impl.where_clause().map(|wc| wc.clone_for_update()),
+ old_impl.where_clause(),
ty_where_clause,
None,
- )
- .clone_for_update();
+ );
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
let qualified_path_type =
- make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
-
- // 4) Transform associated items in delegte trait impl
- let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
- for item in old_impl
- .get_or_create_assoc_item_list()
- .assoc_items()
- .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
- {
- let item = item.clone_for_update();
- let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
-
- let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
- delegate_assoc_items.add_item(assoc);
- }
+ make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
- // 5) Remove useless where clauses
- if let Some(wc) = delegate.where_clause() {
- remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
- }
- Some(delegate)
+ // 4) Transform associated items in delegate trait impl
+ let assoc_items: Option<Vec<ast::AssocItem>> = old_impl.assoc_item_list().map(|ail| {
+ ail.assoc_items()
+ .filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
+ .filter_map(|item| {
+ let item =
+ transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
+ process_assoc_item(item, qualified_path_type.clone(), field_name)
+ })
+ .collect()
+ });
+
+ finalize_delegate(&make, &delegate, assoc_items, true)
}
}
}
@@ -446,6 +437,35 @@ fn transform_impl<N: ast::AstNode>(
N::cast(transform.apply(syntax.syntax()))
}
+/// Extracts the name from a generic parameter.
+fn generic_param_name(param: &ast::GenericParam) -> Option<String> {
+ match param {
+ ast::GenericParam::TypeParam(t) => t.name().map(|n| n.to_string()),
+ ast::GenericParam::ConstParam(c) => c.name().map(|n| n.to_string()),
+ ast::GenericParam::LifetimeParam(l) => l.lifetime().map(|lt| lt.to_string()),
+ }
+}
+
+/// Filters generic params, keeping only those whose names are not in `names_to_remove`.
+fn filter_generic_params(
+ gpl: ast::GenericParamList,
+ names_to_remove: &FxHashSet<String>,
+) -> Option<ast::GenericParamList> {
+ let remaining_params: Vec<_> = gpl
+ .generic_params()
+ .filter(|param| {
+ generic_param_name(param).is_none_or(|name| !names_to_remove.contains(&name))
+ })
+ .collect();
+
+ if remaining_params.is_empty() {
+ None
+ } else {
+ let make = SyntaxFactory::without_mappings();
+ Some(make.generic_param_list(remaining_params))
+ }
+}
+
fn remove_instantiated_params(
self_ty: &ast::Type,
old_impl_params: Option<GenericParamList>,
@@ -454,10 +474,8 @@ fn remove_instantiated_params(
match self_ty {
ast::Type::PathType(path_type) => {
old_impl_params.and_then(|gpl| {
- // Remove generic parameters in field_ty (which is instantiated).
- let new_gpl = gpl.clone_for_update();
-
- path_type
+ // Collect generic args that should be removed (instantiated params)
+ let args_to_remove: FxHashSet<String> = path_type
.path()?
.segments()
.filter_map(|seg| seg.generic_arg_list())
@@ -466,16 +484,25 @@ fn remove_instantiated_params(
// it shouldn't be removed now, which will be instantiated in
// later `path_transform`
.filter(|arg| !old_trait_args.contains(&arg.to_string()))
- .for_each(|arg| new_gpl.remove_generic_arg(&arg));
- (new_gpl.generic_params().count() > 0).then_some(new_gpl)
+ .map(|arg| arg.to_string())
+ .collect();
+
+ filter_generic_params(gpl, &args_to_remove)
})
}
_ => old_impl_params,
}
}
-fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: ast::WhereClause) {
- let live_generics = [trait_ty, self_ty]
+fn remove_useless_where_clauses(editor: &mut SyntaxEditor, delegate: &ast::Impl) {
+ let Some(wc) = delegate.where_clause() else {
+ return;
+ };
+ let (Some(trait_ty), Some(self_ty)) = (delegate.trait_(), delegate.self_ty()) else {
+ return;
+ };
+
+ let live_generics = [&trait_ty, &self_ty]
.into_iter()
.flat_map(|ty| ty.generic_arg_list())
.flat_map(|gal| gal.generic_args())
@@ -484,34 +511,76 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a
// Keep where-clauses that have generics after substitution, and remove the
// rest.
- let has_live_generics = |pred: &WherePred| {
+ let has_no_live_generics = |pred: &WherePred| {
pred.syntax()
.descendants_with_tokens()
.filter_map(|e| e.into_token())
.any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string()))
.not()
};
- wc.predicates().filter(has_live_generics).for_each(|pred| wc.remove_predicate(pred));
-
- if wc.predicates().count() == 0 {
- // Remove useless whitespaces
- [syntax::Direction::Prev, syntax::Direction::Next]
- .into_iter()
- .flat_map(|dir| {
- wc.syntax()
- .siblings_with_tokens(dir)
- .skip(1)
- .take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE)
- })
- .for_each(ted::remove);
- ted::insert(
- ted::Position::after(wc.syntax()),
- NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
- );
- // Remove where clause
- ted::remove(wc.syntax());
+ let predicates_to_remove: Vec<_> = wc.predicates().filter(has_no_live_generics).collect();
+ let remaining_predicates = wc.predicates().count() - predicates_to_remove.len();
+
+ if remaining_predicates == 0 {
+ // Remove the entire where clause
+ editor.delete(wc.syntax().clone());
+ } else {
+ // Remove only the useless predicates
+ for pred in predicates_to_remove {
+ // Also remove the comma before or after the predicate
+ if let Some(previous) = pred.syntax().prev_sibling() {
+ // Remove from after previous sibling to predicate (inclusive)
+ if let Some(start) = previous.next_sibling_or_token() {
+ let end: SyntaxElement = pred.syntax().clone().into();
+ editor.delete_all(start..=end);
+ }
+ } else if let Some(next) = pred.syntax().next_sibling() {
+ // Remove from predicate to before next sibling (exclusive)
+ if let Some(end) = next.prev_sibling_or_token() {
+ let start: SyntaxElement = pred.syntax().clone().into();
+ editor.delete_all(start..=end);
+ }
+ } else {
+ editor.delete(pred.syntax().clone());
+ }
+ }
+ }
+}
+
+/// Finalize the delegate impl by:
+/// 1. Replacing the assoc_item_list with new items (if any)
+/// 2. Removing useless where clauses
+fn finalize_delegate(
+ make: &SyntaxFactory,
+ delegate: &ast::Impl,
+ assoc_items: Option<Vec<ast::AssocItem>>,
+ remove_where_clauses: bool,
+) -> Option<ast::Impl> {
+ let has_items = assoc_items.as_ref().is_some_and(|items| !items.is_empty());
+
+ if !has_items && !remove_where_clauses {
+ return Some(delegate.clone());
}
+
+ let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
+
+ // 1. Replace assoc_item_list if we have new items
+ if let Some(items) = assoc_items
+ && !items.is_empty()
+ {
+ let new_assoc_item_list = make.assoc_item_list(items);
+ if let Some(old_list) = delegate.assoc_item_list() {
+ editor.replace(old_list.syntax(), new_assoc_item_list.syntax());
+ }
+ }
+
+ // 2. Remove useless where clauses
+ if remove_where_clauses {
+ remove_useless_where_clauses(&mut editor, delegate);
+ }
+
+ ast::Impl::cast(editor.finish().new_root().clone())
}
// Generate generic args that should be apply to current impl.
@@ -524,10 +593,13 @@ fn generate_args_for_impl(
old_impl_gpl: Option<GenericParamList>,
self_ty: &ast::Type,
field_ty: &ast::Type,
- trait_params: &Option<GenericParamList>,
+ trait_params: Option<GenericParamList>,
old_trait_args: &FxHashSet<String>,
-) -> Option<ast::GenericArgList> {
- let old_impl_args = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args())?;
+) -> (Option<ast::GenericArgList>, Option<GenericParamList>) {
+ let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else {
+ return (None, trait_params);
+ };
+
// Create pairs of the args of `self_ty` and corresponding `field_ty` to
// form the substitution list
let mut arg_substs = FxHashMap::default();
@@ -542,6 +614,8 @@ fn generate_args_for_impl(
}
}
+ let mut params_to_remove = FxHashSet::default();
+
let args = old_impl_args
.map(|old_arg| {
arg_substs.get(&old_arg.to_string()).map_or_else(
@@ -549,14 +623,18 @@ fn generate_args_for_impl(
|replace_with| {
// The old_arg will be replaced, so it becomes redundant
if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) {
- trait_params.as_ref().unwrap().remove_generic_arg(&old_arg)
+ params_to_remove.insert(old_arg.to_string());
}
replace_with.clone()
},
)
})
.collect_vec();
- args.is_empty().not().then(|| make::generic_arg_list(args))
+
+ let make = SyntaxFactory::without_mappings();
+ let result = args.is_empty().not().then(|| make.generic_arg_list(args, false));
+ let trait_params = trait_params.and_then(|gpl| filter_generic_params(gpl, &params_to_remove));
+ (result, trait_params)
}
fn rename_strukt_args<N>(
@@ -570,41 +648,37 @@ where
{
let hir_strukt = ctx.sema.to_struct_def(strukt)?;
let hir_adt = hir::Adt::from(hir_strukt);
-
- let item = item.clone_for_update();
let scope = ctx.sema.scope(item.syntax())?;
let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
N::cast(transform.apply(item.syntax()))
}
-fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
- let trait_source = ctx.sema.source(trait_)?.value;
- trait_source
- .syntax()
- .descendants_with_tokens()
- .filter_map(|e| e.into_token())
- .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
- .map(|_| ())
+fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> bool {
+ ctx.sema
+ .source(trait_)
+ .and_then(|src| {
+ src.value
+ .syntax()
+ .descendants_with_tokens()
+ .filter_map(|e| e.into_token())
+ .find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
+ })
+ .is_some()
}
fn resolve_name_conflicts(
strukt_params: Option<ast::GenericParamList>,
old_impl_params: &Option<ast::GenericParamList>,
) -> Option<ast::GenericParamList> {
+ let make = SyntaxFactory::without_mappings();
match (strukt_params, old_impl_params) {
(Some(old_strukt_params), Some(old_impl_params)) => {
- let params = make::generic_param_list(std::iter::empty()).clone_for_update();
+ let mut new_params: Vec<ast::GenericParam> = Vec::new();
for old_strukt_param in old_strukt_params.generic_params() {
// Get old name from `strukt`
- let name = SmolStr::from(match &old_strukt_param {
- ast::GenericParam::ConstParam(c) => c.name()?.to_string(),
- ast::GenericParam::LifetimeParam(l) => {
- l.lifetime()?.lifetime_ident_token()?.to_string()
- }
- ast::GenericParam::TypeParam(t) => t.name()?.to_string(),
- });
+ let name = SmolStr::from(generic_param_name(&old_strukt_param)?);
// The new name cannot be conflicted with generics in trait, and the renamed names.
let param_list_to_names = |param_list: &GenericParamList| {
@@ -613,8 +687,9 @@ fn resolve_name_conflicts(
p => Some(p.to_string()),
})
};
+ let new_params_list = make.generic_param_list(new_params.clone());
let existing_names = param_list_to_names(old_impl_params)
- .chain(param_list_to_names(&params))
+ .chain(param_list_to_names(&new_params_list))
.collect_vec();
let mut name_generator = suggest_name::NameGenerator::new_with_names(
existing_names.iter().map(|s| s.as_str()),
@@ -623,25 +698,21 @@ fn resolve_name_conflicts(
match old_strukt_param {
ast::GenericParam::ConstParam(c) => {
if let Some(const_ty) = c.ty() {
- let const_param = make::const_param(make::name(&name), const_ty);
- params.add_generic_param(ast::GenericParam::ConstParam(
- const_param.clone_for_update(),
- ));
+ let const_param = make.const_param(make.name(&name), const_ty);
+ new_params.push(ast::GenericParam::ConstParam(const_param));
}
}
p @ ast::GenericParam::LifetimeParam(_) => {
- params.add_generic_param(p.clone_for_update());
+ new_params.push(p.clone_for_update());
}
ast::GenericParam::TypeParam(t) => {
let type_bounds = t.type_bound_list();
- let type_param = make::type_param(make::name(&name), type_bounds);
- params.add_generic_param(ast::GenericParam::TypeParam(
- type_param.clone_for_update(),
- ));
+ let type_param = make.type_param(make.name(&name), type_bounds);
+ new_params.push(ast::GenericParam::TypeParam(type_param));
}
}
}
- Some(params)
+ Some(make.generic_param_list(new_params))
}
(Some(old_strukt_gpl), None) => Some(old_strukt_gpl),
_ => None,
@@ -666,7 +737,8 @@ fn process_assoc_item(
}
fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
- let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
+ let make = SyntaxFactory::without_mappings();
+ let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
// We want rhs of the const assignment to be a qualified path
// The general case for const assignment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`)
@@ -674,15 +746,14 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option
// <Base as Trait<GenArgs>>::ConstName;
// FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it.
// make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
- let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
- let inner = make::item_const(
+ let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
+ let inner = make.item_const(
item.attrs(),
item.visibility(),
item.name()?,
item.ty()?,
- make::expr_path(qualified_path),
- )
- .clone_for_update();
+ make.expr_path(qualified_path),
+ );
Some(AssocItem::Const(inner))
}
@@ -692,59 +763,46 @@ fn func_assoc_item(
qual_path_ty: Path,
base_name: &str,
) -> Option<AssocItem> {
- let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
- let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
+ let make = SyntaxFactory::without_mappings();
+ let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
+ let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
let call = match item.param_list() {
// Methods and funcs should be handled separately.
// We ask if the func has a `self` param.
Some(l) => match l.self_param() {
Some(slf) => {
- let mut self_kw = make::expr_path(make::path_from_text("self"));
- self_kw = make::expr_field(self_kw, base_name);
+ let self_kw = make.expr_path(make.path_from_text("self"));
+ let self_kw = make.expr_field(self_kw, base_name).into();
let tail_expr_self = match slf.kind() {
ast::SelfParamKind::Owned => self_kw,
- ast::SelfParamKind::Ref => make::expr_ref(self_kw, false),
- ast::SelfParamKind::MutRef => make::expr_ref(self_kw, true),
+ ast::SelfParamKind::Ref => make.expr_ref(self_kw, false),
+ ast::SelfParamKind::MutRef => make.expr_ref(self_kw, true),
};
- let param_count = l.params().count();
- let args = convert_param_list_to_arg_list(l).clone_for_update();
- let pos_after_l_paren = Position::after(args.l_paren_token()?);
- if param_count > 0 {
- // Add SelfParam and a TOKEN::COMMA
- ted::insert_all_raw(
- pos_after_l_paren,
- vec![
- NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
- NodeOrToken::Token(make::token(SyntaxKind::COMMA)),
- NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
- ],
- );
- } else {
- // Add SelfParam only
- ted::insert_raw(
- pos_after_l_paren,
- NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
- );
- }
+ // Build argument list with self expression prepended
+ let other_args = convert_param_list_to_arg_list(l);
+ let all_args: Vec<ast::Expr> =
+ std::iter::once(tail_expr_self).chain(other_args.args()).collect();
+ let args = make.arg_list(all_args);
- make::expr_call(make::expr_path(qualified_path), args)
- }
- None => {
- make::expr_call(make::expr_path(qualified_path), convert_param_list_to_arg_list(l))
+ make.expr_call(make.expr_path(qualified_path), args).into()
}
+ None => make
+ .expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l))
+ .into(),
},
- None => make::expr_call(
- make::expr_path(qualified_path),
- convert_param_list_to_arg_list(make::param_list(None, Vec::new())),
- ),
- }
- .clone_for_update();
+ None => make
+ .expr_call(
+ make.expr_path(qualified_path),
+ convert_param_list_to_arg_list(make.param_list(None, Vec::new())),
+ )
+ .into(),
+ };
- let body = make::block_expr(vec![], Some(call.into())).clone_for_update();
- let func = make::fn_(
+ let body = make.block_expr(vec![], Some(call));
+ let func = make.fn_(
item.attrs(),
item.visibility(),
item.name()?,
@@ -757,35 +815,32 @@ fn func_assoc_item(
item.const_token().is_some(),
item.unsafe_token().is_some(),
item.gen_token().is_some(),
- )
- .clone_for_update();
+ );
Some(AssocItem::Fn(func.indent(edit::IndentLevel(1))))
}
fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
- let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
- let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
- let ty = make::ty_path(qualified_path);
+ let make = SyntaxFactory::without_mappings();
+ let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
+ let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
+ let ty = make.ty_path(qualified_path).into();
let ident = item.name()?.to_string();
- let alias = make::ty_alias(
- item.attrs(),
- ident.as_str(),
- item.generic_param_list(),
- None,
- item.where_clause(),
- Some((ty, None)),
- )
- .indent(edit::IndentLevel(1));
+ let alias = make
+ .ty_alias(
+ item.attrs(),
+ ident.as_str(),
+ item.generic_param_list(),
+ None,
+ item.where_clause(),
+ Some((ty, None)),
+ )
+ .indent(edit::IndentLevel(1));
Some(AssocItem::TypeAlias(alias))
}
-fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
- make::path_from_text(&format!("{qual_path_ty}::{path_expr_seg}"))
-}
-
#[cfg(test)]
mod test {
diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs
index b02e3e435c..494c87e6d1 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -57,8 +57,8 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
};
let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
- let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db())));
+ let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate(ctx.db()))?;
let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?;
let field_type = field.ty()?;
@@ -77,7 +77,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
field_name.syntax(),
deref_type_to_generate,
trait_path,
- module.krate().edition(ctx.db()),
+ module.krate(ctx.db()).edition(ctx.db()),
)
},
)
@@ -99,8 +99,8 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
};
let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
- let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
+ let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate(ctx.db()))?;
let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(trait_), cfg)?;
let field_type = field.ty()?;
@@ -118,7 +118,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
field_list_index,
deref_type_to_generate,
trait_path,
- module.krate().edition(ctx.db()),
+ module.krate(ctx.db()).edition(ctx.db()),
)
},
)
@@ -163,7 +163,7 @@ fn existing_deref_impl(
strukt: &ast::Struct,
) -> Option<DerefType> {
let strukt = sema.to_def(strukt)?;
- let krate = strukt.module(sema.db).krate();
+ let krate = strukt.module(sema.db).krate(sema.db);
let deref_trait = FamousDefs(sema, krate).core_ops_Deref()?;
let deref_mut_trait = FamousDefs(sema, krate).core_ops_DerefMut()?;
diff --git a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index 0b7eca2290..7fd94b4bed 100644
--- a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -270,6 +270,22 @@ fn foo<A: Trait, B: Trait>(a: A, b: B) -> i32 { return 42; }
}
#[test]
+ fn generate_fn_alias_unnamed_complex_types() {
+ check_assist_by_label(
+ generate_fn_type_alias,
+ r#"
+fn fo$0o(x: Vec<i32>) {}
+"#,
+ r#"
+type ${0:FooFn} = fn(Vec<i32>);
+
+fn foo(x: Vec<i32>) {}
+"#,
+ ParamStyle::Unnamed.label(),
+ );
+ }
+
+ #[test]
fn generate_fn_alias_unnamed_self() {
check_assist_by_label(
generate_fn_type_alias,
@@ -406,6 +422,22 @@ fn foo<A: Trait, B: Trait>(a: A, b: B) -> i32 { return 42; }
}
#[test]
+ fn generate_fn_alias_named_complex_types() {
+ check_assist_by_label(
+ generate_fn_type_alias,
+ r#"
+fn fo$0o(x: Vec<i32>) {}
+"#,
+ r#"
+type ${0:FooFn} = fn(x: Vec<i32>);
+
+fn foo(x: Vec<i32>) {}
+"#,
+ ParamStyle::Named.label(),
+ );
+ }
+
+ #[test]
fn generate_fn_alias_named_self() {
check_assist_by_label(
generate_fn_type_alias,
diff --git a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
index 199c85d98d..24f271ded8 100644
--- a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
@@ -121,7 +121,7 @@ fn existing_from_impl(
) -> Option<()> {
let db = sema.db;
let variant = sema.to_def(variant)?;
- let krate = variant.module(db).krate();
+ let krate = variant.module(db).krate(db);
let from_trait = FamousDefs(sema, krate).core_convert_From()?;
let interner = DbInterner::new_with(db, krate.base());
use hir::next_solver::infer::DbInternerInferExt;
diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs
index a9cf2c1bae..bd66c02b41 100644
--- a/crates/ide-assists/src/handlers/generate_function.rs
+++ b/crates/ide-assists/src/handlers/generate_function.rs
@@ -71,7 +71,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
fn_target_info(ctx, path, &call, fn_name)?;
if let Some(m) = target_module
- && !is_editable_crate(m.krate(), ctx.db())
+ && !is_editable_crate(m.krate(ctx.db()), ctx.db())
{
return None;
}
@@ -143,7 +143,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let adt = receiver_ty.as_adt()?;
let target_module = adt.module(ctx.sema.db);
- if !is_editable_crate(target_module.krate(), ctx.db()) {
+ if !is_editable_crate(target_module.krate(ctx.db()), ctx.db()) {
return None;
}
@@ -241,7 +241,7 @@ impl FunctionBuilder {
) -> Option<Self> {
let target_module =
target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
- let target_edition = target_module.krate().edition(ctx.db());
+ let target_edition = target_module.krate(ctx.db()).edition(ctx.db());
let current_module = ctx.sema.scope(call.syntax())?.module();
let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
@@ -311,7 +311,7 @@ impl FunctionBuilder {
target_module: Module,
target: GeneratedFunctionTarget,
) -> Option<Self> {
- let target_edition = target_module.krate().edition(ctx.db());
+ let target_edition = target_module.krate(ctx.db()).edition(ctx.db());
let current_module = ctx.sema.scope(call.syntax())?.module();
let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
@@ -546,7 +546,7 @@ fn assoc_fn_target_info(
let current_module = ctx.sema.scope(call.syntax())?.module();
let module = adt.module(ctx.sema.db);
let target_module = if current_module == module { None } else { Some(module) };
- if current_module.krate() != module.krate() {
+ if current_module.krate(ctx.db()) != module.krate(ctx.db()) {
return None;
}
let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
@@ -1149,7 +1149,10 @@ fn fn_arg_type(
convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
.map(|conversion| {
conversion
- .convert_type(ctx.db(), target_module.krate().to_display_target(ctx.db()))
+ .convert_type(
+ ctx.db(),
+ target_module.krate(ctx.db()).to_display_target(ctx.db()),
+ )
.to_string()
})
.or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
@@ -1235,7 +1238,7 @@ fn calculate_necessary_visibility(
let current_module = current_module.nearest_non_block_module(db);
let target_module = target_module.nearest_non_block_module(db);
- if target_module.krate() != current_module.krate() {
+ if target_module.krate(ctx.db()) != current_module.krate(ctx.db()) {
Visibility::Pub
} else if current_module.path_to_root(db).contains(&target_module) {
Visibility::None
diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs
index cd968b9710..4b923ab556 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -77,14 +77,16 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate()));
+ let cfg = ctx
+ .config
+ .find_path_config(ctx.sema.is_nightly(current_module.krate(ctx.sema.db)));
let type_path = current_module.find_path(
ctx.sema.db,
item_for_path_search(ctx.sema.db, item_in_ns)?,
cfg,
)?;
- let edition = current_module.krate().edition(ctx.db());
+ let edition = current_module.krate(ctx.db()).edition(ctx.db());
let expr = use_trivial_constructor(
ctx.sema.db,
diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index bdb42f9c1f..d3022ceda3 100644
--- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -178,7 +178,7 @@ fn make_constructors(
types: &[ast::Type],
) -> Vec<Option<ast::Expr>> {
let (db, sema) = (ctx.db(), &ctx.sema);
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
types
.iter()
.map(|ty| {
@@ -187,7 +187,7 @@ fn make_constructors(
return Some(make::expr_tuple([]).into());
}
let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into();
- let edition = module.krate().edition(db);
+ let edition = module.krate(db).edition(db);
let ty_path = module.find_path(db, item_for_path_search(db, item_in_ns)?, cfg)?;
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 5367350052..fa4f2a78c8 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -110,7 +110,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
let mut inline_refs_for_file = |file_id: EditionedFileId, refs: Vec<FileReference>| {
let file_id = file_id.file_id(ctx.db());
builder.edit_file(file_id);
- let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate());
+ let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate(ctx.db()));
let count = refs.len();
// The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some);
@@ -196,7 +196,7 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
let name_ref: ast::NameRef = ctx.find_node_at_offset()?;
let call_info = CallInfo::from_name_ref(
name_ref.clone(),
- ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate().into(),
+ ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(),
)?;
let (function, label) = match &call_info.node {
ast::CallableExpr::Call(call) => {
diff --git a/crates/ide-assists/src/handlers/inline_macro.rs b/crates/ide-assists/src/handlers/inline_macro.rs
index b09bef36ae..280bd7f2ca 100644
--- a/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/crates/ide-assists/src/handlers/inline_macro.rs
@@ -38,7 +38,7 @@ use crate::{AssistContext, AssistId, Assists};
pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?;
let macro_call = ctx.sema.to_def(&unexpanded)?;
- let target_crate_id = ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate().into();
+ let target_crate_id = ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into();
let text_range = unexpanded.syntax().text_range();
acc.add(
diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
index d8dbefd59e..495a84d62b 100644
--- a/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -42,10 +42,10 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
let resolved_call = ctx.sema.resolve_method_call(&call)?;
let current_module = ctx.sema.scope(call.syntax())?.module();
- let current_edition = current_module.krate().edition(ctx.db());
+ let current_edition = current_module.krate(ctx.db()).edition(ctx.db());
let target_module_def = ModuleDef::from(resolved_call);
let item_in_ns = ItemInNs::from(target_module_def);
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_module.krate(ctx.sema.db)));
let receiver_path = current_module.find_path(
ctx.sema.db,
item_for_path_search(ctx.sema.db, item_in_ns)?,
diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs
index 8834ad9765..b3cf296965 100644
--- a/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/crates/ide-assists/src/handlers/qualify_path.rs
@@ -82,7 +82,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
let current_edition =
- current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT);
+ current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT);
// prioritize more relevant imports
proposed_imports.sort_by_key(|import| {
Reverse(super::auto_import::relevance_score(
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 2bf4406cc6..11b3fd22fa 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -69,7 +69,7 @@ pub(crate) fn replace_derive_with_manual_impl(
let args = attr.token_tree()?;
let current_module = ctx.sema.scope(adt.syntax())?.module();
- let current_crate = current_module.krate();
+ let current_crate = current_module.krate(ctx.db());
let current_edition = current_crate.edition(ctx.db());
let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_crate));
@@ -193,7 +193,7 @@ fn impl_def_from_trait(
let target_scope = sema.scope(annotated_name.syntax())?;
// Keep assoc items of local crates even if they have #[doc(hidden)] attr.
- let ignore_items = if trait_.module(sema.db).krate().origin(sema.db).is_local() {
+ let ignore_items = if trait_.module(sema.db).krate(sema.db).origin(sema.db).is_local() {
IgnoreAssocItems::No
} else {
IgnoreAssocItems::DocHiddenAttrPresent
diff --git a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
index c85ec734c0..6ca3e26ca0 100644
--- a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
+++ b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
@@ -1,4 +1,5 @@
-use ide_db::assists::AssistId;
+use hir::Semantics;
+use ide_db::{RootDatabase, assists::AssistId, defs::Definition};
use syntax::{
AstNode,
ast::{self, Expr, HasArgList, make},
@@ -60,8 +61,8 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
format!("Replace {method_name} with {method_name_lazy}"),
call.syntax().text_range(),
|builder| {
+ let closured = into_closure(&last_arg, &method_name_lazy);
builder.replace(method_name.syntax().text_range(), method_name_lazy);
- let closured = into_closure(&last_arg);
builder.replace_ast(last_arg, closured);
},
)
@@ -79,7 +80,7 @@ fn lazy_method_name(name: &str) -> String {
}
}
-fn into_closure(param: &Expr) -> Expr {
+fn into_closure(param: &Expr, name_lazy: &str) -> Expr {
(|| {
if let ast::Expr::CallExpr(call) = param {
if call.arg_list()?.args().count() == 0 { Some(call.expr()?) } else { None }
@@ -87,7 +88,11 @@ fn into_closure(param: &Expr) -> Expr {
None
}
})()
- .unwrap_or_else(|| make::expr_closure(None, param.clone()).into())
+ .unwrap_or_else(|| {
+ let pats = (name_lazy == "and_then")
+ .then(|| make::untyped_param(make::ext::simple_ident_pat(make::name("it")).into()));
+ make::expr_closure(pats, param.clone()).into()
+ })
}
// Assist: replace_with_eager_method
@@ -146,21 +151,39 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
call.syntax().text_range(),
|builder| {
builder.replace(method_name.syntax().text_range(), method_name_eager);
- let called = into_call(&last_arg);
+ let called = into_call(&last_arg, &ctx.sema);
builder.replace_ast(last_arg, called);
},
)
}
-fn into_call(param: &Expr) -> Expr {
+fn into_call(param: &Expr, sema: &Semantics<'_, RootDatabase>) -> Expr {
(|| {
if let ast::Expr::ClosureExpr(closure) = param {
- if closure.param_list()?.params().count() == 0 { Some(closure.body()?) } else { None }
+ let mut params = closure.param_list()?.params();
+ match params.next() {
+ Some(_) if params.next().is_none() => {
+ let params = sema.resolve_expr_as_callable(param)?.params();
+ let used_param = Definition::Local(params.first()?.as_local(sema.db)?)
+ .usages(sema)
+ .at_least_one();
+ if used_param { None } else { Some(closure.body()?) }
+ }
+ None => Some(closure.body()?),
+ Some(_) => None,
+ }
} else {
None
}
})()
- .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())).into())
+ .unwrap_or_else(|| {
+ let callable = if needs_parens_in_call(param) {
+ make::expr_paren(param.clone()).into()
+ } else {
+ param.clone()
+ };
+ make::expr_call(callable, make::arg_list(Vec::new())).into()
+ })
}
fn eager_method_name(name: &str) -> Option<&str> {
@@ -177,6 +200,12 @@ fn ends_is(name: &str, end: &str) -> bool {
name.strip_suffix(end).is_some_and(|s| s.is_empty() || s.ends_with('_'))
}
+fn needs_parens_in_call(param: &Expr) -> bool {
+ let call = make::expr_call(make::ext::expr_unit(), make::arg_list(Vec::new()));
+ let callable = call.expr().expect("invalid make call");
+ param.needs_parens_in_place_of(call.syntax(), callable.syntax())
+}
+
#[cfg(test)]
mod tests {
use crate::tests::check_assist;
@@ -333,7 +362,7 @@ fn foo() {
r#"
fn foo() {
let foo = Some("foo");
- return foo.and_then(|| Some("bar"));
+ return foo.and_then(|it| Some("bar"));
}
"#,
)
@@ -347,7 +376,7 @@ fn foo() {
//- minicore: option, fn
fn foo() {
let foo = Some("foo");
- return foo.and_then$0(|| Some("bar"));
+ return foo.and_then$0(|it| Some("bar"));
}
"#,
r#"
@@ -360,6 +389,26 @@ fn foo() {
}
#[test]
+ fn replace_and_then_with_and_used_param() {
+ check_assist(
+ replace_with_eager_method,
+ r#"
+//- minicore: option, fn
+fn foo() {
+ let foo = Some("foo");
+ return foo.and_then$0(|it| Some(it.strip_suffix("bar")));
+}
+"#,
+ r#"
+fn foo() {
+ let foo = Some("foo");
+ return foo.and((|it| Some(it.strip_suffix("bar")))());
+}
+"#,
+ )
+ }
+
+ #[test]
fn replace_then_some_with_then() {
check_assist(
replace_with_lazy_method,
@@ -398,4 +447,28 @@ fn foo() {
"#,
)
}
+
+ #[test]
+ fn replace_then_with_then_some_needs_parens() {
+ check_assist(
+ replace_with_eager_method,
+ r#"
+//- minicore: option, fn, bool_impl
+struct Func { f: fn() -> i32 }
+fn foo() {
+ let foo = true;
+ let func = Func { f: || 2 };
+ let x = foo.then$0(func.f);
+}
+"#,
+ r#"
+struct Func { f: fn() -> i32 }
+fn foo() {
+ let foo = true;
+ let func = Func { f: || 2 };
+ let x = foo.then_some((func.f)());
+}
+"#,
+ )
+ }
}
diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index e9f0e190d4..009fc077ce 100644
--- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -58,7 +58,7 @@ pub(crate) fn replace_qualified_name_with_use(
let path_to_qualifier = starts_with_name_ref
.then(|| {
let mod_ = ctx.sema.scope(original_path.syntax())?.module();
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(mod_.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(mod_.krate(ctx.sema.db)));
mod_.find_use_path(ctx.sema.db, module, ctx.config.insert_use.prefix_kind, cfg)
})
.flatten();
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index d64a76eb8b..849dfa49dd 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -55,7 +55,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
path.gen_source_code(
&scope,
&mut formatter,
- ctx.config.find_path_config(ctx.sema.is_nightly(scope.module().krate())),
+ ctx.config.find_path_config(ctx.sema.is_nightly(scope.module().krate(ctx.sema.db))),
scope.krate().to_display_target(ctx.db()),
)
.ok()
diff --git a/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/crates/ide-assists/src/handlers/toggle_async_sugar.rs
index fa6fca8150..fa6ccb9a5f 100644
--- a/crates/ide-assists/src/handlers/toggle_async_sugar.rs
+++ b/crates/ide-assists/src/handlers/toggle_async_sugar.rs
@@ -132,7 +132,7 @@ pub(crate) fn desugar_async_into_impl_future(
let scope = ctx.sema.scope(function.syntax())?;
let module = scope.module();
- let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate()));
+ let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
let future_trait = FamousDefs(&ctx.sema, scope.krate()).core_future_Future()?;
let trait_path = module.find_path(ctx.db(), ModuleDef::Trait(future_trait), cfg)?;
let edition = scope.krate().edition(ctx.db());
diff --git a/crates/ide-assists/src/handlers/toggle_ignore.rs b/crates/ide-assists/src/handlers/toggle_ignore.rs
index 386625b86b..a088fb178d 100644
--- a/crates/ide-assists/src/handlers/toggle_ignore.rs
+++ b/crates/ide-assists/src/handlers/toggle_ignore.rs
@@ -1,6 +1,6 @@
use syntax::{
AstNode, AstToken,
- ast::{self, HasAttrs},
+ ast::{self, HasAttrs, edit::AstNodeEdit},
};
use crate::{AssistContext, AssistId, Assists, utils::test_related_attribute_syn};
@@ -27,13 +27,16 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
let attr: ast::Attr = ctx.find_node_at_offset()?;
let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
let attr = test_related_attribute_syn(&func)?;
+ let indent = attr.indent_level();
match has_ignore_attribute(&func) {
None => acc.add(
AssistId::refactor("toggle_ignore"),
"Ignore this test",
attr.syntax().text_range(),
- |builder| builder.insert(attr.syntax().text_range().end(), "\n#[ignore]"),
+ |builder| {
+ builder.insert(attr.syntax().text_range().end(), format!("\n{indent}#[ignore]"))
+ },
),
Some(ignore_attr) => acc.add(
AssistId::refactor("toggle_ignore"),
@@ -69,13 +72,17 @@ mod tests {
check_assist(
toggle_ignore,
r#"
- #[test$0]
- fn test() {}
+ mod indent {
+ #[test$0]
+ fn test() {}
+ }
"#,
r#"
- #[test]
- #[ignore]
- fn test() {}
+ mod indent {
+ #[test]
+ #[ignore]
+ fn test() {}
+ }
"#,
)
}
@@ -85,13 +92,17 @@ mod tests {
check_assist(
toggle_ignore,
r#"
- #[test$0]
- #[ignore]
- fn test() {}
+ mod indent {
+ #[test$0]
+ #[ignore]
+ fn test() {}
+ }
"#,
r#"
- #[test]
- fn test() {}
+ mod indent {
+ #[test]
+ fn test() {}
+ }
"#,
)
}
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index 0b5dae6bc4..47cb4c8e74 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -59,6 +59,8 @@
//! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
#![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)]
mod assist_config;
mod assist_context;
@@ -245,7 +247,6 @@ mod handlers {
add_label_to_loop::add_label_to_loop,
add_lifetime_to_type::add_lifetime_to_type,
add_missing_match_arms::add_missing_match_arms,
- add_return_type::add_return_type,
add_turbo_fish::add_turbo_fish,
apply_demorgan::apply_demorgan_iterator,
apply_demorgan::apply_demorgan,
@@ -390,6 +391,7 @@ mod handlers {
// used as a tie-breaker.
add_missing_impl_members::add_missing_impl_members,
add_missing_impl_members::add_missing_default_members,
+ add_return_type::add_return_type,
//
replace_string_with_char::replace_string_with_char,
replace_string_with_char::replace_char_with_string,
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index de8c4b6bca..9a96374c00 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -27,7 +27,7 @@ use syntax::{
make,
syntax_factory::SyntaxFactory,
},
- syntax_editor::{Removable, SyntaxEditor},
+ syntax_editor::{Element, Removable, SyntaxEditor},
};
use crate::{
@@ -384,6 +384,28 @@ fn invert_special_case_legacy(expr: &ast::Expr) -> Option<ast::Expr> {
}
}
+pub(crate) fn insert_attributes(
+ before: impl Element,
+ edit: &mut SyntaxEditor,
+ attrs: impl IntoIterator<Item = ast::Attr>,
+) {
+ let mut attrs = attrs.into_iter().peekable();
+ if attrs.peek().is_none() {
+ return;
+ }
+ let elem = before.syntax_element();
+ let indent = IndentLevel::from_element(&elem);
+ let whitespace = format!("\n{indent}");
+ edit.insert_all(
+ syntax::syntax_editor::Position::before(elem),
+ attrs
+ .flat_map(|attr| {
+ [attr.syntax().clone().into(), make::tokens::whitespace(&whitespace).into()]
+ })
+ .collect(),
+ );
+}
+
pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
[Direction::Next, Direction::Prev].into_iter()
}
diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml
index 277d5dfa49..6abc009241 100644
--- a/crates/ide-completion/Cargo.toml
+++ b/crates/ide-completion/Cargo.toml
@@ -37,5 +37,9 @@ expect-test = "1.5.1"
test-utils.workspace = true
test-fixture.workspace = true
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index abae3cb368..b28764f6fc 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -190,7 +190,7 @@ impl Completions {
path_ctx: &PathCompletionCtx<'_>,
) {
ctx.process_all_names(&mut |name, res, doc_aliases| match res {
- ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => {
+ ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
self.add_module(ctx, path_ctx, m, name, doc_aliases);
}
_ => (),
diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs
index 267d92b6c0..57ea609a40 100644
--- a/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/crates/ide-completion/src/completions/attribute/derive.rs
@@ -56,7 +56,7 @@ pub(crate) fn complete_derive_path(
_ => return,
};
- match (core, mac.module(ctx.db).krate()) {
+ match (core, mac.module(ctx.db).krate(ctx.db)) {
// show derive dependencies for `core`/`std` derives
(Some(core), mac_krate) if core == mac_krate => {}
_ => return acc.add_macro(ctx, path_ctx, mac, name),
diff --git a/crates/ide-completion/src/completions/attribute/macro_use.rs b/crates/ide-completion/src/completions/attribute/macro_use.rs
index 0641a4f6c3..136315c61f 100644
--- a/crates/ide-completion/src/completions/attribute/macro_use.rs
+++ b/crates/ide-completion/src/completions/attribute/macro_use.rs
@@ -15,7 +15,7 @@ pub(super) fn complete_macro_use(
let Some(extern_crate) = ctx.sema.to_def(extern_crate) else { return };
let Some(krate) = extern_crate.resolved_crate(ctx.db) else { return };
- for mod_def in krate.root_module().declarations(ctx.db) {
+ for mod_def in krate.root_module(ctx.db).declarations(ctx.db) {
if let ModuleDef::Macro(mac) = mod_def {
let mac_name = mac.name(ctx.db);
let mac_name = mac_name.as_str();
diff --git a/crates/ide-completion/src/completions/format_string.rs b/crates/ide-completion/src/completions/format_string.rs
index 5ae65b05bc..eaacd8d1a8 100644
--- a/crates/ide-completion/src/completions/format_string.rs
+++ b/crates/ide-completion/src/completions/format_string.rs
@@ -22,13 +22,8 @@ pub(crate) fn format_string(
let cursor_in_lit = cursor - lit_start;
let prefix = &original.text()[..cursor_in_lit.into()];
- let braces = prefix.char_indices().rev().skip_while(|&(_, c)| c.is_alphanumeric()).next_tuple();
- let brace_offset = match braces {
- // escaped brace
- Some(((_, '{'), (_, '{'))) => return,
- Some(((idx, '{'), _)) => lit_start + TextSize::from(idx as u32 + 1),
- _ => return,
- };
+ let Some(brace_offset) = unescaped_brace(prefix) else { return };
+ let brace_offset = lit_start + brace_offset + TextSize::of('{');
let source_range = TextRange::new(brace_offset, cursor);
ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| {
@@ -59,6 +54,15 @@ pub(crate) fn format_string(
});
}
+fn unescaped_brace(prefix: &str) -> Option<TextSize> {
+ let is_ident_char = |ch: char| ch.is_alphanumeric() || ch == '_';
+ prefix
+ .trim_end_matches(is_ident_char)
+ .strip_suffix('{')
+ .filter(|it| it.chars().rev().take_while(|&ch| ch == '{').count() % 2 == 0)
+ .map(|s| TextSize::new(s.len() as u32))
+}
+
#[cfg(test)]
mod tests {
use expect_test::expect;
@@ -97,6 +101,82 @@ fn main() {
}
#[test]
+ fn no_completion_after_escaped() {
+ check_no_kw(
+ r#"
+//- minicore: fmt
+fn main() {
+ let foobar = 1;
+ format_args!("{{f$0");
+}
+"#,
+ expect![[]],
+ );
+ check_no_kw(
+ r#"
+//- minicore: fmt
+fn main() {
+ let foobar = 1;
+ format_args!("some text {{{{f$0");
+}
+"#,
+ expect![[]],
+ );
+ }
+
+ #[test]
+ fn completes_unescaped_after_escaped() {
+ check_edit(
+ "foobar",
+ r#"
+//- minicore: fmt
+fn main() {
+ let foobar = 1;
+ format_args!("{{{f$0");
+}
+"#,
+ r#"
+fn main() {
+ let foobar = 1;
+ format_args!("{{{foobar");
+}
+"#,
+ );
+ check_edit(
+ "foobar",
+ r#"
+//- minicore: fmt
+fn main() {
+ let foobar = 1;
+ format_args!("{{{{{f$0");
+}
+"#,
+ r#"
+fn main() {
+ let foobar = 1;
+ format_args!("{{{{{foobar");
+}
+"#,
+ );
+ check_edit(
+ "foobar",
+ r#"
+//- minicore: fmt
+fn main() {
+ let foobar = 1;
+ format_args!("}}{f$0");
+}
+"#,
+ r#"
+fn main() {
+ let foobar = 1;
+ format_args!("}}{foobar");
+}
+"#,
+ );
+ }
+
+ #[test]
fn completes_locals() {
check_edit(
"foobar",
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index cdd77e79b5..4072f05a41 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -344,7 +344,13 @@ fn get_transformed_fn(
}
_ => None,
})?;
- ted::replace(ty.syntax(), output.syntax());
+ if let ast::Type::TupleType(ty) = &output
+ && ty.fields().next().is_none()
+ {
+ ted::remove(fn_.ret_type()?.syntax());
+ } else {
+ ted::replace(ty.syntax(), output.syntax());
+ }
}
_ => (),
}
@@ -1619,6 +1625,35 @@ impl DesugaredAsyncTrait for () {
}
"#,
);
+
+ check_edit(
+ "async fn foo",
+ r#"
+//- minicore: future, send, sized
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+ fn foo(&self) -> impl Future<Output = ()> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+ $0
+}
+"#,
+ r#"
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+ fn foo(&self) -> impl Future<Output = ()> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+ async fn foo(&self) {
+ $0
+}
+}
+"#,
+ );
}
#[test]
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index eab2b9063f..fbb3cde968 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -344,6 +344,60 @@ fn main() {
}
"#,
);
+
+ check_edit(
+ "loop",
+ r#"
+fn main() {
+ let x = &$0
+ bar();
+}
+"#,
+ r#"
+fn main() {
+ let x = &loop {
+ $0
+};
+ bar();
+}
+"#,
+ );
+
+ check_edit(
+ "loop",
+ r#"
+fn main() {
+ let x = -$0
+ bar();
+}
+"#,
+ r#"
+fn main() {
+ let x = -loop {
+ $0
+};
+ bar();
+}
+"#,
+ );
+
+ check_edit(
+ "loop",
+ r#"
+fn main() {
+ let x = 2 + $0
+ bar();
+}
+"#,
+ r#"
+fn main() {
+ let x = 2 + loop {
+ $0
+};
+ bar();
+}
+"#,
+ );
}
#[test]
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index e761da7152..add637a16f 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1321,9 +1321,8 @@ fn classify_name_ref<'db>(
let incomplete_expr_stmt =
it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none());
let before_else_kw = before_else_kw(it);
- let incomplete_let = it
- .parent()
- .and_then(ast::LetStmt::cast)
+ let incomplete_let = left_ancestors(it.parent())
+ .find_map(ast::LetStmt::cast)
.is_some_and(|it| it.semicolon_token().is_none())
|| after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
let in_value = is_in_value(it);
@@ -1882,6 +1881,13 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
Some((use_tree.path()?, true))
}
+fn left_ancestors(node: Option<SyntaxNode>) -> impl Iterator<Item = SyntaxNode> {
+ node.into_iter().flat_map(|node| {
+ let end = node.text_range().end();
+ node.ancestors().take_while(move |it| it.text_range().end() == end)
+ })
+}
+
fn is_in_token_of_for_loop(path: &ast::Path) -> bool {
// oh my ...
(|| {
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index c526c7f070..71d32da747 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -23,7 +23,7 @@ use crate::{
/// editor pop-up.
///
/// It is basically a POD with various properties. To construct a [`CompletionItem`],
-/// use [`Builder::new`] method and the [`Builder`] struct.
+/// use the [`Builder`] struct.
#[derive(Clone, UpmapFromRaFixture)]
#[non_exhaustive]
pub struct CompletionItem {
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index f7a118db50..33ab43fa61 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -1,5 +1,12 @@
//! `completions` crate provides utilities for generating completions of user input.
+// It's useful to refer to code that is private in doc comments.
+#![allow(rustdoc::private_intra_doc_links)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
mod completions;
mod config;
mod context;
@@ -283,7 +290,7 @@ pub fn resolve_completion_edits(
let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?;
let current_module = sema.scope(position_for_import)?.module();
- let current_crate = current_module.krate();
+ let current_crate = current_module.krate(db);
let current_edition = current_crate.edition(db);
let new_ast = scope.clone_for_update();
let mut import_insert = TextEdit::builder();
diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs
index cfd6340f1e..ce35ab135f 100644
--- a/crates/ide-completion/src/render/variant.rs
+++ b/crates/ide-completion/src/render/variant.rs
@@ -106,7 +106,7 @@ pub(crate) fn visible_fields(
.collect::<Vec<_>>();
let has_invisible_field = n_fields - fields.len() > 0;
let is_foreign_non_exhaustive =
- item.attrs(ctx.db).is_non_exhaustive() && item.krate(ctx.db) != module.krate();
+ item.attrs(ctx.db).is_non_exhaustive() && item.krate(ctx.db) != module.krate(ctx.db);
let fields_omitted = has_invisible_field || is_foreign_non_exhaustive;
Some((fields, fields_omitted))
}
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 9ff490f904..3701416dfc 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -1508,3 +1508,55 @@ extern crate dep;
)
}
}
+
+#[test]
+fn builtin_macro_completed_only_as_its_kind() {
+ check(
+ r#"
+#[rustc_builtin_macro]
+pub macro define_opaque($($tt:tt)*) {
+ /* compiler built-in */
+}
+
+fn foo() {
+ def$0
+}
+ "#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw impl for
+ kw let
+ kw letm
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+}
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 94530bf51d..cf86618de6 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -780,9 +780,9 @@ fn main() {
}
"#,
expect![[r#"
- me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
+ me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
"#]],
);
}
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index f1f9d85cf9..fca06b69d1 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -52,5 +52,9 @@ line-index.workspace = true
[dev-dependencies]
expect-test = "1.5.1"
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index 9ce85b2bf3..788f9b73fa 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -64,9 +64,9 @@ impl Definition {
pub fn krate(&self, db: &RootDatabase) -> Option<Crate> {
Some(match self {
- Definition::Module(m) => m.krate(),
+ Definition::Module(m) => m.krate(db),
&Definition::Crate(it) => it,
- _ => self.module(db)?.krate(),
+ _ => self.module(db)?.krate(db),
})
}
@@ -93,7 +93,7 @@ impl Definition {
Definition::ExternCrateDecl(it) => it.module(db),
Definition::DeriveHelper(it) => it.derive().module(db),
Definition::InlineAsmOperand(it) => it.parent(db).module(db),
- Definition::ToolModule(t) => t.krate().root_module(),
+ Definition::ToolModule(t) => t.krate().root_module(db),
Definition::BuiltinAttr(_)
| Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
@@ -374,7 +374,7 @@ pub fn find_std_module(
) -> Option<hir::Module> {
let db = famous_defs.0.db;
let std_crate = famous_defs.std()?;
- let std_root_module = std_crate.root_module();
+ let std_root_module = std_crate.root_module(famous_defs.0.db);
std_root_module.children(db).find(|module| {
module.name(db).is_some_and(|module| module.display(db, edition).to_string() == name)
})
diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs
index 8eea2b81ba..f28ce53e91 100644
--- a/crates/ide-db/src/famous_defs.rs
+++ b/crates/ide-db/src/famous_defs.rs
@@ -232,7 +232,7 @@ impl FamousDefs<'_, '_> {
lang_crate => lang_crate,
};
let std_crate = self.find_lang_crate(lang_crate)?;
- let mut module = std_crate.root_module();
+ let mut module = std_crate.root_module(db);
for segment in path {
module = module.children(db).find_map(|child| {
let name = child.name(db)?;
diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs
index 1e54058dd1..08cf1eeed3 100644
--- a/crates/ide-db/src/helpers.rs
+++ b/crates/ide-db/src/helpers.rs
@@ -80,7 +80,7 @@ pub fn visit_file_defs(
}
module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
- let is_root = module.is_crate_root();
+ let is_root = module.is_crate_root(db);
module
.legacy_macros(db)
.into_iter()
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index c49ade2350..90e3bb61f4 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -315,7 +315,7 @@ impl<'db> ImportAssets<'db> {
allow_unstable: sema.is_nightly(scope.krate()),
};
let db = sema.db;
- let krate = self.module_with_candidate.krate();
+ let krate = self.module_with_candidate.krate(sema.db);
let scope_definitions = self.scope_definitions(sema);
let mod_path = |item| {
get_mod_path(
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 0301b50208..338c423254 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -2,6 +2,11 @@
//!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
extern crate self as ide_db;
mod apply_change;
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index bc5958ec58..48305c2082 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -152,7 +152,7 @@ impl<'a> PathTransform<'a> {
db,
node,
&db.expansion_span_map(file_id),
- self.target_scope.module().krate().into(),
+ self.target_scope.module().krate(db).into(),
)
}
}
@@ -174,7 +174,7 @@ impl<'a> PathTransform<'a> {
let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default();
let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default();
let mut defaulted_params: Vec<DefaultedParam> = Default::default();
- let target_edition = target_module.krate().edition(self.source_scope.db);
+ let target_edition = target_module.krate(db).edition(self.source_scope.db);
self.generic_def
.into_iter()
.flat_map(|it| it.type_or_const_params(db))
@@ -219,7 +219,7 @@ impl<'a> PathTransform<'a> {
}
(Either::Left(k), None) => {
if let Some(default) =
- k.default(db, target_module.krate().to_display_target(db))
+ k.default(db, target_module.krate(db).to_display_target(db))
&& let Some(default) = default.expr()
{
const_substs.insert(k, default.syntax().clone_for_update());
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index a8800c142a..82eee69f0d 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -246,7 +246,7 @@ fn rename_mod(
) -> Result<SourceChange> {
let mut source_change = SourceChange::default();
- if module.is_crate_root() {
+ if module.is_crate_root(sema.db) {
return Ok(source_change);
}
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index f52b345007..a48438cfa8 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -294,9 +294,9 @@ impl Definition {
// def is crate root
if let &Definition::Module(module) = self
- && module.is_crate_root()
+ && module.is_crate_root(db)
{
- return SearchScope::reverse_dependencies(db, module.krate());
+ return SearchScope::reverse_dependencies(db, module.krate(db));
}
let module = match self.module(db) {
@@ -367,22 +367,22 @@ impl Definition {
return match macro_def.kind(db) {
hir::MacroKind::Declarative => {
if macro_def.attrs(db).is_macro_export() {
- SearchScope::reverse_dependencies(db, module.krate())
+ SearchScope::reverse_dependencies(db, module.krate(db))
} else {
- SearchScope::krate(db, module.krate())
+ SearchScope::krate(db, module.krate(db))
}
}
hir::MacroKind::AttrBuiltIn
| hir::MacroKind::DeriveBuiltIn
| hir::MacroKind::DeclarativeBuiltIn => SearchScope::crate_graph(db),
hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => {
- SearchScope::reverse_dependencies(db, module.krate())
+ SearchScope::reverse_dependencies(db, module.krate(db))
}
};
}
if let Definition::DeriveHelper(_) = self {
- return SearchScope::reverse_dependencies(db, module.krate());
+ return SearchScope::reverse_dependencies(db, module.krate(db));
}
if let Some(vis) = self.visibility(db) {
@@ -391,7 +391,7 @@ impl Definition {
SearchScope::module_and_children(db, module.into())
}
Visibility::PubCrate(krate) => SearchScope::krate(db, krate.into()),
- Visibility::Public => SearchScope::reverse_dependencies(db, module.krate()),
+ Visibility::Public => SearchScope::reverse_dependencies(db, module.krate(db)),
};
}
@@ -907,13 +907,13 @@ impl<'a> FindUsages<'a> {
}
}
// special case crate modules as these do not have a proper name
- (_, Definition::Module(module)) if module.is_crate_root() => {
+ (_, Definition::Module(module)) if module.is_crate_root(self.sema.db) => {
// FIXME: This assumes the crate name is always equal to its display name when it
// really isn't
// we should instead look at the dependency edge name and recursively search our way
// up the ancestors
module
- .krate()
+ .krate(self.sema.db)
.display_name(self.sema.db)
.map(|crate_name| crate_name.crate_name().symbol().as_str().into())
}
@@ -1002,7 +1002,7 @@ impl<'a> FindUsages<'a> {
let scope =
search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module));
- let is_crate_root = module.is_crate_root().then(|| Finder::new("crate"));
+ let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
let finder = &Finder::new("super");
for (text, file_id, search_range) in Self::scope_files(sema.db, &scope) {
diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index ef67fbf6fe..e15d0b33bb 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/crates/ide-db/src/symbol_index.rs
@@ -37,6 +37,7 @@ use hir::{
};
use rayon::prelude::*;
use rustc_hash::FxHashSet;
+use salsa::Update;
use crate::RootDatabase;
@@ -118,7 +119,7 @@ pub struct LocalRoots {
}
/// The symbol indices of modules that make up a given crate.
-pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> {
+pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_>]> {
let _p = tracing::info_span!("crate_symbols").entered();
krate.modules(db).into_iter().map(|module| SymbolIndex::module_symbols(db, module)).collect()
}
@@ -148,7 +149,7 @@ pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]>
// | Editor | Shortcut |
// |---------|-----------|
// | VS Code | <kbd>Ctrl+T</kbd>
-pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
+pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol<'_>> {
let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
let indices: Vec<_> = if query.libs {
@@ -170,9 +171,7 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
crates
.par_iter()
.for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into()));
- let indices: Vec<_> =
- crates.into_iter().map(|krate| crate_symbols(db, krate.into())).collect();
- indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
+ crates.into_iter().flat_map(|krate| Vec::from(crate_symbols(db, krate.into()))).collect()
};
let mut res = vec![];
@@ -184,24 +183,27 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
}
#[derive(Default)]
-pub struct SymbolIndex {
- symbols: Box<[FileSymbol]>,
+pub struct SymbolIndex<'db> {
+ symbols: Box<[FileSymbol<'db>]>,
map: fst::Map<Vec<u8>>,
}
-impl SymbolIndex {
+impl<'db> SymbolIndex<'db> {
/// The symbol index for a given source root within library_roots.
- pub fn library_symbols(db: &dyn HirDatabase, source_root_id: SourceRootId) -> &SymbolIndex {
+ pub fn library_symbols(
+ db: &'db dyn HirDatabase,
+ source_root_id: SourceRootId,
+ ) -> &'db SymbolIndex<'db> {
// FIXME:
#[salsa::interned]
struct InternedSourceRootId {
id: SourceRootId,
}
#[salsa::tracked(returns(ref))]
- fn library_symbols(
- db: &dyn HirDatabase,
- source_root_id: InternedSourceRootId<'_>,
- ) -> SymbolIndex {
+ fn library_symbols<'db>(
+ db: &'db dyn HirDatabase,
+ source_root_id: InternedSourceRootId<'db>,
+ ) -> SymbolIndex<'db> {
let _p = tracing::info_span!("library_symbols").entered();
// We call this without attaching because this runs in parallel, so we need to attach here.
@@ -224,7 +226,7 @@ impl SymbolIndex {
/// The symbol index for a given module. These modules should only be in source roots that
/// are inside local_roots.
- pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex {
+ pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex<'_> {
// FIXME:
#[salsa::interned]
struct InternedModuleId {
@@ -232,7 +234,10 @@ impl SymbolIndex {
}
#[salsa::tracked(returns(ref))]
- fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolIndex {
+ fn module_symbols<'db>(
+ db: &'db dyn HirDatabase,
+ module: InternedModuleId<'db>,
+ ) -> SymbolIndex<'db> {
let _p = tracing::info_span!("module_symbols").entered();
// We call this without attaching because this runs in parallel, so we need to attach here.
@@ -241,7 +246,7 @@ impl SymbolIndex {
SymbolIndex::new(SymbolCollector::new_module(
db,
module,
- !module.krate().origin(db).is_local(),
+ !module.krate(db).origin(db).is_local(),
))
})
}
@@ -250,29 +255,41 @@ impl SymbolIndex {
}
}
-impl fmt::Debug for SymbolIndex {
+impl fmt::Debug for SymbolIndex<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
}
}
-impl PartialEq for SymbolIndex {
- fn eq(&self, other: &SymbolIndex) -> bool {
+impl PartialEq for SymbolIndex<'_> {
+ fn eq(&self, other: &SymbolIndex<'_>) -> bool {
self.symbols == other.symbols
}
}
-impl Eq for SymbolIndex {}
+impl Eq for SymbolIndex<'_> {}
-impl Hash for SymbolIndex {
+impl Hash for SymbolIndex<'_> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.symbols.hash(hasher)
}
}
-impl SymbolIndex {
- fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex {
- fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
+unsafe impl Update for SymbolIndex<'_> {
+ unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
+ let this = unsafe { &mut *old_pointer };
+ if *this == new_value {
+ false
+ } else {
+ *this = new_value;
+ true
+ }
+ }
+}
+
+impl<'db> SymbolIndex<'db> {
+ fn new(mut symbols: Box<[FileSymbol<'db>]>) -> SymbolIndex<'db> {
+ fn cmp(lhs: &FileSymbol<'_>, rhs: &FileSymbol<'_>) -> Ordering {
let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
lhs_chars.cmp(rhs_chars)
@@ -318,7 +335,7 @@ impl SymbolIndex {
}
pub fn memory_size(&self) -> usize {
- self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol>()
+ self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol<'_>>()
}
fn range_to_map_value(start: usize, end: usize) -> u64 {
@@ -336,10 +353,10 @@ impl SymbolIndex {
}
impl Query {
- pub(crate) fn search<'sym, T>(
+ pub(crate) fn search<'db, T>(
self,
- indices: &'sym [&SymbolIndex],
- cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+ indices: &[&'db SymbolIndex<'db>],
+ cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
) -> Option<T> {
let _p = tracing::info_span!("symbol_index::Query::search").entered();
let mut op = fst::map::OpBuilder::new();
@@ -371,11 +388,11 @@ impl Query {
}
}
- fn search_maps<'sym, T>(
+ fn search_maps<'db, T>(
&self,
- indices: &'sym [&SymbolIndex],
+ indices: &[&'db SymbolIndex<'db>],
mut stream: fst::map::Union<'_>,
- mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
+ mut cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
) -> Option<T> {
let ignore_underscore_prefixed = !self.query.starts_with("__");
while let Some((_, indexed_values)) = stream.next() {
diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt
index 427a510559..5783d97564 100644
--- a/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -1,12 +1,8 @@
[
(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(0),
+ id: ModuleIdLt {
+ [salsa id]: Id(3800),
},
},
[
@@ -16,7 +12,7 @@
Struct(
Struct {
id: StructId(
- 3801,
+ 3c01,
),
},
),
@@ -43,6 +39,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Struct",
@@ -50,7 +47,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -77,6 +74,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "mul1",
@@ -84,7 +82,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -111,6 +109,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "mul2",
@@ -118,7 +117,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -145,6 +144,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "s1",
@@ -152,7 +152,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -179,6 +179,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "s1",
@@ -186,7 +187,7 @@
Struct(
Struct {
id: StructId(
- 3801,
+ 3c01,
),
},
),
@@ -213,6 +214,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "s2",
@@ -220,7 +222,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -247,6 +249,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
],
),
diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index cc130194cb..953bc73da9 100644
--- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -1,12 +1,8 @@
[
(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(0),
+ id: ModuleIdLt {
+ [salsa id]: Id(3800),
},
},
[
@@ -15,7 +11,7 @@
def: Variant(
Variant {
id: EnumVariantId(
- 7800,
+ 7c00,
),
},
),
@@ -43,13 +39,14 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Alias",
def: TypeAlias(
TypeAlias {
id: TypeAliasId(
- 6c00,
+ 7000,
),
},
),
@@ -75,13 +72,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "B",
def: Variant(
Variant {
id: EnumVariantId(
- 7801,
+ 7c01,
),
},
),
@@ -109,13 +107,14 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "CONST",
def: Const(
Const {
id: ConstId(
- 6400,
+ 6800,
),
},
),
@@ -141,13 +140,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "CONST_WITH_INNER",
def: Const(
Const {
id: ConstId(
- 6402,
+ 6802,
),
},
),
@@ -173,6 +173,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Enum",
@@ -180,7 +181,7 @@
Enum(
Enum {
id: EnumId(
- 5000,
+ 5400,
),
},
),
@@ -207,6 +208,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "ItemLikeMacro",
@@ -214,7 +216,7 @@
Macro {
id: Macro2Id(
Macro2Id(
- 4c00,
+ 5000,
),
),
},
@@ -241,6 +243,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Macro",
@@ -248,7 +251,7 @@
Macro {
id: Macro2Id(
Macro2Id(
- 4c00,
+ 5000,
),
),
},
@@ -275,13 +278,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "STATIC",
def: Static(
Static {
id: StaticId(
- 6800,
+ 6c00,
),
},
),
@@ -307,6 +311,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Struct",
@@ -314,7 +319,7 @@
Struct(
Struct {
id: StructId(
- 4801,
+ 4c01,
),
},
),
@@ -341,6 +346,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructFromMacro",
@@ -348,7 +354,7 @@
Struct(
Struct {
id: StructId(
- 4800,
+ 4c00,
),
},
),
@@ -356,7 +362,7 @@
loc: DeclarationLocation {
hir_file_id: MacroFile(
MacroCallId(
- Id(4000),
+ Id(4400),
),
),
ptr: SyntaxNodePtr {
@@ -375,6 +381,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInFn",
@@ -382,7 +389,7 @@
Struct(
Struct {
id: StructId(
- 4805,
+ 4c05,
),
},
),
@@ -411,6 +418,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInNamedConst",
@@ -418,7 +426,7 @@
Struct(
Struct {
id: StructId(
- 4806,
+ 4c06,
),
},
),
@@ -447,6 +455,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInUnnamedConst",
@@ -454,7 +463,7 @@
Struct(
Struct {
id: StructId(
- 4807,
+ 4c07,
),
},
),
@@ -481,6 +490,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructT",
@@ -488,7 +498,7 @@
Struct(
Struct {
id: StructId(
- 4802,
+ 4c02,
),
},
),
@@ -515,13 +525,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Trait",
def: Trait(
Trait {
id: TraitId(
- 5c00,
+ 6000,
),
},
),
@@ -547,6 +558,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Trait",
@@ -554,7 +566,7 @@
Macro {
id: Macro2Id(
Macro2Id(
- 4c00,
+ 5000,
),
),
},
@@ -581,6 +593,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Union",
@@ -588,7 +601,7 @@
Union(
Union {
id: UnionId(
- 5400,
+ 5800,
),
},
),
@@ -615,17 +628,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "a_mod",
def: Module(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(1),
+ id: ModuleIdLt {
+ [salsa id]: Id(3801),
},
},
),
@@ -651,17 +661,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "b_mod",
def: Module(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(2),
+ id: ModuleIdLt {
+ [salsa id]: Id(3802),
},
},
),
@@ -687,6 +694,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "define_struct",
@@ -694,7 +702,7 @@
Macro {
id: MacroRulesId(
MacroRulesId(
- 3c01,
+ 4001,
),
),
},
@@ -721,13 +729,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "generic_impl_fn",
def: Function(
Function {
id: FunctionId(
- 6002,
+ 6402,
),
},
),
@@ -755,13 +764,14 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "impl_fn",
def: Function(
Function {
id: FunctionId(
- 6001,
+ 6401,
),
},
),
@@ -789,6 +799,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "macro_rules_macro",
@@ -796,7 +807,7 @@
Macro {
id: MacroRulesId(
MacroRulesId(
- 3c00,
+ 4000,
),
),
},
@@ -823,13 +834,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "main",
def: Function(
Function {
id: FunctionId(
- 6000,
+ 6400,
),
},
),
@@ -855,6 +867,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "really_define_struct",
@@ -862,7 +875,7 @@
Macro {
id: MacroRulesId(
MacroRulesId(
- 3c01,
+ 4001,
),
),
},
@@ -889,13 +902,14 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "trait_fn",
def: Function(
Function {
id: FunctionId(
- 6003,
+ 6403,
),
},
),
@@ -923,17 +937,14 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
],
),
(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(1),
+ id: ModuleIdLt {
+ [salsa id]: Id(3801),
},
},
[
@@ -943,7 +954,7 @@
Struct(
Struct {
id: StructId(
- 4803,
+ 4c03,
),
},
),
@@ -970,17 +981,14 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
],
),
(
Module {
- id: ModuleId {
- krate: Crate(
- Id(2c00),
- ),
- block: None,
- local_id: Idx::<ModuleData>(2),
+ id: ModuleIdLt {
+ [salsa id]: Id(3802),
},
},
[
@@ -989,7 +997,7 @@
def: Trait(
Trait {
id: TraitId(
- 5c00,
+ 6000,
),
},
),
@@ -1015,6 +1023,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "IsThisJustATrait",
@@ -1022,7 +1031,7 @@
Macro {
id: Macro2Id(
Macro2Id(
- 4c00,
+ 5000,
),
),
},
@@ -1049,6 +1058,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInModB",
@@ -1056,7 +1066,7 @@
Struct(
Struct {
id: StructId(
- 4804,
+ 4c04,
),
},
),
@@ -1083,6 +1093,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "SuperItemLikeMacro",
@@ -1090,7 +1101,7 @@
Macro {
id: Macro2Id(
Macro2Id(
- 4c00,
+ 5000,
),
),
},
@@ -1117,6 +1128,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "ThisStruct",
@@ -1124,7 +1136,7 @@
Struct(
Struct {
id: StructId(
- 4804,
+ 4c04,
),
},
),
@@ -1151,6 +1163,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
],
),
diff --git a/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
index 3ab837aa61..6f5f8f889c 100644
--- a/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
+++ b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
@@ -5,7 +5,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -32,5 +32,6 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
]
diff --git a/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/crates/ide-db/src/test_data/test_symbols_with_imports.txt
index a6a808d616..5d3fe4d265 100644
--- a/crates/ide-db/src/test_data/test_symbols_with_imports.txt
+++ b/crates/ide-db/src/test_data/test_symbols_with_imports.txt
@@ -5,7 +5,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -32,6 +32,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
FileSymbol {
name: "Foo",
@@ -39,7 +40,7 @@
Struct(
Struct {
id: StructId(
- 3800,
+ 3c00,
),
},
),
@@ -66,5 +67,6 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
+ _marker: PhantomData<&()>,
},
]
diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs
index 7b9fdb1e1c..7200e7fbe5 100644
--- a/crates/ide-db/src/traits.rs
+++ b/crates/ide-db/src/traits.rs
@@ -34,7 +34,7 @@ pub fn get_missing_assoc_items(
// may share the same name as a function or constant.
let mut impl_fns_consts = FxHashSet::default();
let mut impl_type = FxHashSet::default();
- let edition = imp.module(sema.db).krate().edition(sema.db);
+ let edition = imp.module(sema.db).krate(sema.db).edition(sema.db);
for item in imp.items(sema.db) {
match item {
diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml
index 6f1e66948f..ddf5999036 100644
--- a/crates/ide-diagnostics/Cargo.toml
+++ b/crates/ide-diagnostics/Cargo.toml
@@ -34,5 +34,9 @@ expect-test = "1.5.1"
test-utils.workspace = true
test-fixture.workspace = true
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index fdc426c32c..4a12c5a26d 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -1000,7 +1000,8 @@ mod OtherBadCase;
// ^^^^^^^^^^^^ 💡 error: Module `OtherBadCase` should have snake_case name, e.g. `other_bad_case`
//- /BAD_CASE/OtherBadCase.rs
-#![deny(non_snake_case)]
+#![allow(non_snake_case)]
+#![deny(non_snake_case)] // The lint level has been overridden.
fn FOO() {}
// ^^^ 💡 error: Function `FOO` should have snake_case name, e.g. `foo`
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index ab7256d63c..2a251382d4 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -221,8 +221,8 @@ fn get_default_constructor(
let krate = ctx
.sema
.file_to_module_def(d.file.original_file(ctx.sema.db).file_id(ctx.sema.db))?
- .krate();
- let module = krate.root_module();
+ .krate(ctx.sema.db);
+ let module = krate.root_module(ctx.sema.db);
// Look for a ::new() associated function
let has_new_func = ty
diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 59215f34a5..1abb50144d 100644
--- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -296,8 +296,12 @@ fn main() {
#[rustc_deprecated_safe_2024]
fn set_var() {}
+#[rustc_deprecated_safe_2024(audit_that = "something")]
+fn set_var2() {}
+
fn main() {
set_var();
+ set_var2();
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 18280a4add..2887a32825 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -995,6 +995,10 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
}
"#,
);
+ // FIXME: There should be no "unused variable" here, and there should be a mutability error,
+ // but our MIR infra is horribly broken and due to the order in which expressions are lowered
+ // there is no `StorageLive` for `x` in the closure (in fact, `x` should not even be a variable
+ // of the closure, the environment should be, but as I said, our MIR infra is horribly broken).
check_diagnostics(
r#"
//- minicore: copy, fn
@@ -1003,8 +1007,8 @@ fn f() {
|| {
|| {
let x = 2;
+ // ^ 💡 warn: unused variable
|| { || { x = 5; } }
- //^^^^^ 💡 error: cannot mutate immutable variable `x`
}
}
};
diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs
index 0edab5e0b3..bcfe3a8aa5 100644
--- a/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -102,7 +102,8 @@ fn missing_record_expr_field_fixes(
let indent = IndentLevel::from_node(last_field_syntax);
let mut new_field = new_field.to_string();
- if usage_file_id != def_file_id {
+ // FIXME: check submodule instead of FileId
+ if usage_file_id != def_file_id && !matches!(def_id, hir::VariantDef::Variant(_)) {
new_field = format!("pub(crate) {new_field}");
}
new_field = format!("\n{indent}{new_field}");
@@ -358,6 +359,34 @@ pub struct Foo {
}
#[test]
+ fn test_add_enum_variant_field_in_other_file_from_usage() {
+ check_fix(
+ r#"
+//- /main.rs
+mod foo;
+
+fn main() {
+ foo::Foo::Variant { bar: 3, $0baz: false};
+}
+//- /foo.rs
+pub enum Foo {
+ Variant {
+ bar: i32
+ }
+}
+"#,
+ r#"
+pub enum Foo {
+ Variant {
+ bar: i32,
+ baz: bool
+ }
+}
+"#,
+ )
+ }
+
+ #[test]
fn test_tuple_field_on_record_struct() {
check_no_fix(
r#"
diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs
index 23f0460075..90c27bdcef 100644
--- a/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -37,7 +37,7 @@ pub(crate) fn field_is_private_fixes(
fix_range: TextRange,
) -> Option<Vec<Assist>> {
let def_crate = private_field.krate(sema.db);
- let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
+ let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(sema.db);
let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
let source = private_field.source(sema.db)?;
diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index fc2648efb4..cb3aac3717 100644
--- a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -83,7 +83,7 @@ fn quickfix_for_redundant_assoc_item(
let root = db.parse_or_expand(d.file_id);
// don't modify trait def in outer crate
let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate();
- let trait_def_crate = d.trait_.module(db).krate();
+ let trait_def_crate = d.trait_.module(db).krate(db);
if trait_def_crate != current_crate {
return None;
}
diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 3a6e480f55..1283a11700 100644
--- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -3,7 +3,7 @@
use std::iter;
use hir::crate_def_map;
-use hir::{DefMap, InFile, ModuleSource};
+use hir::{InFile, ModuleSource};
use ide_db::base_db::RootQueryDb;
use ide_db::text_edit::TextEdit;
use ide_db::{
@@ -106,7 +106,7 @@ fn fixes(
// FIXME: This shouldnt need to access the crate def map directly
let crate_def_map = crate_def_map(ctx.sema.db, krate);
- let root_module = &crate_def_map[DefMap::ROOT];
+ let root_module = &crate_def_map[crate_def_map.root_module_id()];
let Some(root_file_id) = root_module.origin.file_id() else { continue };
let Some(crate_root_path) = source_root.path_for_file(&root_file_id.file_id(ctx.sema.db))
else {
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 358e0c43c2..59ec259adf 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -83,7 +83,7 @@ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Opti
make::ty("()")
};
- if !is_editable_crate(target_module.krate(), ctx.sema.db)
+ if !is_editable_crate(target_module.krate(ctx.sema.db), ctx.sema.db)
|| SyntaxKind::from_keyword(field_name, ctx.edition).is_some()
{
return None;
diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 84e63acbc0..b7ec8fa53f 100644
--- a/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -183,6 +183,61 @@ fn main2() {
}
#[test]
+ fn apply_last_lint_attribute_when_multiple_are_present() {
+ check_diagnostics(
+ r#"
+#![allow(unused_variables)]
+#![warn(unused_variables)]
+#![deny(unused_variables)]
+
+fn main() {
+ let x = 2;
+ //^ 💡 error: unused variable
+
+ #[deny(unused_variables)]
+ #[warn(unused_variables)]
+ #[allow(unused_variables)]
+ let y = 0;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn prefer_closest_ancestor_lint_attribute() {
+ check_diagnostics(
+ r#"
+#![allow(unused_variables)]
+
+fn main() {
+ #![warn(unused_variables)]
+
+ #[deny(unused_variables)]
+ let x = 2;
+ //^ 💡 error: unused variable
+}
+
+#[warn(unused_variables)]
+fn main2() {
+ #[deny(unused_variables)]
+ let x = 2;
+ //^ 💡 error: unused variable
+}
+
+#[warn(unused_variables)]
+fn main3() {
+ let x = 2;
+ //^ 💡 warn: unused variable
+}
+
+fn main4() {
+ let x = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
fn fix_unused_variable() {
check_fix(
r#"
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 41ae854455..2b8474c316 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -23,6 +23,11 @@
//! There are also a couple of ad-hoc diagnostics implemented directly here, we
//! don't yet have a great pattern for how to do them properly.
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
mod handlers {
pub(crate) mod await_outside_of_async;
pub(crate) mod bad_rtn;
@@ -83,9 +88,8 @@ mod handlers {
#[cfg(test)]
mod tests;
-use std::{iter, sync::LazyLock};
+use std::sync::LazyLock;
-use either::Either;
use hir::{
Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic,
};
@@ -97,11 +101,9 @@ use ide_db::{
imports::insert_use::InsertUseConfig,
label::Label,
source_change::SourceChange,
- syntax_helpers::node_ext::parse_tt_as_comma_sep_paths,
};
-use itertools::Itertools;
use syntax::{
- AstPtr, Edition, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, T, TextRange,
+ AstPtr, Edition, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange,
ast::{self, AstNode},
};
@@ -345,12 +347,12 @@ pub fn semantic_diagnostics(
let module = sema.file_to_module_def(file_id);
let is_nightly = matches!(
- module.and_then(|m| db.toolchain_channel(m.krate().into())),
+ module.and_then(|m| db.toolchain_channel(m.krate(db).into())),
Some(ReleaseChannel::Nightly) | None
);
let krate = match module {
- Some(module) => module.krate(),
+ Some(module) => module.krate(db),
None => {
match db.all_crates().last() {
Some(last) => (*last).into(),
@@ -483,7 +485,7 @@ pub fn semantic_diagnostics(
// The edition isn't accurate (each diagnostics may have its own edition due to macros),
// but it's okay as it's only being used for error recovery.
- handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db));
+ handle_lints(&ctx.sema, krate, &mut lints, editioned_file_id.edition(db));
res.retain(|d| d.severity != Severity::Allow);
@@ -591,6 +593,7 @@ fn build_lints_map(
fn handle_lints(
sema: &Semantics<'_, RootDatabase>,
+ krate: hir::Crate,
diagnostics: &mut [(InFile<SyntaxNode>, &mut Diagnostic)],
edition: Edition,
) {
@@ -606,10 +609,10 @@ fn handle_lints(
}
let mut diag_severity =
- lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition);
+ lint_severity_at(sema, krate, node, &lint_groups(&diag.code, edition));
if let outline_diag_severity @ Some(_) =
- find_outline_mod_lint_severity(sema, node, diag, edition)
+ find_outline_mod_lint_severity(sema, krate, node, diag, edition)
{
diag_severity = outline_diag_severity;
}
@@ -632,6 +635,7 @@ fn default_lint_severity(lint: &Lint, edition: Edition) -> Severity {
fn find_outline_mod_lint_severity(
sema: &Semantics<'_, RootDatabase>,
+ krate: hir::Crate,
node: &InFile<SyntaxNode>,
diag: &Diagnostic,
edition: Edition,
@@ -644,123 +648,47 @@ fn find_outline_mod_lint_severity(
let mod_def = sema.to_module_def(&mod_node)?;
let module_source_file = sema.module_definition_node(mod_def);
- let mut result = None;
let lint_groups = lint_groups(&diag.code, edition);
lint_attrs(
sema,
- &ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"),
- edition,
+ krate,
+ ast::AnyHasAttrs::cast(module_source_file.value).expect("SourceFile always has attrs"),
)
- .for_each(|(lint, severity)| {
- if lint_groups.contains(&lint) {
- result = Some(severity);
- }
- });
- result
+ .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity))
}
fn lint_severity_at(
sema: &Semantics<'_, RootDatabase>,
+ krate: hir::Crate,
node: &InFile<SyntaxNode>,
lint_groups: &LintGroups,
- edition: Edition,
) -> Option<Severity> {
node.value
.ancestors()
.filter_map(ast::AnyHasAttrs::cast)
.find_map(|ancestor| {
- lint_attrs(sema, &ancestor, edition)
+ lint_attrs(sema, krate, ancestor)
.find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity))
})
.or_else(|| {
- lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition)
+ lint_severity_at(sema, krate, &sema.find_parent_file(node.file_id)?, lint_groups)
})
}
// FIXME: Switch this to analysis' `expand_cfg_attr`.
-fn lint_attrs<'a>(
- sema: &'a Semantics<'a, RootDatabase>,
- ancestor: &'a ast::AnyHasAttrs,
- edition: Edition,
-) -> impl Iterator<Item = (SmolStr, Severity)> + 'a {
- ast::attrs_including_inner(ancestor)
- .filter_map(|attr| {
- attr.as_simple_call().and_then(|(name, value)| match &*name {
- "allow" | "expect" => Some(Either::Left(iter::once((Severity::Allow, value)))),
- "warn" => Some(Either::Left(iter::once((Severity::Warning, value)))),
- "forbid" | "deny" => Some(Either::Left(iter::once((Severity::Error, value)))),
- "cfg_attr" => {
- let mut lint_attrs = Vec::new();
- cfg_attr_lint_attrs(sema, &value, &mut lint_attrs);
- Some(Either::Right(lint_attrs.into_iter()))
- }
- _ => None,
- })
- })
- .flatten()
- .flat_map(move |(severity, lints)| {
- parse_tt_as_comma_sep_paths(lints, edition).into_iter().flat_map(move |lints| {
- // Rejoin the idents with `::`, so we have no spaces in between.
- lints.into_iter().map(move |lint| {
- (
- lint.segments().filter_map(|segment| segment.name_ref()).join("::").into(),
- severity,
- )
- })
- })
- })
-}
-
-fn cfg_attr_lint_attrs(
+fn lint_attrs(
sema: &Semantics<'_, RootDatabase>,
- value: &ast::TokenTree,
- lint_attrs: &mut Vec<(Severity, ast::TokenTree)>,
-) {
- let prev_len = lint_attrs.len();
-
- let mut iter = value.token_trees_and_tokens().filter(|it| match it {
- NodeOrToken::Node(_) => true,
- NodeOrToken::Token(it) => !it.kind().is_trivia(),
- });
-
- // Skip the condition.
- for value in &mut iter {
- if value.as_token().is_some_and(|it| it.kind() == T![,]) {
- break;
- }
- }
-
- while let Some(value) = iter.next() {
- if let Some(token) = value.as_token()
- && token.kind() == SyntaxKind::IDENT
- {
- let severity = match token.text() {
- "allow" | "expect" => Some(Severity::Allow),
- "warn" => Some(Severity::Warning),
- "forbid" | "deny" => Some(Severity::Error),
- "cfg_attr" => {
- if let Some(NodeOrToken::Node(value)) = iter.next() {
- cfg_attr_lint_attrs(sema, &value, lint_attrs);
- }
- None
- }
- _ => None,
- };
- if let Some(severity) = severity {
- let lints = iter.next();
- if let Some(NodeOrToken::Node(lints)) = lints {
- lint_attrs.push((severity, lints));
- }
- }
- }
- }
-
- if prev_len != lint_attrs.len()
- && let Some(false) | None = sema.check_cfg_attr(value)
- {
- // Discard the attributes when the condition is false.
- lint_attrs.truncate(prev_len);
- }
+ krate: hir::Crate,
+ ancestor: ast::AnyHasAttrs,
+) -> impl Iterator<Item = (SmolStr, Severity)> {
+ sema.lint_attrs(krate, ancestor).rev().map(|(lint_attr, lint)| {
+ let severity = match lint_attr {
+ hir::LintAttr::Allow | hir::LintAttr::Expect => Severity::Allow,
+ hir::LintAttr::Warn => Severity::Warning,
+ hir::LintAttr::Deny | hir::LintAttr::Forbid => Severity::Error,
+ };
+ (lint, severity)
+ })
}
#[derive(Debug)]
diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml
index 0620bd26fe..1900b069e0 100644
--- a/crates/ide-ssr/Cargo.toml
+++ b/crates/ide-ssr/Cargo.toml
@@ -30,5 +30,9 @@ triomphe.workspace = true
test-utils.workspace = true
test-fixture.workspace = true
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs
index 977dfb7466..958a26324f 100644
--- a/crates/ide-ssr/src/lib.rs
+++ b/crates/ide-ssr/src/lib.rs
@@ -63,6 +63,11 @@
// // foo($a, $b) ==>> ($a).foo($b)
// ```
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
mod fragments;
mod from_comment;
mod matching;
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 9d38a860a0..d43f13b79d 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -28,7 +28,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
let sema = Semantics::new(db);
let file_id = sema.attach_first_edition(position.file_id);
let file = sema.parse(file_id);
- let krate = sema.file_to_module_def(file_id.file_id(db))?.krate().into();
+ let krate = sema.file_to_module_def(file_id.file_id(db))?.krate(db).into();
let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
SyntaxKind::IDENT => 1,
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index e1db370d44..b00aa4d0ca 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -139,7 +139,7 @@ pub(crate) fn goto_definition(
if let Definition::ExternCrateDecl(crate_def) = def {
return crate_def
.resolved_crate(db)
- .map(|it| it.root_module().to_nav(sema.db))
+ .map(|it| it.root_module(db).to_nav(db))
.into_iter()
.flatten()
.collect();
@@ -262,7 +262,7 @@ fn try_lookup_macro_def_in_macro_use(
let extern_crate = sema.to_def(&extern_crate)?;
let krate = extern_crate.resolved_crate(sema.db)?;
- for mod_def in krate.root_module().declarations(sema.db) {
+ for mod_def in krate.root_module(sema.db).declarations(sema.db) {
if let ModuleDef::Macro(mac) = mod_def
&& mac.name(sema.db).as_str() == token.text()
&& let Some(nav) = mac.try_to_nav(sema)
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index a29da4f258..4bf9b82cc8 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -384,7 +384,7 @@ trait Bar {}
fn test() {
#[derive(Copy)]
- // ^^^^^^^^^^^^
+ // ^^^^
struct Foo$0;
impl Foo {}
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index a8929859bc..9dc72a87af 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -464,7 +464,7 @@ pub(super) fn path(
item_name: Option<String>,
edition: Edition,
) -> String {
- let crate_name = module.krate().display_name(db).as_ref().map(|it| it.to_string());
+ let crate_name = module.krate(db).display_name(db).as_ref().map(|it| it.to_string());
let module_path = module
.path_to_root(db)
.into_iter()
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 071eacf660..5330b7eb99 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -11169,3 +11169,60 @@ fn foo() {
"#]],
);
}
+
+#[test]
+fn hover_trait_impl_shows_generic_args() {
+ // Single generic arg
+ check(
+ r#"
+trait Foo<T> {
+ fn foo(&self) {}
+}
+
+impl<T> Foo<()> for T {
+ fn fo$0o(&self) {}
+}
+
+fn bar() {
+ ().foo();
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ impl<T> Foo<()> for T
+ fn foo(&self)
+ ```
+ "#]],
+ );
+
+ // Multiple generic args
+ check(
+ r#"
+trait Foo<A, B> {
+ fn foo(&self) {}
+}
+
+impl<T> Foo<i32, u64> for T {
+ fn fo$0o(&self) {}
+}
+"#,
+ expect![[r#"
+ *foo*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ impl<T> Foo<i32, u64> for T
+ fn foo(&self)
+ ```
+ "#]],
+ );
+}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index deacc7fafb..03674978d5 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -320,6 +320,7 @@ pub struct InlayHintsConfig<'a> {
pub implied_dyn_trait_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
+ pub hide_inferred_type_hints: bool,
pub hide_named_constructor_hints: bool,
pub hide_closure_initialization_hints: bool,
pub hide_closure_parameter_hints: bool,
@@ -810,7 +811,7 @@ fn hint_iterator<'db>(
) -> Option<(hir::Trait, hir::TypeAlias, hir::Type<'db>)> {
let db = sema.db;
let strukt = ty.strip_references().as_adt()?;
- let krate = strukt.module(db).krate();
+ let krate = strukt.module(db).krate(db);
if krate != famous_defs.core()? {
return None;
}
@@ -900,6 +901,7 @@ mod tests {
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
binding_mode_hints: false,
+ hide_inferred_type_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
hide_closure_parameter_hints: false,
diff --git a/crates/ide/src/inlay_hints/placeholders.rs b/crates/ide/src/inlay_hints/placeholders.rs
index 96d2c17c03..e535b92a57 100644
--- a/crates/ide/src/inlay_hints/placeholders.rs
+++ b/crates/ide/src/inlay_hints/placeholders.rs
@@ -20,7 +20,7 @@ pub(super) fn type_hints(
display_target: DisplayTarget,
placeholder: InferType,
) -> Option<()> {
- if !config.type_hints {
+ if !config.type_hints || config.hide_inferred_type_hints {
return None;
}
@@ -73,4 +73,22 @@ fn foo() {
"#,
);
}
+
+ #[test]
+ fn hide_inferred_types() {
+ check_with_config(
+ InlayHintsConfig {
+ type_hints: true,
+ hide_inferred_type_hints: true,
+ ..DISABLED_CONFIG
+ },
+ r#"
+struct S<T>(T);
+
+fn foo() {
+ let t: (_, _, [_; _]) = (1_u32, S(2), [false] as _);
+}
+ "#,
+ );
+ }
}
diff --git a/crates/ide/src/interpret.rs b/crates/ide/src/interpret.rs
index 05cd145033..791da00bb6 100644
--- a/crates/ide/src/interpret.rs
+++ b/crates/ide/src/interpret.rs
@@ -45,7 +45,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura
None => format!("file://{path} range {text_range:?}"),
}
};
- let display_target = def.module(db).krate().to_display_target(db);
+ let display_target = def.module(db).krate(db).to_display_target(db);
let start_time = Instant::now();
let res = match def {
DefWithBody::Function(it) => it.eval(db, span_formatter),
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 4aa9eb98a1..1c1389ca7a 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -284,10 +284,10 @@ fn def_to_non_local_moniker(
from_crate: Crate,
) -> Option<Moniker> {
let module = match definition {
- Definition::Module(module) if module.is_crate_root() => module,
+ Definition::Module(module) if module.is_crate_root(db) => module,
_ => definition.module(db)?,
};
- let krate = module.krate();
+ let krate = module.krate(db);
let edition = krate.edition(db);
// Add descriptors for this definition and every enclosing definition.
@@ -321,7 +321,7 @@ fn def_to_non_local_moniker(
});
} else {
match def {
- Definition::Module(module) if module.is_crate_root() => {
+ Definition::Module(module) if module.is_crate_root(db) => {
// only include `crate` namespace by itself because we prefer
// `rust-analyzer cargo foo . bar/` over `rust-analyzer cargo foo . crate/bar/`
if reverse_description.is_empty() {
@@ -389,7 +389,8 @@ fn display<'db, T: HirDisplay<'db>>(db: &'db RootDatabase, module: hir::Module,
Ok(result) => result,
// Fallback on display variant that always succeeds
Err(_) => {
- let fallback_result = it.display(db, module.krate().to_display_target(db)).to_string();
+ let fallback_result =
+ it.display(db, module.krate(db).to_display_target(db)).to_string();
tracing::error!(
display = %fallback_result, "`display_source_code` failed; falling back to using display"
);
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 4c4d57f0f4..29530ed02b 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -160,7 +160,7 @@ impl NavigationTarget {
);
res.docs = module.docs(db).map(Documentation::into_owned);
res.description = Some(
- module.display(db, module.krate().to_display_target(db)).to_string(),
+ module.display(db, module.krate(db).to_display_target(db)).to_string(),
);
res
},
@@ -225,7 +225,7 @@ impl NavigationTarget {
}
}
-impl TryToNav for FileSymbol {
+impl<'db> TryToNav for FileSymbol<'db> {
fn try_to_nav(
&self,
sema: &Semantics<'_, RootDatabase>,
@@ -468,7 +468,7 @@ impl ToNav for hir::Module {
impl ToNav for hir::Crate {
fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
- self.root_module().to_nav(db)
+ self.root_module(db).to_nav(db)
}
}
@@ -511,7 +511,7 @@ impl TryToNav for hir::ExternCrateDecl {
let focus = value
.rename()
.map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right));
- let krate = self.module(db).krate();
+ let krate = self.module(db).krate(db);
Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map(
|(FileRange { file_id, range: full_range }, focus_range)| {
@@ -539,7 +539,7 @@ impl TryToNav for hir::Field {
) -> Option<UpmappingResult<NavigationTarget>> {
let db = sema.db;
let src = self.source(db)?;
- let krate = self.parent_def(db).module(db).krate();
+ let krate = self.parent_def(db).module(db).krate(db);
let field_source = match &src.value {
FieldSource::Named(it) => {
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 9e17ab2bab..a61be93ea9 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -372,7 +372,7 @@ pub(crate) fn runnable_mod(
.rev()
.filter_map(|module| {
module.name(sema.db).map(|mod_name| {
- mod_name.display(sema.db, module.krate().edition(sema.db)).to_string()
+ mod_name.display(sema.db, module.krate(sema.db).edition(sema.db)).to_string()
})
})
.join("::");
@@ -401,7 +401,7 @@ pub(crate) fn runnable_impl(
sema: &Semantics<'_, RootDatabase>,
def: &hir::Impl,
) -> Option<Runnable> {
- let display_target = def.module(sema.db).krate().to_display_target(sema.db);
+ let display_target = def.module(sema.db).krate(sema.db).to_display_target(sema.db);
let edition = display_target.edition;
let attrs = def.attrs(sema.db);
if !has_runnable_doc_test(sema.db, &attrs) {
@@ -466,7 +466,7 @@ fn runnable_mod_outline_definition(
.rev()
.filter_map(|module| {
module.name(sema.db).map(|mod_name| {
- mod_name.display(sema.db, module.krate().edition(sema.db)).to_string()
+ mod_name.display(sema.db, module.krate(sema.db).edition(sema.db)).to_string()
})
})
.join("::");
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 0cf2e15bc6..7749f8e2f2 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -10,7 +10,7 @@ use ide_db::{
documentation::Documentation,
famous_defs::FamousDefs,
};
-use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange};
+use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange};
use crate::navigation_target::UpmappingResult;
use crate::{
@@ -102,7 +102,7 @@ pub struct StaticIndexedFile {
fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
let mut worklist: Vec<_> =
- Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
+ Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
let mut modules = Vec::new();
while let Some(module) = worklist.pop() {
@@ -136,12 +136,12 @@ fn documentation_for_definition(
}
// FIXME: This is a weird function
-fn get_definitions(
- sema: &Semantics<'_, RootDatabase>,
+fn get_definitions<'db>(
+ sema: &Semantics<'db, RootDatabase>,
token: SyntaxToken,
-) -> Option<ArrayVec<Definition, 2>> {
+) -> Option<ArrayVec<(Definition, Option<hir::GenericSubstitution<'db>>), 2>> {
for token in sema.descend_into_macros_exact(token) {
- let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
+ let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions);
if let Some(defs) = def
&& !defs.is_empty()
{
@@ -183,6 +183,7 @@ impl StaticIndex<'_> {
adjustment_hints_hide_outside_unsafe: false,
implicit_drop_hints: false,
implied_dyn_trait_hints: false,
+ hide_inferred_type_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
hide_closure_parameter_hints: false,
@@ -225,12 +226,6 @@ impl StaticIndex<'_> {
show_drop_glue: true,
minicore: MiniCore::default(),
};
- let tokens = tokens.filter(|token| {
- matches!(
- token.kind(),
- IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
- )
- });
let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| {
@@ -290,9 +285,9 @@ impl StaticIndex<'_> {
let range = token.text_range();
let node = token.parent().unwrap();
match hir::attach_db(self.db, || get_definitions(&sema, token.clone())) {
- Some(it) => {
- for i in it {
- add_token(i, range, &node);
+ Some(defs) => {
+ for (def, _) in defs {
+ add_token(def, range, &node);
}
}
None => continue,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 8937f8249c..044fd3f5ac 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -501,7 +501,7 @@ pub(super) fn highlight_def(
),
Definition::Module(module) => {
let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
- if module.is_crate_root() {
+ if module.is_crate_root(db) {
h |= HlMod::CrateRoot;
}
@@ -747,7 +747,7 @@ fn highlight_method_call(
h |= HlMod::Trait;
}
- let def_crate = func.module(sema.db).krate();
+ let def_crate = func.module(sema.db).krate(sema.db);
let is_from_other_crate = krate.as_ref().map_or(false, |krate| def_crate != *krate);
let is_from_builtin_crate = def_crate.is_builtin(sema.db);
let is_public = func.visibility(sema.db) == hir::Visibility::Public;
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index e3daeef841..982e89dfab 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span>
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
- <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
+ <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="builtin_type">u32</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span><span class="comma">,</span> <span class="field declaration">field2</span><span class="colon">:</span> <span class="punctuation">&</span><span class="struct">Innerest</span> <span class="brace">}</span>
<span class="brace">}</span>
<span class="brace">}</span>
<span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index b7510e3aba..89a5e434f9 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1183,7 +1183,7 @@ fn main() {
foo!(Bar);
fn func(_: y::Bar) {
mod inner {
- struct Innerest<const C: usize> { field: [(); {C}] }
+ struct Innerest<const C: usize> { field: [u32; {C}], field2: &Innerest }
}
}
}
diff --git a/crates/ide/src/test_explorer.rs b/crates/ide/src/test_explorer.rs
index bd60ffe559..4792566f5f 100644
--- a/crates/ide/src/test_explorer.rs
+++ b/crates/ide/src/test_explorer.rs
@@ -135,11 +135,11 @@ fn find_module_id_and_test_parents(
module: Module,
) -> Option<(Vec<TestItem>, String)> {
let Some(parent) = module.parent(sema.db) else {
- let name = module.krate().display_name(sema.db)?.to_string();
+ let name = module.krate(sema.db).display_name(sema.db)?.to_string();
return Some((
vec![TestItem {
id: name.clone(),
- kind: TestItemKind::Crate(module.krate().into()),
+ kind: TestItemKind::Crate(module.krate(sema.db).into()),
label: name.clone(),
parent: None,
file: None,
@@ -181,7 +181,7 @@ pub(crate) fn discover_tests_in_crate(
let kind = TestItemKind::Crate(crate_id);
let crate_test_id = crate_test_id.to_string();
let crate_id: Crate = crate_id.into();
- let module = crate_id.root_module();
+ let module = crate_id.root_module(db);
let mut r = vec![TestItem {
id: crate_test_id.clone(),
kind,
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 37eb3d4101..462f1c69fa 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -524,4 +524,5 @@ define_symbols! {
arbitrary_self_types,
arbitrary_self_types_pointers,
supertrait_item_shadowing,
+ define_opaque,
}
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index a486219efa..28fbfecfde 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -2,6 +2,12 @@
//! for incorporating changes.
// Note, don't remove any public api from this. This API is consumed by external tools
// to run rust-analyzer as a library.
+
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync};
use crossbeam_channel::{Receiver, unbounded};
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 3dd2c1f6c4..4478bf4e37 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -3,9 +3,10 @@
//! NOTE: The crate is undergoing refactors, don't believe everything the docs
//! say :-)
//!
-//! The parser doesn't know about concrete representation of tokens and syntax
-//! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As
-//! a consequence, this crate does not contain a lexer.
+//! The parser doesn't know about concrete representation of tokens
+//! and syntax trees. Abstract [`Input`] and [`Output`] traits are
+//! used to provide tokens instead. As a consequence, this crate does
+//! not contain a lexer.
//!
//! The [`Parser`] struct from the [`parser`] module is a cursor into the
//! sequence of tokens. Parsing routines use [`Parser`] to inspect current
@@ -23,6 +24,8 @@
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_lexer as rustc_lexer;
#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+#[cfg(feature = "in-rust-tree")]
extern crate rustc_lexer;
mod event;
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index 2c6a82bf0c..d6d9ed4676 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -1,5 +1,5 @@
-//! Thin wrappers around [`camino::path`], distinguishing between absolute and
-//! relative paths.
+//! Thin wrappers around [`camino::Utf8PathBuf`], distinguishing
+//! between absolute and relative paths.
use std::{
borrow::Borrow,
diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml
index 18a2408c40..4de1a3e5dd 100644
--- a/crates/proc-macro-api/Cargo.toml
+++ b/crates/proc-macro-api/Cargo.toml
@@ -34,6 +34,8 @@ semver.workspace = true
[features]
sysroot-abi = ["proc-macro-srv", "proc-macro-srv/sysroot-abi"]
+default = []
+in-rust-tree = []
[lints]
workspace = true
diff --git a/crates/proc-macro-api/src/legacy_protocol/msg.rs b/crates/proc-macro-api/src/legacy_protocol/msg.rs
index 680372210a..a6e228d977 100644
--- a/crates/proc-macro-api/src/legacy_protocol/msg.rs
+++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs
@@ -17,19 +17,19 @@ pub enum Request {
// As such, this is the only request that needs to be supported across all protocol versions
// and by keeping it first, we ensure it always has the same discriminant encoding in postcard
/// Performs an API version check between the client and the server.
- /// Since [`VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::VERSION_CHECK_VERSION`]
ApiVersionCheck {},
/// Retrieves a list of macros from a given dynamic library.
- /// Since [`NO_VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::NO_VERSION_CHECK_VERSION`]
ListMacros { dylib_path: Utf8PathBuf },
/// Expands a procedural macro.
- /// Since [`NO_VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::NO_VERSION_CHECK_VERSION`]
ExpandMacro(Box<ExpandMacro>),
/// Sets server-specific configurations.
- /// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
+ /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`]
SetConfig(ServerConfig),
}
@@ -51,23 +51,23 @@ pub enum Response {
// As such, this is the only request that needs to be supported across all protocol versions
// and by keeping it first, we ensure it always has the same discriminant encoding in postcard
/// Returns the API version supported by the server.
- /// Since [`NO_VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::NO_VERSION_CHECK_VERSION`]
ApiVersionCheck(u32),
/// Returns a list of available macros in a dynamic library.
- /// Since [`NO_VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::NO_VERSION_CHECK_VERSION`]
ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
/// Returns result of a macro expansion.
- /// Since [`NO_VERSION_CHECK_VERSION`]
+ /// Since [`crate::version::NO_VERSION_CHECK_VERSION`]
ExpandMacro(Result<FlatTree, PanicMessage>),
/// Confirms the application of a configuration update.
- /// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
+ /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`]
SetConfig(ServerConfig),
/// Returns the result of a macro expansion, including extended span data.
- /// Since [`RUST_ANALYZER_SPAN_SUPPORT`]
+ /// Since [`crate::version::RUST_ANALYZER_SPAN_SUPPORT`]
ExpandMacroExtended(Result<ExpandMacroExtended, PanicMessage>),
}
@@ -185,7 +185,7 @@ mod tests {
use super::*;
- fn fixture_token_tree() -> TopSubtree<Span> {
+ fn fixture_token_tree_top_many_none() -> TopSubtree<Span> {
let anchor = SpanAnchor {
file_id: span::EditionedFileId::new(
span::FileId::from_raw(0xe4e4e),
@@ -201,7 +201,7 @@ mod tests {
ctx: SyntaxContext::root(Edition::CURRENT),
},
close: Span {
- range: TextRange::empty(TextSize::new(19)),
+ range: TextRange::empty(TextSize::new(0)),
anchor,
ctx: SyntaxContext::root(Edition::CURRENT),
},
@@ -259,10 +259,18 @@ mod tests {
ctx: SyntaxContext::root(Edition::CURRENT),
},
);
+ builder.open(
+ DelimiterKind::Bracket,
+ Span {
+ range: TextRange::at(TextSize::new(15), TextSize::of('[')),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ },
+ );
builder.push(Leaf::Literal(Literal {
symbol: sym::INTEGER_0,
span: Span {
- range: TextRange::at(TextSize::new(15), TextSize::of("0u32")),
+ range: TextRange::at(TextSize::new(16), TextSize::of("0u32")),
anchor,
ctx: SyntaxContext::root(Edition::CURRENT),
},
@@ -270,45 +278,140 @@ mod tests {
suffix: Some(sym::u32),
}));
builder.close(Span {
- range: TextRange::at(TextSize::new(19), TextSize::of('}')),
+ range: TextRange::at(TextSize::new(20), TextSize::of(']')),
anchor,
ctx: SyntaxContext::root(Edition::CURRENT),
});
+ builder.close(Span {
+ range: TextRange::at(TextSize::new(21), TextSize::of('}')),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ });
+
+ builder.build()
+ }
+
+ fn fixture_token_tree_top_empty_none() -> TopSubtree<Span> {
+ let anchor = SpanAnchor {
+ file_id: span::EditionedFileId::new(
+ span::FileId::from_raw(0xe4e4e),
+ span::Edition::CURRENT,
+ ),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
+ };
+
+ let builder = TopSubtreeBuilder::new(Delimiter {
+ open: Span {
+ range: TextRange::empty(TextSize::new(0)),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ },
+ close: Span {
+ range: TextRange::empty(TextSize::new(0)),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ },
+ kind: DelimiterKind::Invisible,
+ });
+
+ builder.build()
+ }
+
+ fn fixture_token_tree_top_empty_brace() -> TopSubtree<Span> {
+ let anchor = SpanAnchor {
+ file_id: span::EditionedFileId::new(
+ span::FileId::from_raw(0xe4e4e),
+ span::Edition::CURRENT,
+ ),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
+ };
+
+ let builder = TopSubtreeBuilder::new(Delimiter {
+ open: Span {
+ range: TextRange::empty(TextSize::new(0)),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ },
+ close: Span {
+ range: TextRange::empty(TextSize::new(0)),
+ anchor,
+ ctx: SyntaxContext::root(Edition::CURRENT),
+ },
+ kind: DelimiterKind::Brace,
+ });
+
builder.build()
}
#[test]
fn test_proc_macro_rpc_works() {
- let tt = fixture_token_tree();
- for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
- let mut span_data_table = Default::default();
- let task = ExpandMacro {
- data: ExpandMacroData {
- macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table),
- macro_name: Default::default(),
- attributes: None,
- has_global_spans: ExpnGlobals {
- serialize: true,
- def_site: 0,
- call_site: 0,
- mixed_site: 0,
+ for tt in [
+ fixture_token_tree_top_many_none,
+ fixture_token_tree_top_empty_none,
+ fixture_token_tree_top_empty_brace,
+ ] {
+ for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
+ let tt = tt();
+ let mut span_data_table = Default::default();
+ let task = ExpandMacro {
+ data: ExpandMacroData {
+ macro_body: FlatTree::from_subtree(tt.view(), v, &mut span_data_table),
+ macro_name: Default::default(),
+ attributes: None,
+ has_global_spans: ExpnGlobals {
+ serialize: true,
+ def_site: 0,
+ call_site: 0,
+ mixed_site: 0,
+ },
+ span_data_table: Vec::new(),
},
- span_data_table: Vec::new(),
- },
- lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
- env: Default::default(),
- current_dir: Default::default(),
- };
-
- let json = serde_json::to_string(&task).unwrap();
- // println!("{}", json);
- let back: ExpandMacro = serde_json::from_str(&json).unwrap();
-
- assert!(
- tt == back.data.macro_body.to_subtree_resolved(v, &span_data_table),
- "version: {v}"
- );
+ lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(),
+ env: Default::default(),
+ current_dir: Default::default(),
+ };
+
+ let json = serde_json::to_string(&task).unwrap();
+ // println!("{}", json);
+ let back: ExpandMacro = serde_json::from_str(&json).unwrap();
+
+ assert_eq!(
+ tt,
+ back.data.macro_body.to_subtree_resolved(v, &span_data_table),
+ "version: {v}"
+ );
+ }
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "sysroot-abi")]
+ fn test_proc_macro_rpc_works_ts() {
+ for tt in [
+ fixture_token_tree_top_many_none,
+ fixture_token_tree_top_empty_none,
+ fixture_token_tree_top_empty_brace,
+ ] {
+ let tt = tt();
+ for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION {
+ let mut span_data_table = Default::default();
+ let flat_tree = FlatTree::from_subtree(tt.view(), v, &mut span_data_table);
+ assert_eq!(
+ tt,
+ flat_tree.clone().to_subtree_resolved(v, &span_data_table),
+ "version: {v}"
+ );
+ let ts = flat_tree.to_tokenstream_resolved(v, &span_data_table, |a, b| a.cover(b));
+ let call_site = *span_data_table.first().unwrap();
+ let mut span_data_table = Default::default();
+ assert_eq!(
+ tt,
+ FlatTree::from_tokenstream(ts.clone(), v, call_site, &mut span_data_table)
+ .to_subtree_resolved(v, &span_data_table),
+ "version: {v}, ts:\n{ts:#?}"
+ );
+ }
}
}
}
diff --git a/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs b/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs
index 92e9038554..1ac8cd4006 100644
--- a/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs
+++ b/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs
@@ -85,7 +85,7 @@ pub fn deserialize_span_data_index_map(map: &[u32]) -> SpanDataIndexMap {
.collect()
}
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FlatTree {
subtree: Vec<u32>,
literal: Vec<u32>,
@@ -615,14 +615,17 @@ impl<'a, T: SpanTransformer>
root: &'a proc_macro_srv::TokenStream<T::Span>,
) {
let call_site = self.token_id_of(call_site);
- self.subtree.push(SubtreeRepr {
- open: call_site,
- close: call_site,
- kind: tt::DelimiterKind::Invisible,
- tt: [!0, !0],
- });
- self.work.push_back((0, root.len(), Some(root.iter())));
-
+ if let Some(group) = root.as_single_group() {
+ self.enqueue(group);
+ } else {
+ self.subtree.push(SubtreeRepr {
+ open: call_site,
+ close: call_site,
+ kind: tt::DelimiterKind::Invisible,
+ tt: [!0, !0],
+ });
+ self.work.push_back((0, root.len(), Some(root.iter())));
+ }
while let Some((idx, len, group)) = self.work.pop_front() {
self.group(idx, len, group);
}
@@ -962,6 +965,11 @@ impl<T: SpanTransformer> Reader<'_, T> {
};
res[i] = Some(g);
}
- res[0].take().unwrap().stream.unwrap_or_default()
+ let group = res[0].take().unwrap();
+ if group.delimiter == proc_macro_srv::Delimiter::None {
+ group.stream.unwrap_or_default()
+ } else {
+ TokenStream::new(vec![proc_macro_srv::TokenTree::Group(group)])
+ }
}
}
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index f0c7ce7efd..85b250eddf 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -11,6 +11,10 @@
feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)
)]
#![allow(internal_features)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
mod codec;
mod framing;
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index e31ab86bdd..d6a8d27bfc 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -58,7 +58,9 @@ impl ProcMacroServerProcess {
if v.pre.as_str() == "nightly" { *v > VERSION } else { *v >= VERSION }
});
- let formats: &[_] = if has_working_format_flag {
+ let formats: &[_] = if std::env::var_os("RUST_ANALYZER_USE_POSTCARD").is_some()
+ && has_working_format_flag
+ {
&[
(Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }),
(Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }),
diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index c3838a8e61..93319df824 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -83,31 +83,10 @@ impl<'env> ProcMacroSrv<'env> {
}
pub fn join_spans(&self, first: Span, second: Span) -> Option<Span> {
- // We can't modify the span range for fixup spans, those are meaningful to fixup, so just
- // prefer the non-fixup span.
- if first.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER {
- return Some(second);
- }
- if second.anchor.ast_id == span::FIXUP_ERASED_FILE_AST_ID_MARKER {
- return Some(first);
- }
- // FIXME: Once we can talk back to the client, implement a "long join" request for anchors
- // that differ in [AstId]s as joining those spans requires resolving the AstIds.
- if first.anchor != second.anchor {
- return None;
- }
- // Differing context, we can't merge these so prefer the one that's root
- if first.ctx != second.ctx {
- if first.ctx.is_root() {
- return Some(second);
- } else if second.ctx.is_root() {
- return Some(first);
- }
- }
- Some(Span {
- range: first.range.cover(second.range),
- anchor: second.anchor,
- ctx: second.ctx,
+ first.join(second, |_, _| {
+ // FIXME: Once we can talk back to the client, implement a "long join" request for anchors
+ // that differ in [AstId]s as joining those spans requires resolving the AstIds.
+ None
})
}
}
diff --git a/crates/proc-macro-srv/src/token_stream.rs b/crates/proc-macro-srv/src/token_stream.rs
index e134a47f8c..36827d2561 100644
--- a/crates/proc-macro-srv/src/token_stream.rs
+++ b/crates/proc-macro-srv/src/token_stream.rs
@@ -40,6 +40,13 @@ impl<S> TokenStream<S> {
TokenStreamIter::new(self)
}
+ pub fn as_single_group(&self) -> Option<&Group<S>> {
+ match &**self.0 {
+ [TokenTree::Group(group)] => Some(group),
+ _ => None,
+ }
+ }
+
pub(crate) fn from_str(s: &str, span: S) -> Result<Self, String>
where
S: SpanLike + Copy,
diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml
index 7e0b1f75f7..f825a456de 100644
--- a/crates/project-model/Cargo.toml
+++ b/crates/project-model/Cargo.toml
@@ -39,5 +39,9 @@ toolchain.workspace = true
[dev-dependencies]
expect-test = "1.5.1"
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 731104981a..6e1a3f37ff 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -305,7 +305,7 @@ impl TargetKind {
/// If this is a valid cargo target, returns the name cargo uses in command line arguments
/// and output, otherwise None.
- /// https://docs.rs/cargo_metadata/latest/cargo_metadata/enum.TargetKind.html
+ /// <https://docs.rs/cargo_metadata/latest/cargo_metadata/enum.TargetKind.html>
pub fn as_cargo_target(self) -> Option<&'static str> {
match self {
TargetKind::Bin => Some("bin"),
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 910bc0a96b..3414b52d45 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -1,7 +1,7 @@
//! In rust-analyzer, we maintain a strict separation between pure abstract
//! semantic project model and a concrete model of a particular build system.
//!
-//! Pure model is represented by the [`base_db::CrateGraph`] from another crate.
+//! Pure model is represented by the `base_db::CrateGraph` from another crate.
//!
//! In this crate, we are concerned with "real world" project models.
//!
@@ -13,7 +13,14 @@
//! * Project discovery (where's the relevant Cargo.toml for the current dir).
//! * Custom build steps (`build.rs` code generation and compilation of
//! procedural macros).
-//! * Lowering of concrete model to a [`base_db::CrateGraph`]
+//! * Lowering of concrete model to a `base_db::CrateGraph`
+
+// It's useful to refer to code that is private in doc comments.
+#![allow(rustdoc::private_intra_doc_links)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
pub mod project_json;
pub mod toolchain_info {
diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs
index d3e1f11d78..041b9accf4 100644
--- a/crates/project-model/src/project_json.rs
+++ b/crates/project-model/src/project_json.rs
@@ -1,6 +1,6 @@
//! `rust-project.json` file format.
//!
-//! This format is spiritually a serialization of [`base_db::CrateGraph`]. The
+//! This format is spiritually a serialization of `base_db::CrateGraph`. The
//! idea here is that people who do not use Cargo, can instead teach their build
//! system to generate `rust-project.json` which can be ingested by
//! rust-analyzer.
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index e02891eca2..10abb21ace 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -1044,7 +1044,7 @@ impl ProjectWorkspace {
/// Returns `true` if the project workspace is [`Json`].
///
- /// [`Json`]: ProjectWorkspace::Json
+ /// [`Json`]: ProjectWorkspaceKind::Json
#[must_use]
pub fn is_json(&self) -> bool {
matches!(self.kind, ProjectWorkspaceKind::Json { .. })
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 2e48c5a5a6..d1283ca59e 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -98,12 +98,16 @@ syntax-bridge.workspace = true
jemalloc = ["jemallocator", "profile/jemalloc"]
force-always-assert = ["stdx/force-always-assert"]
in-rust-tree = [
- "syntax/in-rust-tree",
- "parser/in-rust-tree",
- "hir/in-rust-tree",
+ "cfg/in-rust-tree",
"hir-def/in-rust-tree",
"hir-ty/in-rust-tree",
+ "hir/in-rust-tree",
+ "ide-ssr/in-rust-tree",
+ "ide/in-rust-tree",
"load-cargo/in-rust-tree",
+ "parser/in-rust-tree",
+ "proc-macro-api/in-rust-tree",
+ "syntax/in-rust-tree",
]
dhat = ["dep:dhat"]
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 767672fc2f..f39ab1301f 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -10,8 +10,8 @@ use std::{
use cfg::{CfgAtom, CfgDiff};
use hir::{
- Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasSource, HirDisplay, ModuleDef, Name,
- crate_lang_items,
+ Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasCrate, HasSource, HirDisplay, ModuleDef,
+ Name, crate_lang_items,
db::{DefDatabase, ExpandDatabase, HirDatabase},
next_solver::{DbInterner, GenericArgs},
};
@@ -206,7 +206,7 @@ impl flags::AnalysisStats {
let mut visited_modules = FxHashSet::default();
let mut visit_queue = Vec::new();
for &krate in &krates {
- let module = krate.root_module();
+ let module = krate.root_module(db);
let file_id = module.definition_source_file_id(db);
let file_id = file_id.original_file(db);
@@ -391,7 +391,10 @@ impl flags::AnalysisStats {
let Err(e) = db.layout_of_adt(
hir_def::AdtId::from(a),
GenericArgs::new_from_iter(interner, []),
- db.trait_environment(a.into()),
+ hir_ty::ParamEnvAndCrate {
+ param_env: db.trait_environment(a.into()),
+ krate: a.krate(db).into(),
+ },
) else {
continue;
};
@@ -766,7 +769,7 @@ impl flags::AnalysisStats {
for &body_id in bodies {
let name = body_id.name(db).unwrap_or_else(Name::missing);
let module = body_id.module(db);
- let display_target = module.krate().to_display_target(db);
+ let display_target = module.krate(db).to_display_target(db);
if let Some(only_name) = self.only.as_deref()
&& name.display(db, Edition::LATEST).to_string() != only_name
&& full_name(db, body_id, module) != only_name
@@ -1219,6 +1222,7 @@ impl flags::AnalysisStats {
implied_dyn_trait_hints: true,
lifetime_elision_hints: ide::LifetimeElisionHints::Always,
param_names_for_lifetime_elision_hints: true,
+ hide_inferred_type_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
hide_closure_parameter_hints: false,
@@ -1286,7 +1290,7 @@ impl flags::AnalysisStats {
fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> String {
module
- .krate()
+ .krate(db)
.display_name(db)
.map(|it| it.canonical_name().as_str().to_owned())
.into_iter()
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 82590c8e70..776069f155 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -68,8 +68,12 @@ impl flags::Diagnostics {
if !visited_files.contains(&file_id) {
let message = format!("processing {}", _vfs.file_path(file_id.file_id(db)));
bar.set_message(move || message.clone());
- let crate_name =
- module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned();
+ let crate_name = module
+ .krate(db)
+ .display_name(db)
+ .as_deref()
+ .unwrap_or(&sym::unknown)
+ .to_owned();
for diagnostic in analysis
.full_diagnostics(
&DiagnosticsConfig::test_sample(),
@@ -122,7 +126,7 @@ impl flags::Diagnostics {
fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
let mut worklist: Vec<_> =
- Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
+ Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
let mut modules = Vec::new();
while let Some(module) = worklist.pop() {
diff --git a/crates/rust-analyzer/src/cli/run_tests.rs b/crates/rust-analyzer/src/cli/run_tests.rs
index 60b33f0a30..82ace8c8b3 100644
--- a/crates/rust-analyzer/src/cli/run_tests.rs
+++ b/crates/rust-analyzer/src/cli/run_tests.rs
@@ -78,7 +78,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
let mut worklist: Vec<_> = Crate::all(db)
.into_iter()
.filter(|x| x.origin(db).is_local())
- .map(|krate| krate.root_module())
+ .map(|krate| krate.root_module(db))
.collect();
let mut modules = Vec::new();
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index fbf3082e1b..271d2507bc 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -604,6 +604,29 @@ pub mod example_mod {
}
#[test]
+ fn operator_overload() {
+ check_symbol(
+ r#"
+//- minicore: add
+//- /workspace/lib.rs crate:main
+use core::ops::AddAssign;
+
+struct S;
+
+impl AddAssign for S {
+ fn add_assign(&mut self, _rhs: Self) {}
+}
+
+fn main() {
+ let mut s = S;
+ s +=$0 S;
+}
+"#,
+ "rust-analyzer cargo main . impl#[S][`AddAssign<Self>`]add_assign().",
+ );
+ }
+
+ #[test]
fn symbol_for_trait() {
check_symbol(
r#"
diff --git a/crates/rust-analyzer/src/cli/unresolved_references.rs b/crates/rust-analyzer/src/cli/unresolved_references.rs
index a400f86778..294add682d 100644
--- a/crates/rust-analyzer/src/cli/unresolved_references.rs
+++ b/crates/rust-analyzer/src/cli/unresolved_references.rs
@@ -64,8 +64,12 @@ impl flags::UnresolvedReferences {
let file_id = module.definition_source_file_id(db).original_file(db);
let file_id = file_id.file_id(db);
if !visited_files.contains(&file_id) {
- let crate_name =
- module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned();
+ let crate_name = module
+ .krate(db)
+ .display_name(db)
+ .as_deref()
+ .unwrap_or(&sym::unknown)
+ .to_owned();
let file_path = vfs.file_path(file_id);
eprintln!("processing crate: {crate_name}, module: {file_path}",);
@@ -93,7 +97,7 @@ impl flags::UnresolvedReferences {
fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
let mut worklist: Vec<_> =
- Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
+ Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
let mut modules = Vec::new();
while let Some(module) = worklist.pop() {
diff --git a/crates/rust-analyzer/src/command.rs b/crates/rust-analyzer/src/command.rs
index 41055272b1..2f052618cd 100644
--- a/crates/rust-analyzer/src/command.rs
+++ b/crates/rust-analyzer/src/command.rs
@@ -197,4 +197,22 @@ impl<T: Sized + Send + 'static> CommandHandle<T> {
)))
}
}
+
+ pub(crate) fn has_exited(&mut self) -> bool {
+ match self.child.0.try_wait() {
+ Ok(Some(_exit_code)) => {
+ // We have an exit code.
+ true
+ }
+ Ok(None) => {
+ // Hasn't exited yet.
+ false
+ }
+ Err(_) => {
+ // Couldn't get an exit code. Assume that we've
+ // exited.
+ true
+ }
+ }
+ }
}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index c380621d81..1a2ea97204 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -304,6 +304,9 @@ config_data! {
/// Hide inlay parameter type hints for closures.
inlayHints_typeHints_hideClosureParameter: bool = false,
+ /// Hide inlay type hints for inferred types.
+ inlayHints_typeHints_hideInferredTypes: bool = false,
+
/// Hide inlay type hints for constructors.
inlayHints_typeHints_hideNamedConstructor: bool = false,
@@ -1937,6 +1940,7 @@ impl Config {
hide_named_constructor_hints: self
.inlayHints_typeHints_hideNamedConstructor()
.to_owned(),
+ hide_inferred_type_hints: self.inlayHints_typeHints_hideInferredTypes().to_owned(),
hide_closure_initialization_hints: self
.inlayHints_typeHints_hideClosureInitialization()
.to_owned(),
diff --git a/crates/rust-analyzer/src/discover.rs b/crates/rust-analyzer/src/discover.rs
index 0e96eff278..4aef5b0b7f 100644
--- a/crates/rust-analyzer/src/discover.rs
+++ b/crates/rust-analyzer/src/discover.rs
@@ -67,7 +67,7 @@ impl DiscoverCommand {
cmd.args(args);
Ok(DiscoverHandle {
- _handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
+ handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
span: info_span!("discover_command").entered(),
})
}
@@ -76,7 +76,7 @@ impl DiscoverCommand {
/// A handle to a spawned [Discover].
#[derive(Debug)]
pub(crate) struct DiscoverHandle {
- _handle: CommandHandle<DiscoverProjectMessage>,
+ pub(crate) handle: CommandHandle<DiscoverProjectMessage>,
#[allow(dead_code)] // not accessed, but used to log on drop.
span: EnteredSpan,
}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 91f7db7854..7828f50844 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -45,7 +45,7 @@ use crate::{
op_queue::{Cause, OpQueue},
reload,
target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec},
- task_pool::{TaskPool, TaskQueue},
+ task_pool::{DeferredTaskQueue, TaskPool},
test_runner::{CargoTestHandle, CargoTestMessage},
};
@@ -121,9 +121,10 @@ pub(crate) struct GlobalState {
pub(crate) test_run_remaining_jobs: usize,
// Project loading
- pub(crate) discover_handle: Option<discover::DiscoverHandle>,
+ pub(crate) discover_handles: Vec<discover::DiscoverHandle>,
pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,
+ pub(crate) discover_jobs_active: u32,
// Debouncing channel for fetching the workspace
// we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
@@ -175,7 +176,6 @@ pub(crate) struct GlobalState {
pub(crate) fetch_build_data_queue: OpQueue<(), FetchBuildDataResponse>,
pub(crate) fetch_proc_macros_queue: OpQueue<(ChangeWithProcMacros, Vec<ProcMacroPaths>), bool>,
pub(crate) prime_caches_queue: OpQueue,
- pub(crate) discover_workspace_queue: OpQueue,
/// A deferred task queue.
///
@@ -186,7 +186,8 @@ pub(crate) struct GlobalState {
/// For certain features, such as [`GlobalState::handle_discover_msg`],
/// this queue should run only *after* [`GlobalState::process_changes`] has
/// been called.
- pub(crate) deferred_task_queue: TaskQueue,
+ pub(crate) deferred_task_queue: DeferredTaskQueue,
+
/// HACK: Workaround for https://github.com/rust-lang/rust-analyzer/issues/19709
/// This is marked true if we failed to load a crate root file at crate graph creation,
/// which will usually end up causing a bunch of incorrect diagnostics on startup.
@@ -241,9 +242,9 @@ impl GlobalState {
};
let cancellation_pool = thread::Pool::new(1);
- let task_queue = {
+ let deferred_task_queue = {
let (sender, receiver) = unbounded();
- TaskQueue { sender, receiver }
+ DeferredTaskQueue { sender, receiver }
};
let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity());
@@ -291,9 +292,10 @@ impl GlobalState {
test_run_receiver,
test_run_remaining_jobs: 0,
- discover_handle: None,
+ discover_handles: vec![],
discover_sender,
discover_receiver,
+ discover_jobs_active: 0,
fetch_ws_receiver: None,
@@ -312,9 +314,8 @@ impl GlobalState {
fetch_proc_macros_queue: OpQueue::default(),
prime_caches_queue: OpQueue::default(),
- discover_workspace_queue: OpQueue::default(),
- deferred_task_queue: task_queue,
+ deferred_task_queue,
incomplete_crate_graph: false,
minicore: MiniCoreRustAnalyzerInternalOnly::default(),
@@ -540,10 +541,9 @@ impl GlobalState {
// didn't find anything (to make up for the lack of precision).
{
if !matches!(&workspace_structure_change, Some((.., true))) {
- _ = self
- .deferred_task_queue
- .sender
- .send(crate::main_loop::QueuedTask::CheckProcMacroSources(modified_rust_files));
+ _ = self.deferred_task_queue.sender.send(
+ crate::main_loop::DeferredTask::CheckProcMacroSources(modified_rust_files),
+ );
}
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
// but something's going wrong with the source root business when we add a new local
diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs
index 87be09dcbd..4a6544508f 100644
--- a/crates/rust-analyzer/src/handlers/notification.rs
+++ b/crates/rust-analyzer/src/handlers/notification.rs
@@ -91,7 +91,7 @@ pub(crate) fn handle_did_open_text_document(
let _ = state
.deferred_task_queue
.sender
- .send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri));
+ .send(crate::main_loop::DeferredTask::CheckIfIndexed(params.text_document.uri));
}
}
Ok(())
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 6ae527abb1..971ae2a601 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -9,6 +9,11 @@
//! The `cli` submodule implements some batch-processing analysis, primarily as
//! a debugging aid.
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
extern crate ra_ap_rustc_type_ir as rustc_type_ir;
/// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
diff --git a/crates/rust-analyzer/src/lsp/capabilities.rs b/crates/rust-analyzer/src/lsp/capabilities.rs
index f94e7486ff..d6a694be91 100644
--- a/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -37,7 +37,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
change: Some(TextDocumentSyncKind::INCREMENTAL),
will_save: None,
will_save_wait_until: None,
- save: Some(SaveOptions::default().into()),
+ save: if config.caps().did_save_text_document_dynamic_registration() {
+ None
+ } else {
+ Some(SaveOptions::default().into())
+ },
})),
hover_provider: Some(HoverProviderCapability::Simple(true)),
completion_provider: Some(CompletionOptions {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 8b4748ddb3..1a1c0182f8 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -74,7 +74,7 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
enum Event {
Lsp(lsp_server::Message),
Task(Task),
- QueuedTask(QueuedTask),
+ DeferredTask(DeferredTask),
Vfs(vfs::loader::Message),
Flycheck(FlycheckMessage),
TestResult(CargoTestMessage),
@@ -89,7 +89,7 @@ impl fmt::Display for Event {
Event::Task(_) => write!(f, "Event::Task"),
Event::Vfs(_) => write!(f, "Event::Vfs"),
Event::Flycheck(_) => write!(f, "Event::Flycheck"),
- Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
+ Event::DeferredTask(_) => write!(f, "Event::DeferredTask"),
Event::TestResult(_) => write!(f, "Event::TestResult"),
Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"),
@@ -98,7 +98,7 @@ impl fmt::Display for Event {
}
#[derive(Debug)]
-pub(crate) enum QueuedTask {
+pub(crate) enum DeferredTask {
CheckIfIndexed(lsp_types::Url),
CheckProcMacroSources(Vec<FileId>),
}
@@ -164,7 +164,7 @@ impl fmt::Debug for Event {
match self {
Event::Lsp(it) => fmt::Debug::fmt(it, f),
Event::Task(it) => fmt::Debug::fmt(it, f),
- Event::QueuedTask(it) => fmt::Debug::fmt(it, f),
+ Event::DeferredTask(it) => fmt::Debug::fmt(it, f),
Event::Vfs(it) => fmt::Debug::fmt(it, f),
Event::Flycheck(it) => fmt::Debug::fmt(it, f),
Event::TestResult(it) => fmt::Debug::fmt(it, f),
@@ -279,7 +279,7 @@ impl GlobalState {
task.map(Event::Task),
recv(self.deferred_task_queue.receiver) -> task =>
- task.map(Event::QueuedTask),
+ task.map(Event::DeferredTask),
recv(self.fmt_pool.receiver) -> task =>
task.map(Event::Task),
@@ -323,12 +323,12 @@ impl GlobalState {
lsp_server::Message::Notification(not) => self.on_notification(not),
lsp_server::Message::Response(resp) => self.complete_request(resp),
},
- Event::QueuedTask(task) => {
+ Event::DeferredTask(task) => {
let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered();
- self.handle_queued_task(task);
- // Coalesce multiple task events into one loop turn
+ self.handle_deferred_task(task);
+ // Coalesce multiple deferred task events into one loop turn
while let Ok(task) = self.deferred_task_queue.receiver.try_recv() {
- self.handle_queued_task(task);
+ self.handle_deferred_task(task);
}
}
Event::Task(task) => {
@@ -437,11 +437,17 @@ impl GlobalState {
}
}
Event::Flycheck(message) => {
- let _p = tracing::info_span!("GlobalState::handle_event/flycheck").entered();
- self.handle_flycheck_msg(message);
+ let mut cargo_finished = false;
+ self.handle_flycheck_msg(message, &mut cargo_finished);
// Coalesce many flycheck updates into a single loop turn
while let Ok(message) = self.flycheck_receiver.try_recv() {
- self.handle_flycheck_msg(message);
+ self.handle_flycheck_msg(message, &mut cargo_finished);
+ }
+ if cargo_finished {
+ self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
+ (),
+ |_, _| (),
+ );
}
}
Event::TestResult(message) => {
@@ -531,6 +537,8 @@ impl GlobalState {
}
}
+ self.cleanup_discover_handles();
+
if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
for file_id in diagnostic_changes {
let uri = file_id_to_url(&self.vfs.read().0, file_id);
@@ -806,33 +814,34 @@ impl GlobalState {
self.report_progress("Fetching", state, msg, None, None);
}
Task::DiscoverLinkedProjects(arg) => {
- if let Some(cfg) = self.config.discover_workspace_config()
- && !self.discover_workspace_queue.op_in_progress()
- {
+ if let Some(cfg) = self.config.discover_workspace_config() {
// the clone is unfortunately necessary to avoid a borrowck error when
// `self.report_progress` is called later
let title = &cfg.progress_label.clone();
let command = cfg.command.clone();
let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
- self.report_progress(title, Progress::Begin, None, None, None);
- self.discover_workspace_queue
- .request_op("Discovering workspace".to_owned(), ());
- let _ = self.discover_workspace_queue.should_start_op();
+ if self.discover_jobs_active == 0 {
+ self.report_progress(title, Progress::Begin, None, None, None);
+ }
+ self.discover_jobs_active += 1;
let arg = match arg {
DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
};
- let handle = discover.spawn(
- arg,
- &std::env::current_dir()
- .expect("Failed to get cwd during project discovery"),
- );
- self.discover_handle = Some(handle.unwrap_or_else(|e| {
- panic!("Failed to spawn project discovery command: {e}")
- }));
+ let handle = discover
+ .spawn(
+ arg,
+ &std::env::current_dir()
+ .expect("Failed to get cwd during project discovery"),
+ )
+ .unwrap_or_else(|e| {
+ panic!("Failed to spawn project discovery command: {e}")
+ });
+
+ self.discover_handles.push(handle);
}
}
Task::FetchBuildData(progress) => {
@@ -981,9 +990,9 @@ impl GlobalState {
}
}
- fn handle_queued_task(&mut self, task: QueuedTask) {
+ fn handle_deferred_task(&mut self, task: DeferredTask) {
match task {
- QueuedTask::CheckIfIndexed(uri) => {
+ DeferredTask::CheckIfIndexed(uri) => {
let snap = self.snapshot();
self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
@@ -1007,7 +1016,7 @@ impl GlobalState {
}
});
}
- QueuedTask::CheckProcMacroSources(modified_rust_files) => {
+ DeferredTask::CheckProcMacroSources(modified_rust_files) => {
let analysis = AssertUnwindSafe(self.snapshot().analysis);
self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, {
move |sender| {
@@ -1036,25 +1045,43 @@ impl GlobalState {
.expect("No title could be found; this is a bug");
match message {
DiscoverProjectMessage::Finished { project, buildfile } => {
- self.discover_handle = None;
- self.report_progress(&title, Progress::End, None, None, None);
- self.discover_workspace_queue.op_completed(());
+ self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
+ if self.discover_jobs_active == 0 {
+ self.report_progress(&title, Progress::End, None, None, None);
+ }
let mut config = Config::clone(&*self.config);
config.add_discovered_project_from_command(project, buildfile);
self.update_configuration(config);
}
DiscoverProjectMessage::Progress { message } => {
- self.report_progress(&title, Progress::Report, Some(message), None, None)
+ if self.discover_jobs_active > 0 {
+ self.report_progress(&title, Progress::Report, Some(message), None, None)
+ }
}
DiscoverProjectMessage::Error { error, source } => {
- self.discover_handle = None;
let message = format!("Project discovery failed: {error}");
- self.discover_workspace_queue.op_completed(());
self.show_and_log_error(message.clone(), source);
- self.report_progress(&title, Progress::End, Some(message), None, None)
+
+ self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
+ if self.discover_jobs_active == 0 {
+ self.report_progress(&title, Progress::End, Some(message), None, None)
+ }
+ }
+ }
+ }
+
+ /// Drop any discover command processes that have exited, due to
+ /// finishing or erroring.
+ fn cleanup_discover_handles(&mut self) {
+ let mut active_handles = vec![];
+
+ for mut discover_handle in self.discover_handles.drain(..) {
+ if !discover_handle.handle.has_exited() {
+ active_handles.push(discover_handle);
}
}
+ self.discover_handles = active_handles;
}
fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {
@@ -1088,7 +1115,7 @@ impl GlobalState {
}
}
- fn handle_flycheck_msg(&mut self, message: FlycheckMessage) {
+ fn handle_flycheck_msg(&mut self, message: FlycheckMessage, cargo_finished: &mut bool) {
match message {
FlycheckMessage::AddDiagnostic {
id,
@@ -1146,6 +1173,7 @@ impl GlobalState {
flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
flycheck::Progress::DidCancel => {
self.last_flycheck_error = None;
+ *cargo_finished = true;
(Progress::End, None)
}
flycheck::Progress::DidFailToRestart(err) => {
@@ -1156,6 +1184,7 @@ impl GlobalState {
flycheck::Progress::DidFinish(result) => {
self.last_flycheck_error =
result.err().map(|err| format!("cargo check failed to start: {err}"));
+ *cargo_finished = true;
(Progress::End, None)
}
};
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 8876b850be..317c112365 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -74,7 +74,7 @@ impl GlobalState {
&& !self.fetch_workspaces_queue.op_in_progress()
&& !self.fetch_build_data_queue.op_in_progress()
&& !self.fetch_proc_macros_queue.op_in_progress()
- && !self.discover_workspace_queue.op_in_progress()
+ && self.discover_jobs_active == 0
&& self.vfs_progress_config_version >= self.vfs_config_version
}
@@ -297,7 +297,7 @@ impl GlobalState {
.collect();
let cargo_config = self.config.cargo(None);
let discover_command = self.config.discover_workspace_config().cloned();
- let is_quiescent = !(self.discover_workspace_queue.op_in_progress()
+ let is_quiescent = !(self.discover_jobs_active > 0
|| self.vfs_progress_config_version < self.vfs_config_version
|| !self.vfs_done);
diff --git a/crates/rust-analyzer/src/task_pool.rs b/crates/rust-analyzer/src/task_pool.rs
index c5de69bb9f..ef0feb1796 100644
--- a/crates/rust-analyzer/src/task_pool.rs
+++ b/crates/rust-analyzer/src/task_pool.rs
@@ -6,7 +6,7 @@ use std::panic::UnwindSafe;
use crossbeam_channel::Sender;
use stdx::thread::{Pool, ThreadIntent};
-use crate::main_loop::QueuedTask;
+use crate::main_loop::DeferredTask;
pub(crate) struct TaskPool<T> {
sender: Sender<T>,
@@ -45,11 +45,11 @@ impl<T> TaskPool<T> {
}
}
-/// `TaskQueue`, like its name suggests, queues tasks.
+/// `DeferredTaskQueue` holds deferred tasks.
///
-/// This should only be used if a task must run after [`GlobalState::process_changes`]
-/// has been called.
-pub(crate) struct TaskQueue {
- pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
- pub(crate) receiver: crossbeam_channel::Receiver<QueuedTask>,
+/// These are tasks that must be run after
+/// [`GlobalState::process_changes`] has been called.
+pub(crate) struct DeferredTaskQueue {
+ pub(crate) sender: crossbeam_channel::Sender<DeferredTask>,
+ pub(crate) receiver: crossbeam_channel::Receiver<DeferredTask>,
}
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 5a4ad6f380..48433342d5 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -9,6 +9,10 @@
//! be sure without a real client anyway.
#![allow(clippy::disallowed_types)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
mod cli;
mod ratoml;
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index b1b428e706..195ad226ae 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -48,6 +48,7 @@ impl Project<'_> {
"enable": false,
},
},
+ "checkOnSave": false,
"procMacro": {
"enable": false,
}
diff --git a/crates/span/Cargo.toml b/crates/span/Cargo.toml
index 966962bab3..cfb319d688 100644
--- a/crates/span/Cargo.toml
+++ b/crates/span/Cargo.toml
@@ -27,6 +27,7 @@ syntax.workspace = true
[features]
default = ["salsa"]
+in-rust-tree = []
[lints]
workspace = true
diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs
index e803747998..bd49e08b10 100644
--- a/crates/span/src/ast_id.rs
+++ b/crates/span/src/ast_id.rs
@@ -44,6 +44,7 @@ pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be
/// considered fake.
+/// Do not modify this, it is used by the proc-macro server.
pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32));
@@ -700,7 +701,7 @@ impl AstIdMap {
}
}
- /// The [`AstId`] of the root node
+ /// The root node.
pub fn root(&self) -> SyntaxNodePtr {
self.arena[Idx::from_raw(RawIdx::from_u32(0))].0
}
diff --git a/crates/span/src/hygiene.rs b/crates/span/src/hygiene.rs
index 6c363825aa..6805417177 100644
--- a/crates/span/src/hygiene.rs
+++ b/crates/span/src/hygiene.rs
@@ -249,7 +249,7 @@ const _: () = {
)
}
- /// Invariant: Only [`SyntaxContext::ROOT`] has a [`None`] outer expansion.
+ /// Invariant: Only the root [`SyntaxContext`] has a [`None`] outer expansion.
// FIXME: The None case needs to encode the context crate id. We can encode that as the MSB of
// MacroCallId is reserved anyways so we can do bit tagging here just fine.
// The bigger issue is that this will cause interning to now create completely separate chains
@@ -348,7 +348,7 @@ impl SyntaxContext {
}
}
- /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context.
+ /// The root context, which is the parent of all other contexts. All `FileId`s have this context.
#[inline]
pub const fn root(edition: Edition) -> Self {
let edition = edition as u32;
diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs
index ae9e038459..c44b0198b7 100644
--- a/crates/span/src/lib.rs
+++ b/crates/span/src/lib.rs
@@ -1,4 +1,10 @@
//! File and span related types.
+
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
use std::fmt::{self, Write};
mod ast_id;
@@ -28,6 +34,33 @@ impl Span {
let range = self.range.cover(other.range);
Span { range, ..self }
}
+
+ pub fn join(
+ self,
+ other: Span,
+ differing_anchor: impl FnOnce(Span, Span) -> Option<Span>,
+ ) -> Option<Span> {
+ // We can't modify the span range for fixup spans, those are meaningful to fixup, so just
+ // prefer the non-fixup span.
+ if self.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ return Some(other);
+ }
+ if other.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ return Some(self);
+ }
+ if self.anchor != other.anchor {
+ return differing_anchor(self, other);
+ }
+ // Differing context, we can't merge these so prefer the one that's root
+ if self.ctx != other.ctx {
+ if self.ctx.is_root() {
+ return Some(other);
+ } else if other.ctx.is_root() {
+ return Some(self);
+ }
+ }
+ Some(Span { range: self.range.cover(other.range), anchor: other.anchor, ctx: other.ctx })
+ }
}
/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
diff --git a/crates/syntax-bridge/src/lib.rs b/crates/syntax-bridge/src/lib.rs
index 1ded2b4113..815b4f2799 100644
--- a/crates/syntax-bridge/src/lib.rs
+++ b/crates/syntax-bridge/src/lib.rs
@@ -1,5 +1,10 @@
//! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
use std::{collections::VecDeque, fmt, hash::Hash};
use intern::Symbol;
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 1ee93013e3..8909fb423c 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -33,6 +33,7 @@ rustc_apfloat = "0.2.3"
test-utils.workspace = true
[features]
+default = []
in-rust-tree = []
[lints]
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index dba39204e3..b2904ce3c0 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -658,7 +658,7 @@ pub fn expr_if(
};
expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
}
-pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
+pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr {
expr_from_text(&format!("for {pat} in {expr} {block}"))
}
@@ -1016,7 +1016,19 @@ pub fn item_static(
}
pub fn unnamed_param(ty: ast::Type) -> ast::Param {
- ast_from_text(&format!("fn f({ty}) {{ }}"))
+ quote! {
+ Param {
+ #ty
+ }
+ }
+}
+
+pub fn untyped_param(pat: ast::Pat) -> ast::Param {
+ quote! {
+ Param {
+ #pat
+ }
+ }
}
pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
@@ -1456,3 +1468,86 @@ pub mod tokens {
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use expect_test::expect;
+
+ use super::*;
+
+ #[track_caller]
+ fn check(node: impl AstNode, expect: expect_test::Expect) {
+ let node_debug = format!("{:#?}", node.syntax());
+ expect.assert_eq(&node_debug);
+ }
+
+ #[test]
+ fn test_unnamed_param() {
+ check(
+ unnamed_param(ty("Vec")),
+ expect![[r#"
+ "#]],
+ );
+
+ check(
+ unnamed_param(ty("Vec<T>")),
+ expect![[r#"
+ "#]],
+ );
+ }
+
+ #[test]
+ fn test_untyped_param() {
+ check(
+ untyped_param(path_pat(ext::ident_path("name"))),
+ expect![[r#"
+ "#]],
+ );
+
+ check(
+ untyped_param(
+ range_pat(
+ Some(path_pat(ext::ident_path("start"))),
+ Some(path_pat(ext::ident_path("end"))),
+ )
+ .into(),
+ ),
+ expect![[r#"
+ "#]],
+ );
+ }
+}
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 901d17bb14..b872221bf7 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -813,13 +813,16 @@ pub enum TypeBoundKind {
}
impl ast::TypeBound {
- pub fn kind(&self) -> TypeBoundKind {
+ pub fn kind(&self) -> Option<TypeBoundKind> {
if let Some(path_type) = support::children(self.syntax()).next() {
- TypeBoundKind::PathType(self.for_binder(), path_type)
+ Some(TypeBoundKind::PathType(self.for_binder(), path_type))
+ } else if let Some(for_binder) = support::children::<ast::ForType>(&self.syntax).next() {
+ let Some(ast::Type::PathType(path_type)) = for_binder.ty() else { return None };
+ Some(TypeBoundKind::PathType(for_binder.for_binder(), path_type))
} else if let Some(args) = self.use_bound_generic_args() {
- TypeBoundKind::Use(args)
+ Some(TypeBoundKind::Use(args))
} else if let Some(lifetime) = self.lifetime() {
- TypeBoundKind::Lifetime(lifetime)
+ Some(TypeBoundKind::Lifetime(lifetime))
} else {
unreachable!()
}
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index 9695523921..aca6fcfb2e 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -71,6 +71,188 @@ impl SyntaxFactory {
ast
}
+ pub fn path_from_text(&self, text: &str) -> ast::Path {
+ make::path_from_text(text).clone_for_update()
+ }
+
+ pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr {
+ let ast::Expr::FieldExpr(ast) =
+ make::expr_field(receiver.clone(), field).clone_for_update()
+ else {
+ unreachable!()
+ };
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_node(receiver.syntax().clone(), ast.expr().unwrap().syntax().clone());
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
+ pub fn impl_trait(
+ &self,
+ attrs: impl IntoIterator<Item = ast::Attr>,
+ is_unsafe: bool,
+ trait_gen_params: Option<ast::GenericParamList>,
+ trait_gen_args: Option<ast::GenericArgList>,
+ type_gen_params: Option<ast::GenericParamList>,
+ type_gen_args: Option<ast::GenericArgList>,
+ is_negative: bool,
+ path_type: ast::Type,
+ ty: ast::Type,
+ trait_where_clause: Option<ast::WhereClause>,
+ ty_where_clause: Option<ast::WhereClause>,
+ body: Option<ast::AssocItemList>,
+ ) -> ast::Impl {
+ let (attrs, attrs_input) = iterator_input(attrs);
+ let ast = make::impl_trait(
+ attrs,
+ is_unsafe,
+ trait_gen_params.clone(),
+ trait_gen_args.clone(),
+ type_gen_params.clone(),
+ type_gen_args.clone(),
+ is_negative,
+ path_type.clone(),
+ ty.clone(),
+ trait_where_clause.clone(),
+ ty_where_clause.clone(),
+ body.clone(),
+ )
+ .clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
+ if let Some(trait_gen_params) = trait_gen_params {
+ builder.map_node(
+ trait_gen_params.syntax().clone(),
+ ast.generic_param_list().unwrap().syntax().clone(),
+ );
+ }
+ builder.map_node(path_type.syntax().clone(), ast.trait_().unwrap().syntax().clone());
+ builder.map_node(ty.syntax().clone(), ast.self_ty().unwrap().syntax().clone());
+ if let Some(ty_where_clause) = ty_where_clause {
+ builder.map_node(
+ ty_where_clause.syntax().clone(),
+ ast.where_clause().unwrap().syntax().clone(),
+ );
+ }
+ if let Some(body) = body {
+ builder.map_node(
+ body.syntax().clone(),
+ ast.assoc_item_list().unwrap().syntax().clone(),
+ );
+ }
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
+ pub fn ty_alias(
+ &self,
+ attrs: impl IntoIterator<Item = ast::Attr>,
+ ident: &str,
+ generic_param_list: Option<ast::GenericParamList>,
+ type_param_bounds: Option<ast::TypeParam>,
+ where_clause: Option<ast::WhereClause>,
+ assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
+ ) -> ast::TypeAlias {
+ let (attrs, attrs_input) = iterator_input(attrs);
+ let ast = make::ty_alias(
+ attrs,
+ ident,
+ generic_param_list.clone(),
+ type_param_bounds.clone(),
+ where_clause.clone(),
+ assignment.clone(),
+ )
+ .clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
+ if let Some(generic_param_list) = generic_param_list {
+ builder.map_node(
+ generic_param_list.syntax().clone(),
+ ast.generic_param_list().unwrap().syntax().clone(),
+ );
+ }
+ if let Some(type_param_bounds) = type_param_bounds {
+ builder.map_node(
+ type_param_bounds.syntax().clone(),
+ ast.type_bound_list().unwrap().syntax().clone(),
+ );
+ }
+ if let Some(where_clause) = where_clause {
+ builder.map_node(
+ where_clause.syntax().clone(),
+ ast.where_clause().unwrap().syntax().clone(),
+ );
+ }
+ if let Some((ty, _)) = assignment {
+ builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone());
+ }
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
+ pub fn param_list(
+ &self,
+ self_param: Option<ast::SelfParam>,
+ params: impl IntoIterator<Item = ast::Param>,
+ ) -> ast::ParamList {
+ let (params, input) = iterator_input(params);
+ let ast = make::param_list(self_param.clone(), params).clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ if let Some(self_param) = self_param
+ && let Some(new_self_param) = ast.self_param()
+ {
+ builder.map_node(self_param.syntax().clone(), new_self_param.syntax().clone());
+ }
+ builder.map_children(input, ast.params().map(|p| p.syntax().clone()));
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
+ pub fn const_param(&self, name: ast::Name, ty: ast::Type) -> ast::ConstParam {
+ let ast = make::const_param(name.clone(), ty.clone()).clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone());
+ builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone());
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
+ pub fn generic_param_list(
+ &self,
+ params: impl IntoIterator<Item = ast::GenericParam>,
+ ) -> ast::GenericParamList {
+ let (params, input) = iterator_input(params);
+ let ast = make::generic_param_list(params).clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_children(input, ast.generic_params().map(|p| p.syntax().clone()));
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment {
let ast = make::path_segment(name_ref.clone()).clone_for_update();
@@ -671,6 +853,26 @@ impl SyntaxFactory {
ast
}
+ pub fn expr_for_loop(
+ &self,
+ pat: ast::Pat,
+ iterable: ast::Expr,
+ body: ast::BlockExpr,
+ ) -> ast::ForExpr {
+ let ast =
+ make::expr_for_loop(pat.clone(), iterable.clone(), body.clone()).clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
+ builder.map_node(iterable.syntax().clone(), ast.iterable().unwrap().syntax().clone());
+ builder.map_node(body.syntax().clone(), ast.loop_body().unwrap().syntax().clone());
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update();
@@ -1272,6 +1474,23 @@ impl SyntaxFactory {
ast
}
+ pub fn assoc_item_list(
+ &self,
+ items: impl IntoIterator<Item = ast::AssocItem>,
+ ) -> ast::AssocItemList {
+ let (items, input) = iterator_input(items);
+ let items_vec: Vec<_> = items.into_iter().collect();
+ let ast = make::assoc_item_list(Some(items_vec)).clone_for_update();
+
+ if let Some(mut mapping) = self.mappings() {
+ let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+ builder.map_children(input, ast.assoc_items().map(|item| item.syntax().clone()));
+ builder.finish(&mut mapping);
+ }
+
+ ast
+ }
+
pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr {
let ast = make::attr_outer(meta.clone()).clone_for_update();
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 7346b93192..9e3083066c 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -19,6 +19,11 @@
//! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
mod parsing;
mod ptr;
mod syntax_error;
@@ -282,7 +287,7 @@ fn api_walkthrough() {
assert!(parse.errors().is_empty());
// The `tree` method returns an owned syntax node of type `SourceFile`.
- // Owned nodes are cheap: inside, they are `Rc` handles to the underling data.
+ // Owned nodes are cheap: inside, they are `Rc` handles to the underlying data.
let file: SourceFile = parse.tree();
// `SourceFile` is the root of the syntax tree. We can iterate file's items.
diff --git a/crates/test-fixture/Cargo.toml b/crates/test-fixture/Cargo.toml
index 353d4c312d..7760ae7aa0 100644
--- a/crates/test-fixture/Cargo.toml
+++ b/crates/test-fixture/Cargo.toml
@@ -21,5 +21,9 @@ intern.workspace = true
triomphe.workspace = true
paths.workspace = true
+[features]
+default = []
+in-rust-tree = []
+
[lints]
workspace = true
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index 457cd3ac85..5e8b250c24 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -1,4 +1,10 @@
//! A set of high-level utility fixture methods to use in tests.
+
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
use std::{any::TypeId, mem, str::FromStr, sync};
use base_db::target::TargetData;
diff --git a/crates/test-utils/src/assert_linear.rs b/crates/test-utils/src/assert_linear.rs
index f78bf59a2f..27665a74dc 100644
--- a/crates/test-utils/src/assert_linear.rs
+++ b/crates/test-utils/src/assert_linear.rs
@@ -11,7 +11,7 @@
//! Ideally, we should use a proper "model selection" to directly compare
//! quadratic and linear models, but that sounds rather complicated:
//!
-//! > https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data
+//! > <https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data>
//!
//! We might get false positives on a VM, but never false negatives. So, if the
//! first round fails, we repeat the ordeal three more times and fail only if
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index 559894ee62..831d2b30c1 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -96,9 +96,10 @@ pub struct Fixture {
///
/// Syntax: `cfg:test,dbg=false,opt_level=2`
pub cfgs: Vec<(String, Option<String>)>,
- /// Specifies the edition of this crate. This must be used with `crate` meta. If
- /// this is not specified, ([`base_db::input::Edition::CURRENT`]) will be used.
- /// This must be used with `crate` meta.
+ /// Specifies the edition of this crate. This must be used with
+ /// `crate` meta. If this is not specified,
+ /// `base_db::input::Edition::CURRENT` will be used. This must be
+ /// used with `crate` meta.
///
/// Syntax: `edition:2021`
pub edition: Option<String>,
@@ -106,8 +107,8 @@ pub struct Fixture {
///
/// Syntax: `env:PATH=/bin,RUST_LOG=debug`
pub env: FxHashMap<String, String>,
- /// Introduces a new [source root](base_db::input::SourceRoot). This file **and
- /// the following files** will belong the new source root. This must be used
+ /// Introduces a new source root. This file **and the following
+ /// files** will belong the new source root. This must be used
/// with `crate` meta.
///
/// Use this if you want to test something that uses `SourceRoot::is_library()`
@@ -126,7 +127,7 @@ pub struct Fixture {
/// This is implied if this file belongs to a library source root.
///
/// Use this if you want to test something that checks if a crate is a workspace
- /// member via [`CrateOrigin`](base_db::input::CrateOrigin).
+ /// member via `CrateOrigin`.
///
/// Syntax: `library`
pub library: bool,
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 0fe17e3075..b7c09391ec 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -34,7 +34,8 @@
//! eq: sized
//! error: fmt
//! fmt: option, result, transmute, coerce_unsized, copy, clone, derive
-//! fmt_before_1_89_0: fmt
+//! fmt_before_1_93_0: fmt
+//! fmt_before_1_89_0: fmt_before_1_93_0
//! fn: sized, tuple
//! from: sized, result
//! future: pin
@@ -1259,6 +1260,7 @@ pub mod fmt {
Unknown,
}
+ // region:fmt_before_1_93_0
#[lang = "format_count"]
pub enum Count {
Is(usize),
@@ -1288,6 +1290,7 @@ pub mod fmt {
Placeholder { position, fill, align, flags, precision, width }
}
}
+ // endregion:fmt_before_1_93_0
// region:fmt_before_1_89_0
#[lang = "format_unsafe_arg"]
@@ -1303,6 +1306,7 @@ pub mod fmt {
// endregion:fmt_before_1_89_0
}
+ // region:fmt_before_1_93_0
#[derive(Copy, Clone)]
#[lang = "format_arguments"]
pub struct Arguments<'a> {
@@ -1341,6 +1345,14 @@ pub mod fmt {
}
// endregion:!fmt_before_1_89_0
+ pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
+ Self::from_str(s)
+ }
+
+ pub const fn from_str(s: &'static str) -> Arguments<'a> {
+ Arguments { pieces: &[s], fmt: None, args: &[] }
+ }
+
pub const fn as_str(&self) -> Option<&'static str> {
match (self.pieces, self.args) {
([], []) => Some(""),
@@ -1349,6 +1361,41 @@ pub mod fmt {
}
}
}
+ // endregion:fmt_before_1_93_0
+
+ // region:!fmt_before_1_93_0
+ #[lang = "format_arguments"]
+ #[derive(Copy, Clone)]
+ pub struct Arguments<'a> {
+ // This is a non-faithful representation of `core::fmt::Arguments`, because the real one
+ // is too complex for minicore.
+ message: Option<&'a str>,
+ }
+
+ impl<'a> Arguments<'a> {
+ pub unsafe fn new<const N: usize, const M: usize>(
+ _template: &'a [u8; N],
+ _args: &'a [rt::Argument<'a>; M],
+ ) -> Arguments<'a> {
+ Arguments { message: None }
+ }
+
+ pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
+ Arguments { message: Some(s) }
+ }
+
+ pub const fn from_str(s: &'static str) -> Arguments<'a> {
+ Arguments { message: Some(s) }
+ }
+
+ pub fn as_str(&self) -> Option<&'static str> {
+ match self.message {
+ Some(s) => unsafe { Some(&*(s as *const str)) },
+ None => None,
+ }
+ }
+ }
+ // endregion:!fmt_before_1_93_0
// region:derive
pub(crate) mod derive {
@@ -1817,7 +1864,7 @@ mod panicking {
#[lang = "panic"]
pub const fn panic(expr: &'static str) -> ! {
- panic_fmt(crate::fmt::Arguments::new_const(&[expr]))
+ panic_fmt(crate::fmt::Arguments::from_str(expr))
}
}
// endregion:panic
diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml
index 82e7c24668..3183b72a66 100644
--- a/crates/tt/Cargo.toml
+++ b/crates/tt/Cargo.toml
@@ -21,6 +21,7 @@ intern.workspace = true
ra-ap-rustc_lexer.workspace = true
[features]
+default = []
in-rust-tree = []
[lints]
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index ea0752250d..d6a743c695 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -5,6 +5,9 @@
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_lexer as rustc_lexer;
#[cfg(feature = "in-rust-tree")]
diff --git a/docs/book/README.md b/docs/book/README.md
index 11f7e8f98c..0a3161f3af 100644
--- a/docs/book/README.md
+++ b/docs/book/README.md
@@ -8,7 +8,6 @@ To run the documentation site locally:
```shell
cargo install mdbook
-cargo install mdbook-toc
cargo xtask codegen
cd docs/book
mdbook serve
diff --git a/docs/book/book.toml b/docs/book/book.toml
index c77eabda14..0978851d50 100644
--- a/docs/book/book.toml
+++ b/docs/book/book.toml
@@ -33,8 +33,3 @@ use-boolean-and = true
[output.html.fold]
enable = true
level = 3
-
-[preprocessor.toc]
-command = "mdbook-toc"
-renderer = ["html"]
-max-level = 3
diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md
index fe1ea57c9b..b36576b4bb 100644
--- a/docs/book/src/configuration_generated.md
+++ b/docs/book/src/configuration_generated.md
@@ -1118,6 +1118,13 @@ Default: `false`
Hide inlay parameter type hints for closures.
+## rust-analyzer.inlayHints.typeHints.hideInferredTypes {#inlayHints.typeHints.hideInferredTypes}
+
+Default: `false`
+
+Hide inlay type hints for inferred types.
+
+
## rust-analyzer.inlayHints.typeHints.hideNamedConstructor {#inlayHints.typeHints.hideNamedConstructor}
Default: `false`
diff --git a/docs/book/src/contributing/README.md b/docs/book/src/contributing/README.md
index ad2816b18a..c95a1dba62 100644
--- a/docs/book/src/contributing/README.md
+++ b/docs/book/src/contributing/README.md
@@ -26,8 +26,6 @@ Discussion happens in this Zulip stream:
<https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer>
-<!-- toc -->
-
# Issue Labels
* [good-first-issue](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)
diff --git a/docs/book/src/contributing/architecture.md b/docs/book/src/contributing/architecture.md
index f2b6c053b0..67653ebd74 100644
--- a/docs/book/src/contributing/architecture.md
+++ b/docs/book/src/contributing/architecture.md
@@ -20,8 +20,6 @@ For older, by now mostly outdated stuff, see the [guide](./guide.md) and [anothe
![](https://user-images.githubusercontent.com/4789492/107129398-0ab70f00-687a-11eb-9bfc-d4eb023aec06.png)
-<!-- toc -->
-
On the highest level, rust-analyzer is a thing which accepts input source code from the client and produces a structured semantic model of the code.
More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`.
diff --git a/docs/book/src/contributing/guide.md b/docs/book/src/contributing/guide.md
index 774eb5b2a5..9e944bfe0f 100644
--- a/docs/book/src/contributing/guide.md
+++ b/docs/book/src/contributing/guide.md
@@ -12,8 +12,6 @@ however, it's based on an older 2019-01-20 release (git tag [guide-2019-01]):
[guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01
[2024-01-01]: https://github.com/rust-lang/rust-analyzer/tree/2024-01-01
-<!-- toc -->
-
## The big picture
On the highest possible level, rust-analyzer is a stateful component. A client may
diff --git a/docs/book/src/contributing/lsp-extensions.md b/docs/book/src/contributing/lsp-extensions.md
index 0e91e12612..5922f0b551 100644
--- a/docs/book/src/contributing/lsp-extensions.md
+++ b/docs/book/src/contributing/lsp-extensions.md
@@ -19,8 +19,6 @@ Requests, which are likely to always remain specific to `rust-analyzer` are unde
If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604).
-<!-- toc -->
-
## Configuration in `initializationOptions`
**Upstream Issue:** <https://github.com/microsoft/language-server-protocol/issues/567>
diff --git a/docs/book/src/other_editors.md b/docs/book/src/other_editors.md
index 896df52af5..f7116fc19a 100644
--- a/docs/book/src/other_editors.md
+++ b/docs/book/src/other_editors.md
@@ -6,8 +6,6 @@ Protocol](https://microsoft.github.io/language-server-protocol/).
This page assumes that you have already [installed the rust-analyzer
binary](./rust_analyzer_binary.html).
-<!-- toc -->
-
## Emacs
To use `rust-analyzer`, you need to install and enable one of the two
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index d49d19fbe1..00d83e9068 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -1486,6 +1486,7 @@
"integrity": "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.25.0",
"@typescript-eslint/types": "8.25.0",
@@ -1869,6 +1870,7 @@
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2838,6 +2840,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -3319,6 +3322,7 @@
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -4406,6 +4410,7 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"license": "MIT",
+ "peer": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -4508,25 +4513,25 @@
}
},
"node_modules/jsonwebtoken/node_modules/jwa": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
- "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+ "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "buffer-equal-constant-time": "1.0.1",
+ "buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jsonwebtoken/node_modules/jws": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz",
+ "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jwa": "^1.4.1",
+ "jwa": "^1.4.2",
"safe-buffer": "^5.0.1"
}
},
@@ -4544,25 +4549,25 @@
}
},
"node_modules/jwa": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
- "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
+ "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "buffer-equal-constant-time": "1.0.1",
+ "buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
- "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
+ "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jwa": "^2.0.0",
+ "jwa": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
@@ -6673,6 +6678,7 @@
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
diff --git a/editors/code/package.json b/editors/code/package.json
index 8475864427..abe85d6c9d 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -2469,6 +2469,16 @@
{
"title": "Inlay Hints",
"properties": {
+ "rust-analyzer.inlayHints.typeHints.hideInferredTypes": {
+ "markdownDescription": "Hide inlay type hints for inferred types.",
+ "default": false,
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "title": "Inlay Hints",
+ "properties": {
"rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
"markdownDescription": "Hide inlay type hints for constructors.",
"default": false,
diff --git a/rust-version b/rust-version
index 7a84872f26..dcf82c94aa 100644
--- a/rust-version
+++ b/rust-version
@@ -1 +1 @@
-dfe1b8c97bcde283102f706d5dcdc3649e5e12e3
+0208ee09be465f69005a7a12c28d5eccac7d5f34
diff --git a/triagebot.toml b/triagebot.toml
index c9862495bc..ac4efd0a24 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -25,6 +25,3 @@ labels = ["has-merge-commits", "S-waiting-on-author"]
# Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree
[canonicalize-issue-links]
-
-# Prevents mentions in commits to avoid users being spammed
-[no-mentions]