mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
Rollup merge of #143246 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? ``@ghost``
This commit is contained in:
commit
57b390d8a0
39
.github/workflows/ci.yaml
vendored
39
.github/workflows/ci.yaml
vendored
@ -17,6 +17,10 @@ env:
|
||||
RUST_BACKTRACE: short
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
@ -80,6 +84,7 @@ jobs:
|
||||
CC: deny_c
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
@ -99,7 +104,7 @@ jobs:
|
||||
rustup toolchain install nightly --profile minimal --component rustfmt
|
||||
# https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
|
||||
- name: Install Rust Problem Matcher
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: echo "::add-matcher::.github/rust.json"
|
||||
|
||||
# - name: Cache Dependencies
|
||||
@ -116,23 +121,9 @@ jobs:
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: cargo codegen --check
|
||||
|
||||
- name: Compile tests
|
||||
run: cargo test --no-run
|
||||
|
||||
- name: Run tests
|
||||
run: cargo nextest run --no-fail-fast --hide-progress-bar --status-level fail
|
||||
|
||||
- name: Cancel parallel jobs
|
||||
if: failure()
|
||||
run: |
|
||||
# https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel
|
||||
|
||||
- name: Run Clippy
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
|
||||
@ -333,3 +324,21 @@ jobs:
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful (or have been skipped).
|
||||
jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
|
||||
|
||||
cancel-if-matrix-failed:
|
||||
needs: rust
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel parallel jobs
|
||||
run: |
|
||||
if jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'; then
|
||||
exit 0
|
||||
fi
|
||||
# https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel
|
||||
|
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@ -134,13 +134,13 @@ jobs:
|
||||
|
||||
- name: Run analysis-stats on rust-analyzer
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu'
|
||||
run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats .
|
||||
run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . -q
|
||||
|
||||
- name: Run analysis-stats on rust std library
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu'
|
||||
env:
|
||||
RUSTC_BOOTSTRAP: 1
|
||||
run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
|
||||
run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std -q
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -1458,7 +1458,7 @@ dependencies = [
|
||||
"edition",
|
||||
"expect-test",
|
||||
"ra-ap-rustc_lexer",
|
||||
"rustc-literal-escaper 0.0.3",
|
||||
"rustc-literal-escaper 0.0.4",
|
||||
"stdx",
|
||||
"tracing",
|
||||
]
|
||||
@ -1927,9 +1927,9 @@ checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-literal-escaper"
|
||||
version = "0.0.3"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78744cd17f5d01c75b709e49807d1363e02a940ccee2e9e72435843fdb0d076e"
|
||||
checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-stable-hash"
|
||||
@ -2207,7 +2207,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"rowan",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc-literal-escaper 0.0.3",
|
||||
"rustc-literal-escaper 0.0.4",
|
||||
"rustc_apfloat",
|
||||
"smol_str",
|
||||
"stdx",
|
||||
|
@ -143,7 +143,7 @@ serde = { version = "1.0.219" }
|
||||
serde_derive = { version = "1.0.219" }
|
||||
serde_json = "1.0.140"
|
||||
rustc-hash = "2.1.1"
|
||||
rustc-literal-escaper = "0.0.3"
|
||||
rustc-literal-escaper = "0.0.4"
|
||||
smallvec = { version = "1.15.1", features = [
|
||||
"const_new",
|
||||
"union",
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
la-arena.workspace = true
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc-hash.workspace = true
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
arrayvec.workspace = true
|
||||
|
@ -25,11 +25,10 @@ use crate::{
|
||||
import_map::ImportMap,
|
||||
item_tree::{ItemTree, file_item_tree_query},
|
||||
lang_item::{self, LangItem},
|
||||
nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics},
|
||||
nameres::crate_def_map,
|
||||
signatures::{
|
||||
ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature,
|
||||
StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature,
|
||||
VariantFields,
|
||||
},
|
||||
tt,
|
||||
visibility::{self, Visibility},
|
||||
@ -113,24 +112,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
|
||||
|
||||
// region:data
|
||||
|
||||
#[salsa::invoke(VariantFields::query)]
|
||||
fn variant_fields_with_source_map(
|
||||
&self,
|
||||
id: VariantId,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(TraitItems::trait_items_query)]
|
||||
fn trait_items(&self, e: TraitId) -> Arc<TraitItems>;
|
||||
|
||||
#[salsa::invoke(TraitItems::trait_items_with_diagnostics_query)]
|
||||
fn trait_items_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitItems>, DefDiagnostics);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn variant_fields(&self, id: VariantId) -> Arc<VariantFields> {
|
||||
self.variant_fields_with_source_map(id).0
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> {
|
||||
self.trait_signature_with_source_map(trait_).0
|
||||
|
@ -9,7 +9,10 @@ pub mod scope;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::ops::{Deref, Index};
|
||||
use std::{
|
||||
ops::{Deref, Index},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
@ -19,6 +22,7 @@ use rustc_hash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use span::{Edition, SyntaxContext};
|
||||
use syntax::{AstPtr, SyntaxNodePtr, ast};
|
||||
use triomphe::Arc;
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
@ -220,6 +224,12 @@ impl ExpressionStoreBuilder {
|
||||
}
|
||||
|
||||
impl ExpressionStore {
|
||||
pub fn empty_singleton() -> Arc<Self> {
|
||||
static EMPTY: LazyLock<Arc<ExpressionStore>> =
|
||||
LazyLock::new(|| Arc::new(ExpressionStoreBuilder::default().finish()));
|
||||
EMPTY.clone()
|
||||
}
|
||||
|
||||
/// Returns an iterator over all block expressions in this store that define inner items.
|
||||
pub fn blocks<'a>(
|
||||
&'a self,
|
||||
@ -636,6 +646,12 @@ impl Index<PathId> for ExpressionStore {
|
||||
// FIXME: Change `node_` prefix to something more reasonable.
|
||||
// Perhaps `expr_syntax` and `expr_id`?
|
||||
impl ExpressionStoreSourceMap {
|
||||
pub fn empty_singleton() -> Arc<Self> {
|
||||
static EMPTY: LazyLock<Arc<ExpressionStoreSourceMap>> =
|
||||
LazyLock::new(|| Arc::new(ExpressionStoreSourceMap::default()));
|
||||
EMPTY.clone()
|
||||
}
|
||||
|
||||
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.expr_syntax(id),
|
||||
|
@ -2250,7 +2250,7 @@ impl ExprCollector<'_> {
|
||||
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
||||
Some(ModuleDefId::EnumVariantId(variant))
|
||||
// FIXME: This can cause a cycle if the user is writing invalid code
|
||||
if self.db.variant_fields(variant.into()).shape != FieldsShape::Record =>
|
||||
if variant.fields(self.db).shape != FieldsShape::Record =>
|
||||
{
|
||||
(None, Pat::Path(name.into()))
|
||||
}
|
||||
@ -2825,14 +2825,7 @@ impl ExprCollector<'_> {
|
||||
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,
|
||||
hygiene,
|
||||
argmap,
|
||||
lit_pieces,
|
||||
format_options,
|
||||
)
|
||||
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,
|
||||
@ -2962,7 +2955,6 @@ impl ExprCollector<'_> {
|
||||
&mut self,
|
||||
syntax_ptr: AstPtr<ast::Expr>,
|
||||
fmt: FormatArgs,
|
||||
hygiene: HygieneId,
|
||||
argmap: FxIndexSet<(usize, ArgumentType)>,
|
||||
lit_pieces: ExprId,
|
||||
format_options: ExprId,
|
||||
@ -2997,8 +2989,11 @@ impl ExprCollector<'_> {
|
||||
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, hygiene);
|
||||
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.
|
||||
@ -3008,13 +3003,16 @@ impl ExprCollector<'_> {
|
||||
initializer: Some(args),
|
||||
else_branch: None,
|
||||
};
|
||||
(vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name))))
|
||||
(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, hygiene);
|
||||
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
|
||||
@ -3057,8 +3055,11 @@ impl ExprCollector<'_> {
|
||||
.collect();
|
||||
let array =
|
||||
self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
|
||||
let args_binding =
|
||||
self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
|
||||
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 {
|
||||
|
@ -121,7 +121,7 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E
|
||||
VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
|
||||
};
|
||||
|
||||
let fields = db.variant_fields(owner);
|
||||
let fields = owner.fields(db);
|
||||
|
||||
let mut p = Printer {
|
||||
db,
|
||||
|
@ -331,13 +331,13 @@ impl GenericParams {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn no_predicates(&self) -> bool {
|
||||
pub fn has_no_predicates(&self) -> bool {
|
||||
self.where_predicates.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
|
||||
self.where_predicates.iter()
|
||||
pub fn where_predicates(&self) -> &[WherePredicate] {
|
||||
&self.where_predicates
|
||||
}
|
||||
|
||||
/// Iterator of type_or_consts field
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||
AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
|
||||
db::DefDatabase,
|
||||
item_scope::{ImportOrExternCrate, ItemInNs},
|
||||
nameres::{DefMap, crate_def_map},
|
||||
nameres::{DefMap, assoc::TraitItems, crate_def_map},
|
||||
visibility::Visibility,
|
||||
};
|
||||
|
||||
@ -221,7 +221,7 @@ impl ImportMap {
|
||||
trait_import_info: &ImportInfo,
|
||||
) {
|
||||
let _p = tracing::info_span!("collect_trait_assoc_items").entered();
|
||||
for &(ref assoc_item_name, item) in &db.trait_items(tr).items {
|
||||
for &(ref assoc_item_name, item) in &TraitItems::query(db, tr).items {
|
||||
let module_def_id = match item {
|
||||
AssocItemId::FunctionId(f) => ModuleDefId::from(f),
|
||||
AssocItemId::ConstId(c) => ModuleDefId::from(c),
|
||||
@ -482,7 +482,7 @@ mod tests {
|
||||
use expect_test::{Expect, expect};
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::{ItemContainerId, Lookup, test_db::TestDB};
|
||||
use crate::{ItemContainerId, Lookup, nameres::assoc::TraitItems, test_db::TestDB};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -580,7 +580,7 @@ mod tests {
|
||||
|
||||
let trait_info = dependency_imports.import_info_for(ItemInNs::Types(trait_id.into()))?;
|
||||
|
||||
let trait_items = db.trait_items(trait_id);
|
||||
let trait_items = TraitItems::query(db, trait_id);
|
||||
let (assoc_item_name, _) = trait_items
|
||||
.items
|
||||
.iter()
|
||||
|
@ -9,8 +9,10 @@ use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
|
||||
nameres::crate_def_map,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId,
|
||||
db::DefDatabase,
|
||||
expr_store::path::Path,
|
||||
nameres::{assoc::TraitItems, crate_def_map},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@ -113,14 +115,16 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
|
||||
match def {
|
||||
ModuleDefId::TraitId(trait_) => {
|
||||
lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait);
|
||||
db.trait_items(trait_).items.iter().for_each(|&(_, assoc_id)| match assoc_id {
|
||||
AssocItemId::FunctionId(f) => {
|
||||
lang_items.collect_lang_item(db, f, LangItemTarget::Function);
|
||||
TraitItems::query(db, trait_).items.iter().for_each(|&(_, assoc_id)| {
|
||||
match assoc_id {
|
||||
AssocItemId::FunctionId(f) => {
|
||||
lang_items.collect_lang_item(db, f, LangItemTarget::Function);
|
||||
}
|
||||
AssocItemId::TypeAliasId(alias) => {
|
||||
lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias)
|
||||
}
|
||||
AssocItemId::ConstId(_) => {}
|
||||
}
|
||||
AssocItemId::TypeAliasId(alias) => {
|
||||
lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias)
|
||||
}
|
||||
AssocItemId::ConstId(_) => {}
|
||||
});
|
||||
}
|
||||
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
||||
@ -304,6 +308,8 @@ impl LangItem {
|
||||
language_item_table! {
|
||||
// Variant name, Name, Getter method name, Target Generic requirements;
|
||||
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
MetaSized, sym::meta_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
PointeeSized, sym::pointee_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
|
||||
StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None;
|
||||
|
@ -87,9 +87,12 @@ use crate::{
|
||||
attr::Attrs,
|
||||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
expr_store::ExpressionStoreSourceMap,
|
||||
hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
|
||||
nameres::{
|
||||
LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map,
|
||||
LocalDefMap,
|
||||
assoc::{ImplItems, TraitItems},
|
||||
block_def_map, crate_def_map, crate_local_def_map,
|
||||
diagnostics::DefDiagnostics,
|
||||
},
|
||||
signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields},
|
||||
@ -252,9 +255,35 @@ impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
|
||||
type StructLoc = ItemLoc<ast::Struct>;
|
||||
impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
|
||||
|
||||
impl StructId {
|
||||
pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
|
||||
VariantFields::firewall(db, self.into())
|
||||
}
|
||||
|
||||
pub fn fields_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
|
||||
VariantFields::query(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub type UnionLoc = ItemLoc<ast::Union>;
|
||||
impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
|
||||
|
||||
impl UnionId {
|
||||
pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
|
||||
VariantFields::firewall(db, self.into())
|
||||
}
|
||||
|
||||
pub fn fields_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
|
||||
VariantFields::query(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub type EnumLoc = ItemLoc<ast::Enum>;
|
||||
impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
|
||||
|
||||
@ -282,6 +311,13 @@ impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
|
||||
pub type TraitLoc = ItemLoc<ast::Trait>;
|
||||
impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
|
||||
|
||||
impl TraitId {
|
||||
#[inline]
|
||||
pub fn trait_items(self, db: &dyn DefDatabase) -> &TraitItems {
|
||||
TraitItems::query(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>;
|
||||
impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
|
||||
|
||||
@ -328,6 +364,20 @@ pub struct EnumVariantLoc {
|
||||
}
|
||||
impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant);
|
||||
impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
|
||||
|
||||
impl EnumVariantId {
|
||||
pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
|
||||
VariantFields::firewall(db, self.into())
|
||||
}
|
||||
|
||||
pub fn fields_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
|
||||
VariantFields::query(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Macro2Loc {
|
||||
pub container: ModuleId,
|
||||
@ -1015,8 +1065,15 @@ pub enum VariantId {
|
||||
impl_from!(EnumVariantId, StructId, UnionId for VariantId);
|
||||
|
||||
impl VariantId {
|
||||
pub fn variant_data(self, db: &dyn DefDatabase) -> Arc<VariantFields> {
|
||||
db.variant_fields(self)
|
||||
pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields {
|
||||
VariantFields::firewall(db, self)
|
||||
}
|
||||
|
||||
pub fn fields_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) {
|
||||
VariantFields::query(db, self)
|
||||
}
|
||||
|
||||
pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
|
||||
|
@ -38,16 +38,18 @@ pub struct TraitItems {
|
||||
pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl TraitItems {
|
||||
#[inline]
|
||||
pub(crate) fn trait_items_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitItems> {
|
||||
db.trait_items_with_diagnostics(tr).0
|
||||
pub(crate) fn query(db: &dyn DefDatabase, tr: TraitId) -> &TraitItems {
|
||||
&Self::query_with_diagnostics(db, tr).0
|
||||
}
|
||||
|
||||
pub(crate) fn trait_items_with_diagnostics_query(
|
||||
#[salsa::tracked(returns(ref))]
|
||||
pub fn query_with_diagnostics(
|
||||
db: &dyn DefDatabase,
|
||||
tr: TraitId,
|
||||
) -> (Arc<TraitItems>, DefDiagnostics) {
|
||||
) -> (TraitItems, DefDiagnostics) {
|
||||
let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db);
|
||||
|
||||
let collector =
|
||||
@ -55,7 +57,7 @@ impl TraitItems {
|
||||
let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
|
||||
let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
|
||||
|
||||
(Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics))
|
||||
(TraitItems { macro_calls, items }, DefDiagnostics::new(diagnostics))
|
||||
}
|
||||
|
||||
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
||||
|
@ -41,6 +41,7 @@ use crate::{
|
||||
macro_call_as_call_id,
|
||||
nameres::{
|
||||
BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
|
||||
assoc::TraitItems,
|
||||
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
|
||||
crate_def_map,
|
||||
diagnostics::DefDiagnostic,
|
||||
@ -1020,8 +1021,7 @@ impl<'db> DefCollector<'db> {
|
||||
let resolutions = if true {
|
||||
vec![]
|
||||
} else {
|
||||
self.db
|
||||
.trait_items(it)
|
||||
TraitItems::query(self.db, it)
|
||||
.items
|
||||
.iter()
|
||||
.map(|&(ref name, variant)| {
|
||||
|
@ -24,8 +24,8 @@ use crate::{
|
||||
item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
|
||||
item_tree::FieldsShape,
|
||||
nameres::{
|
||||
BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map,
|
||||
sub_namespace_match,
|
||||
BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, assoc::TraitItems,
|
||||
crate_def_map, sub_namespace_match,
|
||||
},
|
||||
per_ns::PerNs,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
@ -584,8 +584,11 @@ impl DefMap {
|
||||
// now resulting in a cycle.
|
||||
// To properly implement this, trait item collection needs to be done in def map
|
||||
// collection...
|
||||
let item =
|
||||
if true { None } else { db.trait_items(t).assoc_item_by_name(segment) };
|
||||
let item = if true {
|
||||
None
|
||||
} else {
|
||||
TraitItems::query(db, t).assoc_item_by_name(segment)
|
||||
};
|
||||
return match item {
|
||||
Some(item) => ResolvePathResult::new(
|
||||
match item {
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Item signature IR definitions
|
||||
|
||||
use std::ops::Not as _;
|
||||
use std::{cell::LazyCell, ops::Not as _};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
@ -731,29 +731,26 @@ pub struct VariantFields {
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub shape: FieldsShape,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl VariantFields {
|
||||
#[inline]
|
||||
#[salsa::tracked(returns(clone))]
|
||||
pub(crate) fn query(
|
||||
db: &dyn DefDatabase,
|
||||
id: VariantId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let (shape, (fields, store, source_map)) = match id {
|
||||
let (shape, result) = match id {
|
||||
VariantId::EnumVariantId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let parent = loc.parent.lookup(db);
|
||||
let source = loc.source(db);
|
||||
let shape = adt_shape(source.value.kind());
|
||||
let span_map = db.span_map(source.file_id);
|
||||
let override_visibility = visibility_from_ast(
|
||||
db,
|
||||
source.value.parent_enum().visibility(),
|
||||
&mut |range| span_map.span_for_range(range).ctx,
|
||||
);
|
||||
let enum_vis = Some(source.value.parent_enum().visibility());
|
||||
let fields = lower_field_list(
|
||||
db,
|
||||
parent.container,
|
||||
source.map(|src| src.field_list()),
|
||||
Some(override_visibility),
|
||||
enum_vis,
|
||||
);
|
||||
(shape, fields)
|
||||
}
|
||||
@ -777,10 +774,29 @@ impl VariantFields {
|
||||
(FieldsShape::Record, fields)
|
||||
}
|
||||
};
|
||||
|
||||
(Arc::new(VariantFields { fields, store: Arc::new(store), shape }), Arc::new(source_map))
|
||||
match result {
|
||||
Some((fields, store, source_map)) => (
|
||||
Arc::new(VariantFields { fields, store: Arc::new(store), shape }),
|
||||
Arc::new(source_map),
|
||||
),
|
||||
None => (
|
||||
Arc::new(VariantFields {
|
||||
fields: Arena::default(),
|
||||
store: ExpressionStore::empty_singleton(),
|
||||
shape,
|
||||
}),
|
||||
ExpressionStoreSourceMap::empty_singleton(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked(returns(deref))]
|
||||
pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc<Self> {
|
||||
Self::query(db, id).0
|
||||
}
|
||||
}
|
||||
|
||||
impl VariantFields {
|
||||
pub fn len(&self) -> usize {
|
||||
self.fields.len()
|
||||
}
|
||||
@ -798,31 +814,24 @@ fn lower_field_list(
|
||||
db: &dyn DefDatabase,
|
||||
module: ModuleId,
|
||||
fields: InFile<Option<ast::FieldList>>,
|
||||
override_visibility: Option<RawVisibility>,
|
||||
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
|
||||
override_visibility: Option<Option<ast::Visibility>>,
|
||||
) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
|
||||
let file_id = fields.file_id;
|
||||
match fields.value {
|
||||
Some(ast::FieldList::RecordFieldList(fields)) => lower_fields(
|
||||
match fields.value? {
|
||||
ast::FieldList::RecordFieldList(fields) => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
|
||||
|_, field| as_name_opt(field.name()),
|
||||
override_visibility,
|
||||
),
|
||||
Some(ast::FieldList::TupleFieldList(fields)) => lower_fields(
|
||||
ast::FieldList::TupleFieldList(fields) => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
|
||||
|idx, _| Name::new_tuple_field(idx),
|
||||
override_visibility,
|
||||
),
|
||||
None => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()),
|
||||
|_, _| Name::missing(),
|
||||
None,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,22 +840,34 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
|
||||
module: ModuleId,
|
||||
fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>,
|
||||
mut field_name: impl FnMut(usize, &Field) -> Name,
|
||||
override_visibility: Option<RawVisibility>,
|
||||
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
|
||||
let mut arena = Arena::new();
|
||||
override_visibility: Option<Option<ast::Visibility>>,
|
||||
) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
|
||||
let cfg_options = module.krate.cfg_options(db);
|
||||
let mut col = ExprCollector::new(db, module, fields.file_id);
|
||||
let override_visibility = override_visibility.map(|vis| {
|
||||
LazyCell::new(|| {
|
||||
let span_map = db.span_map(fields.file_id);
|
||||
visibility_from_ast(db, vis, &mut |range| span_map.span_for_range(range).ctx)
|
||||
})
|
||||
});
|
||||
|
||||
let mut arena = Arena::new();
|
||||
let mut idx = 0;
|
||||
let mut has_fields = false;
|
||||
for (ty, field) in fields.value {
|
||||
has_fields = true;
|
||||
match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) {
|
||||
Ok(()) => {
|
||||
let type_ref =
|
||||
col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator);
|
||||
let visibility = override_visibility.clone().unwrap_or_else(|| {
|
||||
visibility_from_ast(db, field.visibility(), &mut |range| {
|
||||
col.span_map().span_for_range(range).ctx
|
||||
})
|
||||
});
|
||||
let visibility = override_visibility.as_ref().map_or_else(
|
||||
|| {
|
||||
visibility_from_ast(db, field.visibility(), &mut |range| {
|
||||
col.span_map().span_for_range(range).ctx
|
||||
})
|
||||
},
|
||||
|it| RawVisibility::clone(it),
|
||||
);
|
||||
let is_unsafe = field
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
@ -867,9 +888,12 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
|
||||
}
|
||||
}
|
||||
}
|
||||
if !has_fields {
|
||||
return None;
|
||||
}
|
||||
let store = col.store.finish();
|
||||
arena.shrink_to_fit();
|
||||
(arena, store, col.source_map)
|
||||
Some((arena, store, col.source_map))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -948,7 +972,7 @@ impl EnumVariants {
|
||||
self.variants.iter().all(|&(v, _, _)| {
|
||||
// The condition check order is slightly modified from rustc
|
||||
// to improve performance by early returning with relatively fast checks
|
||||
let variant = &db.variant_fields(v.into());
|
||||
let variant = v.fields(db);
|
||||
if !variant.fields().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ pub(crate) fn field_visibilities_query(
|
||||
db: &dyn DefDatabase,
|
||||
variant_id: VariantId,
|
||||
) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
|
||||
let variant_fields = db.variant_fields(variant_id);
|
||||
let variant_fields = variant_id.fields(db);
|
||||
let fields = variant_fields.fields();
|
||||
if fields.is_empty() {
|
||||
return Arc::default();
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -433,20 +433,19 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
|
||||
let mut buf = String::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape::unescape_unicode(s, unescape::Mode::Str, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
(Ok(c), false) => buf.push(c),
|
||||
(Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
|
||||
prev_end = char_range.end
|
||||
unescape::unescape_str(s, |char_range, unescaped_char| {
|
||||
match (unescaped_char, buf.capacity() == 0) {
|
||||
(Ok(c), false) => buf.push(c),
|
||||
(Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
|
||||
prev_end = char_range.end
|
||||
}
|
||||
(Ok(c), true) => {
|
||||
buf.reserve_exact(s.len());
|
||||
buf.push_str(&s[..prev_end]);
|
||||
buf.push(c);
|
||||
}
|
||||
(Err(_), _) => has_error = true,
|
||||
}
|
||||
(Ok(c), true) => {
|
||||
buf.reserve_exact(s.len());
|
||||
buf.push_str(&s[..prev_end]);
|
||||
buf.push(c);
|
||||
}
|
||||
(Err(_), _) => has_error = true,
|
||||
});
|
||||
|
||||
match (has_error, buf.capacity() == 0) {
|
||||
|
@ -12,7 +12,7 @@ use span::{Edition, FileId, Span};
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
format_smolstr,
|
||||
unescape::{Mode, unescape_byte, unescape_char, unescape_unicode},
|
||||
unescape::{unescape_byte, unescape_char, unescape_str},
|
||||
};
|
||||
use syntax_bridge::syntax_node_to_token_tree;
|
||||
|
||||
@ -430,7 +430,7 @@ fn compile_error_expand(
|
||||
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
||||
suffix: _,
|
||||
})),
|
||||
] => ExpandError::other(span, Box::from(unescape_str(text).as_str())),
|
||||
] => ExpandError::other(span, Box::from(unescape_symbol(text).as_str())),
|
||||
_ => ExpandError::other(span, "`compile_error!` argument must be a string"),
|
||||
};
|
||||
|
||||
@ -481,7 +481,7 @@ fn concat_expand(
|
||||
format_to!(text, "{}", it.symbol.as_str())
|
||||
}
|
||||
tt::LitKind::Str => {
|
||||
text.push_str(unescape_str(&it.symbol).as_str());
|
||||
text.push_str(unescape_symbol(&it.symbol).as_str());
|
||||
record_span(it.span);
|
||||
}
|
||||
tt::LitKind::StrRaw(_) => {
|
||||
@ -691,7 +691,7 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
|
||||
span,
|
||||
kind: tt::LitKind::Str,
|
||||
suffix: _,
|
||||
})) => Ok((unescape_str(text), *span)),
|
||||
})) => Ok((unescape_symbol(text), *span)),
|
||||
TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
symbol: text,
|
||||
span,
|
||||
@ -712,7 +712,7 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
|
||||
span,
|
||||
kind: tt::LitKind::Str,
|
||||
suffix: _,
|
||||
})) => Some((unescape_str(text), *span)),
|
||||
})) => Some((unescape_symbol(text), *span)),
|
||||
TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
symbol: text,
|
||||
span,
|
||||
@ -897,11 +897,11 @@ fn quote_expand(
|
||||
)
|
||||
}
|
||||
|
||||
fn unescape_str(s: &Symbol) -> Symbol {
|
||||
fn unescape_symbol(s: &Symbol) -> Symbol {
|
||||
if s.as_str().contains('\\') {
|
||||
let s = s.as_str();
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
unescape_unicode(s, Mode::Str, &mut |_, c| {
|
||||
unescape_str(s, |_, c| {
|
||||
if let Ok(c) = c {
|
||||
buf.push(c)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -208,7 +208,7 @@ pub(crate) fn deref_by_trait(
|
||||
};
|
||||
let trait_id = trait_id()?;
|
||||
let target =
|
||||
db.trait_items(trait_id).associated_type_by_name(&Name::new_symbol_root(sym::Target))?;
|
||||
trait_id.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Target))?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::subst_for_def(db, trait_id, None);
|
||||
|
@ -315,9 +315,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||
if let Some((future_trait, future_output)) =
|
||||
LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| {
|
||||
let alias = self
|
||||
.db
|
||||
.trait_items(trait_)
|
||||
let alias = trait_
|
||||
.trait_items(self.db)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
|
||||
Some((trait_, alias))
|
||||
})
|
||||
@ -711,7 +710,7 @@ pub(crate) fn trait_datum_query(
|
||||
};
|
||||
let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
|
||||
let associated_ty_ids =
|
||||
db.trait_items(trait_).associated_types().map(to_assoc_type_id).collect();
|
||||
trait_.trait_items(db).associated_types().map(to_assoc_type_id).collect();
|
||||
let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
|
||||
let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item);
|
||||
let trait_datum = TraitDatum {
|
||||
@ -802,7 +801,7 @@ pub(crate) fn adt_datum_query(
|
||||
|
||||
// this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
|
||||
let _variant_id_to_fields = |id: VariantId| {
|
||||
let variant_data = &id.variant_data(db);
|
||||
let variant_data = &id.fields(db);
|
||||
let fields = if variant_data.fields().is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
@ -879,7 +878,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
|
||||
let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
|
||||
|
||||
let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
|
||||
let trait_data = db.trait_items(trait_);
|
||||
let trait_data = trait_.trait_items(db);
|
||||
let associated_ty_value_ids = impl_id
|
||||
.impl_items(db)
|
||||
.items
|
||||
@ -931,8 +930,9 @@ fn type_alias_associated_ty_value(
|
||||
.into_value_and_skipped_binders()
|
||||
.0; // we don't return any assoc ty values if the impl'd trait can't be resolved
|
||||
|
||||
let assoc_ty = db
|
||||
.trait_items(trait_ref.hir_trait_id())
|
||||
let assoc_ty = trait_ref
|
||||
.hir_trait_id()
|
||||
.trait_items(db)
|
||||
.associated_type_by_name(&type_alias_data.name)
|
||||
.expect("assoc ty value should not exist"); // validated when building the impl data as well
|
||||
let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
|
||||
|
@ -307,7 +307,7 @@ impl<'a> DeclValidator<'a> {
|
||||
|
||||
/// Check incorrect names for struct fields.
|
||||
fn validate_struct_fields(&mut self, struct_id: StructId) {
|
||||
let data = self.db.variant_fields(struct_id.into());
|
||||
let data = struct_id.fields(self.db);
|
||||
if data.shape != FieldsShape::Record {
|
||||
return;
|
||||
};
|
||||
@ -468,7 +468,7 @@ impl<'a> DeclValidator<'a> {
|
||||
|
||||
/// Check incorrect names for fields of enum variant.
|
||||
fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
|
||||
let variant_data = self.db.variant_fields(variant_id.into());
|
||||
let variant_data = variant_id.fields(self.db);
|
||||
if variant_data.shape != FieldsShape::Record {
|
||||
return;
|
||||
};
|
||||
|
@ -494,7 +494,7 @@ impl FilterMapNextChecker {
|
||||
Some(next_function_id),
|
||||
match next_function_id.lookup(db).container {
|
||||
ItemContainerId::TraitId(iterator_trait_id) => {
|
||||
let iterator_trait_items = &db.trait_items(iterator_trait_id).items;
|
||||
let iterator_trait_items = &iterator_trait_id.trait_items(db).items;
|
||||
iterator_trait_items.iter().find_map(|(name, it)| match it {
|
||||
&AssocItemId::FunctionId(id) if *name == sym::filter_map => Some(id),
|
||||
_ => None,
|
||||
@ -558,7 +558,7 @@ pub fn record_literal_missing_fields(
|
||||
return None;
|
||||
}
|
||||
|
||||
let variant_data = variant_def.variant_data(db);
|
||||
let variant_data = variant_def.fields(db);
|
||||
|
||||
let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
|
||||
let missed_fields: Vec<LocalFieldId> = variant_data
|
||||
@ -588,7 +588,7 @@ pub fn record_pattern_missing_fields(
|
||||
return None;
|
||||
}
|
||||
|
||||
let variant_data = variant_def.variant_data(db);
|
||||
let variant_data = variant_def.fields(db);
|
||||
|
||||
let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
|
||||
let missed_fields: Vec<LocalFieldId> = variant_data
|
||||
|
@ -169,13 +169,13 @@ impl<'a> PatCtxt<'a> {
|
||||
}
|
||||
|
||||
hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
|
||||
let expected_len = variant.unwrap().variant_data(self.db).fields().len();
|
||||
let expected_len = variant.unwrap().fields(self.db).fields().len();
|
||||
let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
|
||||
self.lower_variant_or_leaf(pat, ty, subpatterns)
|
||||
}
|
||||
|
||||
hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
|
||||
let variant_data = variant.unwrap().variant_data(self.db);
|
||||
let variant_data = variant.unwrap().fields(self.db);
|
||||
let subpatterns = args
|
||||
.iter()
|
||||
.map(|field| {
|
||||
@ -345,7 +345,7 @@ impl HirDisplay for Pat {
|
||||
)?,
|
||||
};
|
||||
|
||||
let variant_data = variant.variant_data(f.db);
|
||||
let variant_data = variant.fields(f.db);
|
||||
if variant_data.shape == FieldsShape::Record {
|
||||
write!(f, " {{ ")?;
|
||||
|
||||
@ -377,7 +377,7 @@ impl HirDisplay for Pat {
|
||||
}
|
||||
|
||||
let num_fields =
|
||||
variant.map_or(subpatterns.len(), |v| v.variant_data(f.db).fields().len());
|
||||
variant.map_or(subpatterns.len(), |v| v.fields(f.db).fields().len());
|
||||
if num_fields != 0 || variant.is_none() {
|
||||
write!(f, "(")?;
|
||||
let subpats = (0..num_fields).map(|i| {
|
||||
|
@ -6,7 +6,7 @@ use std::fmt;
|
||||
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
|
||||
use intern::sym;
|
||||
use rustc_pattern_analysis::{
|
||||
Captures, IndexVec, PatCx, PrivateUninhabitedField,
|
||||
IndexVec, PatCx, PrivateUninhabitedField,
|
||||
constructor::{Constructor, ConstructorSet, VariantVisibility},
|
||||
usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness},
|
||||
};
|
||||
@ -138,15 +138,15 @@ impl<'db> MatchCheckCtx<'db> {
|
||||
}
|
||||
|
||||
// This lists the fields of a variant along with their types.
|
||||
fn list_variant_fields<'a>(
|
||||
&'a self,
|
||||
ty: &'a Ty,
|
||||
fn list_variant_fields(
|
||||
&self,
|
||||
ty: &Ty,
|
||||
variant: VariantId,
|
||||
) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> {
|
||||
) -> impl Iterator<Item = (LocalFieldId, Ty)> {
|
||||
let (_, substs) = ty.as_adt().unwrap();
|
||||
|
||||
let field_tys = self.db.field_types(variant);
|
||||
let fields_len = variant.variant_data(self.db).fields().len() as u32;
|
||||
let fields_len = variant.fields(self.db).fields().len() as u32;
|
||||
|
||||
(0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| {
|
||||
let ty = field_tys[fid].clone().substitute(Interner, substs);
|
||||
@ -229,7 +229,7 @@ impl<'db> MatchCheckCtx<'db> {
|
||||
}
|
||||
};
|
||||
let variant = Self::variant_id_for_adt(self.db, &ctor, adt).unwrap();
|
||||
arity = variant.variant_data(self.db).fields().len();
|
||||
arity = variant.fields(self.db).fields().len();
|
||||
}
|
||||
_ => {
|
||||
never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
|
||||
@ -349,7 +349,7 @@ impl PatCx for MatchCheckCtx<'_> {
|
||||
1
|
||||
} else {
|
||||
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
|
||||
variant.variant_data(self.db).fields().len()
|
||||
variant.fields(self.db).fields().len()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -888,7 +888,7 @@ fn render_const_scalar(
|
||||
write!(f, "{}", data.name.display(f.db, f.edition()))?;
|
||||
let field_types = f.db.field_types(s.into());
|
||||
render_variant_after_name(
|
||||
&f.db.variant_fields(s.into()),
|
||||
s.fields(f.db),
|
||||
f,
|
||||
&field_types,
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
@ -920,7 +920,7 @@ fn render_const_scalar(
|
||||
)?;
|
||||
let field_types = f.db.field_types(var_id.into());
|
||||
render_variant_after_name(
|
||||
&f.db.variant_fields(var_id.into()),
|
||||
var_id.fields(f.db),
|
||||
f,
|
||||
&field_types,
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
@ -1394,7 +1394,7 @@ impl HirDisplay for Ty {
|
||||
let future_trait =
|
||||
LangItem::Future.resolve_trait(db, body.module(db).krate());
|
||||
let output = future_trait.and_then(|t| {
|
||||
db.trait_items(t)
|
||||
t.trait_items(db)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::Output))
|
||||
});
|
||||
write!(f, "impl ")?;
|
||||
@ -2178,6 +2178,7 @@ impl HirDisplayWithExpressionStore for TypeRefId {
|
||||
f.write_joined(
|
||||
generic_params
|
||||
.where_predicates()
|
||||
.iter()
|
||||
.filter_map(|it| match it {
|
||||
WherePredicate::TypeBound { target, bound }
|
||||
| WherePredicate::ForLifetime { lifetimes: _, target, bound }
|
||||
|
@ -101,7 +101,7 @@ where
|
||||
|
||||
// rustc checks for non-lifetime binders here, but we don't support HRTB yet
|
||||
|
||||
let trait_data = db.trait_items(trait_);
|
||||
let trait_data = trait_.trait_items(db);
|
||||
for (_, assoc_item) in &trait_data.items {
|
||||
dyn_compatibility_violation_for_assoc_item(db, trait_, *assoc_item, cb)?;
|
||||
}
|
||||
@ -164,7 +164,7 @@ fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
|
||||
|
||||
// Same as the above, `predicates_reference_self`
|
||||
fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
|
||||
let trait_data = db.trait_items(trait_);
|
||||
let trait_data = trait_.trait_items(db);
|
||||
trait_data
|
||||
.items
|
||||
.iter()
|
||||
|
@ -60,7 +60,16 @@ impl Generics {
|
||||
}
|
||||
|
||||
pub(crate) fn where_predicates(&self) -> impl Iterator<Item = &WherePredicate> {
|
||||
self.params.where_predicates()
|
||||
self.params.where_predicates().iter()
|
||||
}
|
||||
|
||||
pub(crate) fn has_no_predicates(&self) -> bool {
|
||||
self.params.has_no_predicates()
|
||||
&& self.parent_generics.as_ref().is_none_or(|g| g.params.has_no_predicates())
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.params.is_empty() && self.parent_generics.as_ref().is_none_or(|g| g.params.is_empty())
|
||||
}
|
||||
|
||||
pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
|
||||
|
@ -1813,7 +1813,7 @@ impl<'db> InferenceContext<'db> {
|
||||
}
|
||||
|
||||
fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
|
||||
self.db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output))
|
||||
trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output))
|
||||
}
|
||||
|
||||
fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {
|
||||
|
@ -382,7 +382,7 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
|
||||
return Err(());
|
||||
};
|
||||
|
||||
let struct_data = table.db.variant_fields(id.into());
|
||||
let struct_data = id.fields(table.db);
|
||||
if let Some((last_field, _)) = struct_data.fields().iter().last() {
|
||||
let last_field_ty =
|
||||
table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
|
||||
|
@ -677,7 +677,7 @@ impl CapturedItem {
|
||||
match proj {
|
||||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(Either::Left(f)) => {
|
||||
let variant_data = f.parent.variant_data(db);
|
||||
let variant_data = f.parent.fields(db);
|
||||
match variant_data.shape {
|
||||
FieldsShape::Record => {
|
||||
result.push('_');
|
||||
@ -720,7 +720,7 @@ impl CapturedItem {
|
||||
// In source code autoderef kicks in.
|
||||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(Either::Left(f)) => {
|
||||
let variant_data = f.parent.variant_data(db);
|
||||
let variant_data = f.parent.fields(db);
|
||||
match variant_data.shape {
|
||||
FieldsShape::Record => format_to!(
|
||||
result,
|
||||
@ -782,7 +782,7 @@ impl CapturedItem {
|
||||
if field_need_paren {
|
||||
result = format!("({result})");
|
||||
}
|
||||
let variant_data = f.parent.variant_data(db);
|
||||
let variant_data = f.parent.fields(db);
|
||||
let field = match variant_data.shape {
|
||||
FieldsShape::Record => {
|
||||
variant_data.fields()[f.local_id].name.as_str().to_owned()
|
||||
@ -1210,9 +1210,8 @@ impl InferenceContext<'_> {
|
||||
if let Some(deref_trait) =
|
||||
self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait())
|
||||
{
|
||||
if let Some(deref_fn) = self
|
||||
.db
|
||||
.trait_items(deref_trait)
|
||||
if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
@ -1560,7 +1559,7 @@ impl InferenceContext<'_> {
|
||||
self.consume_place(place)
|
||||
}
|
||||
VariantId::StructId(s) => {
|
||||
let vd = &*self.db.variant_fields(s.into());
|
||||
let vd = s.fields(self.db);
|
||||
for field_pat in args.iter() {
|
||||
let arg = field_pat.pat;
|
||||
let Some(local_id) = vd.field(&field_pat.name) else {
|
||||
@ -1612,7 +1611,7 @@ impl InferenceContext<'_> {
|
||||
self.consume_place(place)
|
||||
}
|
||||
VariantId::StructId(s) => {
|
||||
let vd = &*self.db.variant_fields(s.into());
|
||||
let vd = s.fields(self.db);
|
||||
let (al, ar) =
|
||||
args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let fields = vd.fields().iter();
|
||||
|
@ -542,7 +542,7 @@ impl InferenceContext<'_> {
|
||||
_ if fields.is_empty() => {}
|
||||
Some(def) => {
|
||||
let field_types = self.db.field_types(def);
|
||||
let variant_data = def.variant_data(self.db);
|
||||
let variant_data = def.fields(self.db);
|
||||
let visibilities = self.db.field_visibilities(def);
|
||||
for field in fields.iter() {
|
||||
let field_def = {
|
||||
@ -654,9 +654,8 @@ impl InferenceContext<'_> {
|
||||
match op {
|
||||
UnaryOp::Deref => {
|
||||
if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
|
||||
if let Some(deref_fn) = self
|
||||
.db
|
||||
.trait_items(deref_trait)
|
||||
if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref))
|
||||
{
|
||||
// FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
|
||||
@ -813,9 +812,8 @@ impl InferenceContext<'_> {
|
||||
self.table.new_lifetime_var(),
|
||||
));
|
||||
self.write_expr_adj(*base, adj.into_boxed_slice());
|
||||
if let Some(func) = self
|
||||
.db
|
||||
.trait_items(index_trait)
|
||||
if let Some(func) = index_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::index))
|
||||
{
|
||||
let subst = TyBuilder::subst_for_def(self.db, index_trait, None);
|
||||
@ -1148,7 +1146,7 @@ impl InferenceContext<'_> {
|
||||
let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else {
|
||||
return;
|
||||
};
|
||||
let trait_data = self.db.trait_items(trait_);
|
||||
let trait_data = trait_.trait_items(self.db);
|
||||
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
|
||||
let subst = TyBuilder::subst_for_def(self.db, trait_, None)
|
||||
.push(callee_ty.clone())
|
||||
@ -1316,7 +1314,7 @@ impl InferenceContext<'_> {
|
||||
|
||||
let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
|
||||
let func = self.db.trait_items(trait_id).method_by_name(&name)?;
|
||||
let func = trait_id.trait_items(self.db).method_by_name(&name)?;
|
||||
Some((trait_id, func))
|
||||
});
|
||||
let (trait_, func) = match trait_func {
|
||||
@ -1568,12 +1566,12 @@ impl InferenceContext<'_> {
|
||||
});
|
||||
}
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref parameters) => {
|
||||
let local_id = self.db.variant_fields(s.into()).field(name)?;
|
||||
let local_id = s.fields(self.db).field(name)?;
|
||||
let field = FieldId { parent: s.into(), local_id };
|
||||
(field, parameters.clone())
|
||||
}
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), ref parameters) => {
|
||||
let local_id = self.db.variant_fields(u.into()).field(name)?;
|
||||
let local_id = u.fields(self.db).field(name)?;
|
||||
let field = FieldId { parent: u.into(), local_id };
|
||||
(field, parameters.clone())
|
||||
}
|
||||
|
@ -129,9 +129,8 @@ impl InferenceContext<'_> {
|
||||
if let Some(index_trait) =
|
||||
LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate)
|
||||
{
|
||||
if let Some(index_fn) = self
|
||||
.db
|
||||
.trait_items(index_trait)
|
||||
if let Some(index_fn) = index_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::index_mut))
|
||||
{
|
||||
*f = index_fn;
|
||||
@ -194,9 +193,8 @@ impl InferenceContext<'_> {
|
||||
});
|
||||
if is_mut_ptr {
|
||||
mutability = Mutability::Not;
|
||||
} else if let Some(deref_fn) = self
|
||||
.db
|
||||
.trait_items(deref_trait)
|
||||
} else if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
*f = deref_fn;
|
||||
|
@ -38,7 +38,7 @@ impl InferenceContext<'_> {
|
||||
decl: Option<DeclContext>,
|
||||
) -> Ty {
|
||||
let (ty, def) = self.resolve_variant(id.into(), path, true);
|
||||
let var_data = def.map(|it| it.variant_data(self.db));
|
||||
let var_data = def.map(|it| it.fields(self.db));
|
||||
if let Some(variant) = def {
|
||||
self.write_variant_resolution(id.into(), variant);
|
||||
}
|
||||
@ -60,7 +60,7 @@ impl InferenceContext<'_> {
|
||||
_ if subs.is_empty() => {}
|
||||
Some(def) => {
|
||||
let field_types = self.db.field_types(def);
|
||||
let variant_data = def.variant_data(self.db);
|
||||
let variant_data = def.fields(self.db);
|
||||
let visibilities = self.db.field_visibilities(def);
|
||||
|
||||
let (pre, post) = match ellipsis {
|
||||
@ -129,7 +129,7 @@ impl InferenceContext<'_> {
|
||||
_ if subs.len() == 0 => {}
|
||||
Some(def) => {
|
||||
let field_types = self.db.field_types(def);
|
||||
let variant_data = def.variant_data(self.db);
|
||||
let variant_data = def.fields(self.db);
|
||||
let visibilities = self.db.field_visibilities(def);
|
||||
|
||||
let substs = ty.as_adt().map(TupleExt::tail);
|
||||
|
@ -278,7 +278,7 @@ impl InferenceContext<'_> {
|
||||
) -> Option<(ValueNs, Substitution)> {
|
||||
let trait_ = trait_ref.hir_trait_id();
|
||||
let item =
|
||||
self.db.trait_items(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| {
|
||||
trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| {
|
||||
match item {
|
||||
AssocItemId::FunctionId(func) => {
|
||||
if segment.name == &self.db.function_signature(func).name {
|
||||
|
@ -859,7 +859,7 @@ impl<'a> InferenceTable<'a> {
|
||||
] {
|
||||
let krate = self.trait_env.krate;
|
||||
let fn_trait = fn_trait_name.get_id(self.db, krate)?;
|
||||
let trait_data = self.db.trait_items(fn_trait);
|
||||
let trait_data = fn_trait.trait_items(self.db);
|
||||
let output_assoc_type =
|
||||
trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
|
||||
|
||||
@ -1001,7 +1001,7 @@ impl<'a> InferenceTable<'a> {
|
||||
// Must use a loop here and not recursion because otherwise users will conduct completely
|
||||
// artificial examples of structs that have themselves as the tail field and complain r-a crashes.
|
||||
while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
|
||||
let struct_data = self.db.variant_fields(id.into());
|
||||
let struct_data = id.fields(self.db);
|
||||
if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
|
||||
let last_field_ty = self.db.field_types(id.into())[last_field]
|
||||
.clone()
|
||||
|
@ -132,7 +132,7 @@ impl UninhabitedFrom<'_> {
|
||||
variant: VariantId,
|
||||
subst: &Substitution,
|
||||
) -> ControlFlow<VisiblyUninhabited> {
|
||||
let variant_data = self.db.variant_fields(variant);
|
||||
let variant_data = variant.fields(self.db);
|
||||
let fields = variant_data.fields();
|
||||
if fields.is_empty() {
|
||||
return CONTINUE_OPAQUELY_INHABITED;
|
||||
|
@ -375,7 +375,7 @@ pub(crate) fn layout_of_ty_cycle_result(
|
||||
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
||||
match pointee.kind(Interner) {
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), ref subst) => {
|
||||
let data = db.variant_fields(i.into());
|
||||
let data = i.fields(db);
|
||||
let mut it = data.fields().iter().rev();
|
||||
match it.next() {
|
||||
Some((f, _)) => {
|
||||
|
@ -42,7 +42,7 @@ pub fn layout_of_adt_query(
|
||||
AdtId::StructId(s) => {
|
||||
let sig = db.struct_signature(s);
|
||||
let mut r = SmallVec::<[_; 1]>::new();
|
||||
r.push(handle_variant(s.into(), &db.variant_fields(s.into()))?);
|
||||
r.push(handle_variant(s.into(), s.fields(db))?);
|
||||
(
|
||||
r,
|
||||
sig.repr.unwrap_or_default(),
|
||||
@ -52,7 +52,7 @@ pub fn layout_of_adt_query(
|
||||
AdtId::UnionId(id) => {
|
||||
let data = db.union_signature(id);
|
||||
let mut r = SmallVec::new();
|
||||
r.push(handle_variant(id.into(), &db.variant_fields(id.into()))?);
|
||||
r.push(handle_variant(id.into(), id.fields(db))?);
|
||||
(r, data.repr.unwrap_or_default(), false)
|
||||
}
|
||||
AdtId::EnumId(e) => {
|
||||
@ -60,7 +60,7 @@ pub fn layout_of_adt_query(
|
||||
let r = variants
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
|
||||
.map(|&(v, _, _)| handle_variant(v.into(), v.fields(db)))
|
||||
.collect::<Result<SmallVec<_>, _>>()?;
|
||||
(r, db.enum_signature(e).repr.unwrap_or_default(), false)
|
||||
}
|
||||
|
@ -891,8 +891,8 @@ pub fn callable_sig_from_fn_trait(
|
||||
) -> Option<(FnTrait, CallableSig)> {
|
||||
let krate = trait_env.krate;
|
||||
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
|
||||
let output_assoc_type = db
|
||||
.trait_items(fn_once_trait)
|
||||
let output_assoc_type = fn_once_trait
|
||||
.trait_items(db)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
|
||||
|
||||
let mut table = InferenceTable::new(db, trait_env.clone());
|
||||
|
@ -581,11 +581,28 @@ impl<'a> TyLoweringContext<'a> {
|
||||
match bound {
|
||||
&TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => {
|
||||
// FIXME Don't silently drop the hrtb lifetimes here
|
||||
if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) {
|
||||
if !ignore_bindings {
|
||||
assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
|
||||
if let Some((trait_ref, mut ctx)) =
|
||||
self.lower_trait_ref_from_path(path, self_ty.clone())
|
||||
{
|
||||
// FIXME(sized-hierarchy): Remove this bound modifications once we have implemented
|
||||
// sized-hierarchy correctly.
|
||||
let meta_sized = LangItem::MetaSized
|
||||
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
|
||||
let pointee_sized = LangItem::PointeeSized
|
||||
.resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate());
|
||||
if meta_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
|
||||
// Ignore this bound
|
||||
} else if pointee_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) {
|
||||
// Regard this as `?Sized` bound
|
||||
ctx.ty_ctx().unsized_types.insert(self_ty);
|
||||
} else {
|
||||
if !ignore_bindings {
|
||||
assoc_bounds =
|
||||
ctx.assoc_type_bindings_from_type_bound(trait_ref.clone());
|
||||
}
|
||||
clause =
|
||||
Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
|
||||
}
|
||||
clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref)));
|
||||
}
|
||||
}
|
||||
&TypeBound::Path(path, TraitBoundModifier::Maybe) => {
|
||||
@ -711,7 +728,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||
.unwrap_or(it),
|
||||
None => it,
|
||||
},
|
||||
None => static_lifetime(),
|
||||
None => error_lifetime(),
|
||||
},
|
||||
})
|
||||
.intern(Interner)
|
||||
@ -805,7 +822,7 @@ fn named_associated_type_shorthand_candidates<R>(
|
||||
) -> Option<R> {
|
||||
let mut search = |t| {
|
||||
all_super_trait_refs(db, t, |t| {
|
||||
let data = db.trait_items(t.hir_trait_id());
|
||||
let data = t.hir_trait_id().trait_items(db);
|
||||
|
||||
for (name, assoc_id) in &data.items {
|
||||
if let AssocItemId::TypeAliasId(alias) = assoc_id {
|
||||
@ -883,7 +900,12 @@ pub(crate) fn field_types_with_diagnostics_query(
|
||||
db: &dyn HirDatabase,
|
||||
variant_id: VariantId,
|
||||
) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) {
|
||||
let var_data = db.variant_fields(variant_id);
|
||||
let var_data = variant_id.fields(db);
|
||||
let fields = var_data.fields();
|
||||
if fields.is_empty() {
|
||||
return (Arc::new(ArenaMap::default()), None);
|
||||
}
|
||||
|
||||
let (resolver, def): (_, GenericDefId) = match variant_id {
|
||||
VariantId::StructId(it) => (it.resolver(db), it.into()),
|
||||
VariantId::UnionId(it) => (it.resolver(db), it.into()),
|
||||
@ -899,7 +921,7 @@ pub(crate) fn field_types_with_diagnostics_query(
|
||||
LifetimeElisionKind::AnonymousReportError,
|
||||
)
|
||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||
for (field_id, field_data) in var_data.fields().iter() {
|
||||
for (field_id, field_data) in fields.iter() {
|
||||
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
|
||||
}
|
||||
(Arc::new(res), create_diagnostics(ctx.diagnostics))
|
||||
@ -920,6 +942,10 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||
assoc_name: Option<Name>,
|
||||
) -> GenericPredicates {
|
||||
let generics = generics(db, def);
|
||||
if generics.has_no_predicates() && generics.is_empty() {
|
||||
return GenericPredicates(None);
|
||||
}
|
||||
|
||||
let resolver = def.resolver(db);
|
||||
let mut ctx = TyLoweringContext::new(
|
||||
db,
|
||||
@ -936,8 +962,32 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||
| WherePredicate::TypeBound { target, bound, .. } => {
|
||||
let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) };
|
||||
if invalid_target {
|
||||
// If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
|
||||
if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
|
||||
// FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented
|
||||
// sized-hierarchy correctly.
|
||||
// If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into
|
||||
// `ctx.unsized_types`
|
||||
let lower = || -> bool {
|
||||
match bound {
|
||||
TypeBound::Path(_, TraitBoundModifier::Maybe) => true,
|
||||
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
|
||||
let TypeRef::Path(path) = &ctx.store[path.type_ref()] else {
|
||||
return false;
|
||||
};
|
||||
let Some(pointee_sized) =
|
||||
LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
// Lower the path directly with `Resolver` instead of PathLoweringContext`
|
||||
// to prevent diagnostics duplications.
|
||||
ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and(
|
||||
|it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized),
|
||||
)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}();
|
||||
if lower {
|
||||
ctx.lower_where_predicate(pred, true).for_each(drop);
|
||||
}
|
||||
return false;
|
||||
@ -957,7 +1007,7 @@ pub(crate) fn generic_predicates_for_param_query(
|
||||
};
|
||||
|
||||
all_super_traits(db, tr).iter().any(|tr| {
|
||||
db.trait_items(*tr).items.iter().any(|(name, item)| {
|
||||
tr.trait_items(db).items.iter().any(|(name, item)| {
|
||||
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
|
||||
})
|
||||
})
|
||||
@ -1025,6 +1075,10 @@ pub(crate) fn trait_environment_query(
|
||||
def: GenericDefId,
|
||||
) -> Arc<TraitEnvironment> {
|
||||
let generics = generics(db, def);
|
||||
if generics.has_no_predicates() && generics.is_empty() {
|
||||
return TraitEnvironment::empty(def.krate(db));
|
||||
}
|
||||
|
||||
let resolver = def.resolver(db);
|
||||
let mut ctx = TyLoweringContext::new(
|
||||
db,
|
||||
@ -1128,6 +1182,10 @@ where
|
||||
F: Fn(&WherePredicate, GenericDefId) -> bool,
|
||||
{
|
||||
let generics = generics(db, def);
|
||||
if generics.has_no_predicates() && generics.is_empty() {
|
||||
return (GenericPredicates(None), None);
|
||||
}
|
||||
|
||||
let resolver = def.resolver(db);
|
||||
let mut ctx = TyLoweringContext::new(
|
||||
db,
|
||||
@ -1154,7 +1212,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if generics.len() > 0 {
|
||||
if !generics.is_empty() {
|
||||
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let explicitly_unsized_tys = ctx.unsized_types;
|
||||
if let Some(implicitly_sized_predicates) =
|
||||
@ -1229,7 +1287,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query(
|
||||
def: GenericDefId,
|
||||
) -> (GenericDefaults, Diagnostics) {
|
||||
let generic_params = generics(db, def);
|
||||
if generic_params.len() == 0 {
|
||||
if generic_params.is_empty() {
|
||||
return (GenericDefaults(None), None);
|
||||
}
|
||||
let resolver = def.resolver(db);
|
||||
@ -1418,7 +1476,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
|
||||
|
||||
/// Build the type of a tuple struct constructor.
|
||||
fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> {
|
||||
let struct_data = db.variant_fields(def.into());
|
||||
let struct_data = def.fields(db);
|
||||
match struct_data.shape {
|
||||
FieldsShape::Record => None,
|
||||
FieldsShape::Unit => Some(type_for_adt(db, def.into())),
|
||||
@ -1451,7 +1509,7 @@ fn type_for_enum_variant_constructor(
|
||||
def: EnumVariantId,
|
||||
) -> Option<Binders<Ty>> {
|
||||
let e = def.lookup(db).parent;
|
||||
match db.variant_fields(def.into()).shape {
|
||||
match def.fields(db).shape {
|
||||
FieldsShape::Record => None,
|
||||
FieldsShape::Unit => Some(type_for_adt(db, e.into())),
|
||||
FieldsShape::Tuple => {
|
||||
|
@ -173,7 +173,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
||||
self.skip_resolved_segment();
|
||||
let segment = self.current_or_prev_segment;
|
||||
let found =
|
||||
self.ctx.db.trait_items(trait_).associated_type_by_name(segment.name);
|
||||
trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name);
|
||||
|
||||
match found {
|
||||
Some(associated_ty) => {
|
||||
|
@ -1302,7 +1302,7 @@ fn iterate_trait_method_candidates(
|
||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||
// iteration
|
||||
let mut known_implemented = false;
|
||||
for &(_, item) in db.trait_items(t).items.iter() {
|
||||
for &(_, item) in t.trait_items(db).items.iter() {
|
||||
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
|
||||
// since only inherent methods should be included into visibility checking.
|
||||
let visible =
|
||||
@ -1429,7 +1429,7 @@ fn iterate_inherent_methods(
|
||||
) -> ControlFlow<()> {
|
||||
let db = table.db;
|
||||
for t in traits {
|
||||
let data = db.trait_items(t);
|
||||
let data = t.trait_items(db);
|
||||
for &(_, item) in data.items.iter() {
|
||||
// We don't pass `visible_from_module` as all trait items should be visible.
|
||||
let visible = match is_valid_trait_method_candidate(
|
||||
|
@ -657,12 +657,12 @@ impl Evaluator<'_> {
|
||||
cached_ptr_size,
|
||||
cached_fn_trait_func: LangItem::Fn
|
||||
.resolve_trait(db, crate_id)
|
||||
.and_then(|x| db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call))),
|
||||
.and_then(|x| x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call))),
|
||||
cached_fn_mut_trait_func: LangItem::FnMut.resolve_trait(db, crate_id).and_then(|x| {
|
||||
db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut))
|
||||
x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_mut))
|
||||
}),
|
||||
cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| {
|
||||
db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once))
|
||||
x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once))
|
||||
}),
|
||||
})
|
||||
}
|
||||
@ -1749,8 +1749,7 @@ impl Evaluator<'_> {
|
||||
AdtId::UnionId(_) => not_supported!("unsizing unions"),
|
||||
AdtId::EnumId(_) => not_supported!("unsizing enums"),
|
||||
};
|
||||
let Some((last_field, _)) =
|
||||
self.db.variant_fields(id.into()).fields().iter().next_back()
|
||||
let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back()
|
||||
else {
|
||||
not_supported!("unsizing struct without field");
|
||||
};
|
||||
@ -2232,7 +2231,7 @@ impl Evaluator<'_> {
|
||||
}
|
||||
chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
|
||||
AdtId::StructId(s) => {
|
||||
let data = this.db.variant_fields(s.into());
|
||||
let data = s.fields(this.db);
|
||||
let layout = this.layout(ty)?;
|
||||
let field_types = this.db.field_types(s.into());
|
||||
for (f, _) in data.fields().iter() {
|
||||
@ -2261,7 +2260,7 @@ impl Evaluator<'_> {
|
||||
bytes,
|
||||
e,
|
||||
) {
|
||||
let data = &this.db.variant_fields(v.into());
|
||||
let data = v.fields(this.db);
|
||||
let field_types = this.db.field_types(v.into());
|
||||
for (f, _) in data.fields().iter() {
|
||||
let offset =
|
||||
@ -2808,7 +2807,7 @@ impl Evaluator<'_> {
|
||||
) -> Result<()> {
|
||||
let Some(drop_fn) = (|| {
|
||||
let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?;
|
||||
self.db.trait_items(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop))
|
||||
drop_trait.trait_items(self.db).method_by_name(&Name::new_symbol_root(sym::drop))
|
||||
})() else {
|
||||
// in some tests we don't have drop trait in minicore, and
|
||||
// we can ignore drop in them.
|
||||
@ -2838,7 +2837,7 @@ impl Evaluator<'_> {
|
||||
return Ok(());
|
||||
}
|
||||
let layout = self.layout_adt(id.0, subst.clone())?;
|
||||
let variant_fields = self.db.variant_fields(s.into());
|
||||
let variant_fields = s.fields(self.db);
|
||||
match variant_fields.shape {
|
||||
FieldsShape::Record | FieldsShape::Tuple => {
|
||||
let field_types = self.db.field_types(s.into());
|
||||
@ -2918,7 +2917,7 @@ pub fn render_const_using_debug_impl(
|
||||
not_supported!("core::fmt::Debug not found");
|
||||
};
|
||||
let Some(debug_fmt_fn) =
|
||||
db.trait_items(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt))
|
||||
debug_trait.trait_items(db).method_by_name(&Name::new_symbol_root(sym::fmt))
|
||||
else {
|
||||
not_supported!("core::fmt::Debug::fmt not found");
|
||||
};
|
||||
@ -3045,7 +3044,10 @@ impl IntValue {
|
||||
(8, true) => Self::I64(i64::from_le_bytes(bytes.try_into().unwrap())),
|
||||
(16, false) => Self::U128(u128::from_le_bytes(bytes.try_into().unwrap())),
|
||||
(16, true) => Self::I128(i128::from_le_bytes(bytes.try_into().unwrap())),
|
||||
_ => panic!("invalid integer size"),
|
||||
(len, is_signed) => {
|
||||
never!("invalid integer size: {len}, signed: {is_signed}");
|
||||
Self::I32(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1257,9 +1257,8 @@ impl Evaluator<'_> {
|
||||
args.push(IntervalAndTy::new(addr, field, self, locals)?);
|
||||
}
|
||||
if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) {
|
||||
if let Some(def) = self
|
||||
.db
|
||||
.trait_items(target)
|
||||
if let Some(def) = target
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::call_once))
|
||||
{
|
||||
self.exec_fn_trait(
|
||||
|
@ -31,7 +31,7 @@ impl Evaluator<'_> {
|
||||
Some(len) => len,
|
||||
_ => {
|
||||
if let AdtId::StructId(id) = id.0 {
|
||||
let struct_data = self.db.variant_fields(id.into());
|
||||
let struct_data = id.fields(self.db);
|
||||
let fields = struct_data.fields();
|
||||
let Some((first_field, _)) = fields.iter().next() else {
|
||||
not_supported!("simd type with no field");
|
||||
|
@ -984,3 +984,17 @@ fn main<'a, T: Foo + Bar + Baz>(
|
||||
|e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_args_pass() {
|
||||
check_pass(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
fn main() {
|
||||
let x1 = format_args!("");
|
||||
let x2 = format_args!("{}", x1);
|
||||
let x3 = format_args!("{} {}", x1, x2);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
Ok(Some(current))
|
||||
}
|
||||
ValueNs::EnumVariantId(variant_id) => {
|
||||
let variant_fields = &self.db.variant_fields(variant_id.into());
|
||||
let variant_fields = variant_id.fields(self.db);
|
||||
if variant_fields.shape == FieldsShape::Unit {
|
||||
let ty = self.infer.type_of_expr[expr_id].clone();
|
||||
current = self.lower_enum_variant(
|
||||
@ -856,7 +856,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
TyKind::Adt(_, s) => s.clone(),
|
||||
_ => not_supported!("Non ADT record literal"),
|
||||
};
|
||||
let variant_fields = self.db.variant_fields(variant_id);
|
||||
let variant_fields = variant_id.fields(self.db);
|
||||
match variant_id {
|
||||
VariantId::EnumVariantId(_) | VariantId::StructId(_) => {
|
||||
let mut operands = vec![None; variant_fields.fields().len()];
|
||||
@ -1176,8 +1176,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||
place,
|
||||
Rvalue::Aggregate(
|
||||
AggregateKind::Adt(st.into(), subst.clone()),
|
||||
self.db
|
||||
.variant_fields(st.into())
|
||||
st.fields(self.db)
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|it| {
|
||||
|
@ -193,9 +193,8 @@ impl MirLowerCtx<'_> {
|
||||
if let Some(deref_trait) =
|
||||
self.resolve_lang_item(LangItem::DerefMut)?.as_trait()
|
||||
{
|
||||
if let Some(deref_fn) = self
|
||||
.db
|
||||
.trait_items(deref_trait)
|
||||
if let Some(deref_fn) = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&Name::new_symbol_root(sym::deref_mut))
|
||||
{
|
||||
break 'b deref_fn == f;
|
||||
@ -347,9 +346,8 @@ impl MirLowerCtx<'_> {
|
||||
.resolve_lang_item(trait_lang_item)?
|
||||
.as_trait()
|
||||
.ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
|
||||
let deref_fn = self
|
||||
.db
|
||||
.trait_items(deref_trait)
|
||||
let deref_fn = deref_trait
|
||||
.trait_items(self.db)
|
||||
.method_by_name(&trait_method_name)
|
||||
.ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
|
||||
let deref_fn_op = Operand::const_zst(
|
||||
|
@ -609,7 +609,7 @@ impl MirLowerCtx<'_> {
|
||||
}
|
||||
self.pattern_matching_variant_fields(
|
||||
shape,
|
||||
&self.db.variant_fields(v.into()),
|
||||
v.fields(self.db),
|
||||
variant,
|
||||
current,
|
||||
current_else,
|
||||
@ -619,7 +619,7 @@ impl MirLowerCtx<'_> {
|
||||
}
|
||||
VariantId::StructId(s) => self.pattern_matching_variant_fields(
|
||||
shape,
|
||||
&self.db.variant_fields(s.into()),
|
||||
s.fields(self.db),
|
||||
variant,
|
||||
current,
|
||||
current_else,
|
||||
|
@ -326,7 +326,7 @@ impl<'a> MirPrettyCtx<'a> {
|
||||
w!(this, ")");
|
||||
}
|
||||
ProjectionElem::Field(Either::Left(field)) => {
|
||||
let variant_fields = this.db.variant_fields(field.parent);
|
||||
let variant_fields = field.parent.fields(this.db);
|
||||
let name = &variant_fields.fields()[field.local_id].name;
|
||||
match field.parent {
|
||||
hir_def::VariantId::EnumVariantId(e) => {
|
||||
|
@ -486,7 +486,7 @@ pub(crate) fn visit_module(
|
||||
});
|
||||
}
|
||||
ModuleDefId::TraitId(it) => {
|
||||
let trait_data = db.trait_items(it);
|
||||
let trait_data = it.trait_items(db);
|
||||
for &(_, item) in trait_data.items.iter() {
|
||||
match item {
|
||||
AssocItemId::FunctionId(it) => cb(it.into()),
|
||||
|
@ -561,7 +561,7 @@ trait Foo {}
|
||||
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
|
||||
let _: &dyn Foo = &f;
|
||||
let _: &dyn Foo = g;
|
||||
//^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized
|
||||
//^ expected &'? (dyn Foo + '?), got &'? impl Foo + ?Sized
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
@ -67,11 +67,11 @@ trait B: A {}
|
||||
|
||||
fn test<'a>(
|
||||
_: &(dyn A<Assoc = ()> + Send),
|
||||
//^ &(dyn A<Assoc = ()> + Send + 'static)
|
||||
//^ &(dyn A<Assoc = ()> + Send)
|
||||
_: &'a (dyn Send + A<Assoc = ()>),
|
||||
//^ &'a (dyn A<Assoc = ()> + Send + 'static)
|
||||
//^ &'a (dyn A<Assoc = ()> + Send)
|
||||
_: &dyn B<Assoc = ()>,
|
||||
//^ &(dyn B<Assoc = ()> + 'static)
|
||||
//^ &(dyn B<Assoc = ()>)
|
||||
) {}
|
||||
"#,
|
||||
);
|
||||
@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
|
||||
trait Foo<'a> {}
|
||||
|
||||
fn foo(foo: &dyn for<'a> Foo<'a>) {}
|
||||
// ^^^ &(dyn Foo<'?> + 'static)
|
||||
// ^^^ &dyn Foo<'?>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ fn main() {
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_items_with_diagnostics_shim",
|
||||
"query_with_diagnostics_",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
@ -596,8 +596,8 @@ fn main() {
|
||||
"struct_signature_with_source_map_shim",
|
||||
"generic_predicates_shim",
|
||||
"value_ty_shim",
|
||||
"variant_fields_shim",
|
||||
"variant_fields_with_source_map_shim",
|
||||
"firewall_",
|
||||
"query_",
|
||||
"lang_item",
|
||||
"inherent_impls_in_crate_shim",
|
||||
"impl_signature_shim",
|
||||
@ -674,7 +674,7 @@ fn main() {
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_items_with_diagnostics_shim",
|
||||
"query_with_diagnostics_",
|
||||
"body_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"body_shim",
|
||||
@ -695,11 +695,9 @@ fn main() {
|
||||
"return_type_impl_traits_shim",
|
||||
"infer_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"expr_scopes_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"generic_predicates_shim",
|
||||
"variant_fields_with_source_map_shim",
|
||||
"query_",
|
||||
"inherent_impls_in_crate_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_signature_shim",
|
||||
@ -709,7 +707,6 @@ fn main() {
|
||||
"impl_trait_with_diagnostics_shim",
|
||||
"impl_self_ty_with_diagnostics_shim",
|
||||
"generic_predicates_shim",
|
||||
"generic_predicates_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() {
|
||||
51..55 'self': &'? Self
|
||||
64..69 '{ 0 }': u32
|
||||
66..67 '0': u32
|
||||
176..177 'd': &'? (dyn Trait + 'static)
|
||||
176..177 'd': &'? (dyn Trait + '?)
|
||||
191..207 '{ ...o(); }': ()
|
||||
197..198 'd': &'? (dyn Trait + 'static)
|
||||
197..198 'd': &'? (dyn Trait + '?)
|
||||
197..204 'd.foo()': u32
|
||||
"#]],
|
||||
);
|
||||
@ -2019,10 +2019,10 @@ impl dyn Error + Send {
|
||||
/// Attempts to downcast the box to a concrete type.
|
||||
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
|
||||
let err: Box<dyn Error> = self;
|
||||
// ^^^^ expected Box<dyn Error + 'static>, got Box<dyn Error + Send + 'static>
|
||||
// ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + '?>
|
||||
// FIXME, type mismatch should not occur
|
||||
<dyn Error>::downcast(err).map_err(|_| loop {})
|
||||
//^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>>
|
||||
//^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + '?>) -> Result<Box<{unknown}>, Box<dyn Error + '?>>
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() {
|
||||
488..522 '{ ... }': ()
|
||||
498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
|
||||
498..508 'self.order': O
|
||||
498..515 'self.o...into()': dyn QueryFragment<DB> + 'static
|
||||
498..515 'self.o...into()': dyn QueryFragment<DB> + '?
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -773,7 +773,7 @@ fn issue_4800() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
379..383 'self': &'? mut PeerSet<D>
|
||||
401..424 '{ ... }': dyn Future<Output = ()> + 'static
|
||||
401..424 '{ ... }': dyn Future<Output = ()> + '?
|
||||
411..418 'loop {}': !
|
||||
416..418 '{}': ()
|
||||
575..579 'self': &'? mut Self
|
||||
|
@ -2741,11 +2741,11 @@ impl B for Astruct {}
|
||||
715..744 '#[rust...1i32])': Box<[i32; 1], Global>
|
||||
737..743 '[1i32]': [i32; 1]
|
||||
738..742 '1i32': i32
|
||||
755..756 'v': Vec<Box<dyn B + 'static, Global>, Global>
|
||||
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + 'static, Global>, Global>(Box<[Box<dyn B + 'static, Global>], Global>) -> Vec<Box<dyn B + 'static, Global>, Global>
|
||||
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + 'static, Global>, Global>
|
||||
794..849 '#[rust...uct)])': Box<[Box<dyn B + 'static, Global>; 1], Global>
|
||||
816..848 '[#[rus...ruct)]': [Box<dyn B + 'static, Global>; 1]
|
||||
755..756 'v': Vec<Box<dyn B + '?, Global>, Global>
|
||||
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
|
||||
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
|
||||
794..849 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
|
||||
816..848 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
|
||||
817..847 '#[rust...truct)': Box<Astruct, Global>
|
||||
839..846 'Astruct': Astruct
|
||||
"#]],
|
||||
|
@ -1475,26 +1475,26 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) {
|
||||
expect![[r#"
|
||||
29..33 'self': &'? Self
|
||||
54..58 'self': &'? Self
|
||||
198..200 '{}': Box<dyn Trait<u64> + 'static>
|
||||
210..211 'x': Box<dyn Trait<u64> + 'static>
|
||||
234..235 'y': &'? (dyn Trait<u64> + 'static)
|
||||
198..200 '{}': Box<dyn Trait<u64> + '?>
|
||||
210..211 'x': Box<dyn Trait<u64> + '?>
|
||||
234..235 'y': &'? (dyn Trait<u64> + '?)
|
||||
254..371 '{ ...2(); }': ()
|
||||
260..261 'x': Box<dyn Trait<u64> + 'static>
|
||||
267..268 'y': &'? (dyn Trait<u64> + 'static)
|
||||
278..279 'z': Box<dyn Trait<u64> + 'static>
|
||||
282..285 'bar': fn bar() -> Box<dyn Trait<u64> + 'static>
|
||||
282..287 'bar()': Box<dyn Trait<u64> + 'static>
|
||||
293..294 'x': Box<dyn Trait<u64> + 'static>
|
||||
260..261 'x': Box<dyn Trait<u64> + '?>
|
||||
267..268 'y': &'? (dyn Trait<u64> + '?)
|
||||
278..279 'z': Box<dyn Trait<u64> + '?>
|
||||
282..285 'bar': fn bar() -> Box<dyn Trait<u64> + '?>
|
||||
282..287 'bar()': Box<dyn Trait<u64> + '?>
|
||||
293..294 'x': Box<dyn Trait<u64> + '?>
|
||||
293..300 'x.foo()': u64
|
||||
306..307 'y': &'? (dyn Trait<u64> + 'static)
|
||||
306..307 'y': &'? (dyn Trait<u64> + '?)
|
||||
306..313 'y.foo()': u64
|
||||
319..320 'z': Box<dyn Trait<u64> + 'static>
|
||||
319..320 'z': Box<dyn Trait<u64> + '?>
|
||||
319..326 'z.foo()': u64
|
||||
332..333 'x': Box<dyn Trait<u64> + 'static>
|
||||
332..333 'x': Box<dyn Trait<u64> + '?>
|
||||
332..340 'x.foo2()': i64
|
||||
346..347 'y': &'? (dyn Trait<u64> + 'static)
|
||||
346..347 'y': &'? (dyn Trait<u64> + '?)
|
||||
346..354 'y.foo2()': i64
|
||||
360..361 'z': Box<dyn Trait<u64> + 'static>
|
||||
360..361 'z': Box<dyn Trait<u64> + '?>
|
||||
360..368 'z.foo2()': i64
|
||||
"#]],
|
||||
);
|
||||
@ -1523,14 +1523,14 @@ fn test(s: S<u32, i32>) {
|
||||
expect![[r#"
|
||||
32..36 'self': &'? Self
|
||||
102..106 'self': &'? S<T, U>
|
||||
128..139 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
|
||||
128..139 '{ loop {} }': &'? (dyn Trait<T, U> + '?)
|
||||
130..137 'loop {}': !
|
||||
135..137 '{}': ()
|
||||
175..179 'self': &'? Self
|
||||
251..252 's': S<u32, i32>
|
||||
267..289 '{ ...z(); }': ()
|
||||
273..274 's': S<u32, i32>
|
||||
273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
|
||||
273..280 's.bar()': &'? (dyn Trait<u32, i32> + '?)
|
||||
273..286 's.bar().baz()': (u32, i32)
|
||||
"#]],
|
||||
);
|
||||
@ -1556,20 +1556,20 @@ fn test(x: Trait, y: &Trait) -> u64 {
|
||||
}"#,
|
||||
expect![[r#"
|
||||
26..30 'self': &'? Self
|
||||
60..62 '{}': dyn Trait + 'static
|
||||
72..73 'x': dyn Trait + 'static
|
||||
82..83 'y': &'? (dyn Trait + 'static)
|
||||
60..62 '{}': dyn Trait + '?
|
||||
72..73 'x': dyn Trait + '?
|
||||
82..83 'y': &'? (dyn Trait + '?)
|
||||
100..175 '{ ...o(); }': u64
|
||||
106..107 'x': dyn Trait + 'static
|
||||
113..114 'y': &'? (dyn Trait + 'static)
|
||||
124..125 'z': dyn Trait + 'static
|
||||
128..131 'bar': fn bar() -> dyn Trait + 'static
|
||||
128..133 'bar()': dyn Trait + 'static
|
||||
139..140 'x': dyn Trait + 'static
|
||||
106..107 'x': dyn Trait + '?
|
||||
113..114 'y': &'? (dyn Trait + '?)
|
||||
124..125 'z': dyn Trait + '?
|
||||
128..131 'bar': fn bar() -> dyn Trait + '?
|
||||
128..133 'bar()': dyn Trait + '?
|
||||
139..140 'x': dyn Trait + '?
|
||||
139..146 'x.foo()': u64
|
||||
152..153 'y': &'? (dyn Trait + 'static)
|
||||
152..153 'y': &'? (dyn Trait + '?)
|
||||
152..159 'y.foo()': u64
|
||||
165..166 'z': dyn Trait + 'static
|
||||
165..166 'z': dyn Trait + '?
|
||||
165..172 'z.foo()': u64
|
||||
"#]],
|
||||
);
|
||||
@ -1589,10 +1589,10 @@ fn main() {
|
||||
expect![[r#"
|
||||
31..35 'self': &'? S
|
||||
37..39 '{}': ()
|
||||
47..48 '_': &'? (dyn Fn(S) + 'static)
|
||||
47..48 '_': &'? (dyn Fn(S) + '?)
|
||||
58..60 '{}': ()
|
||||
71..105 '{ ...()); }': ()
|
||||
77..78 'f': fn f(&'? (dyn Fn(S) + 'static))
|
||||
77..78 'f': fn f(&'? (dyn Fn(S) + '?))
|
||||
77..102 'f(&|nu...foo())': ()
|
||||
79..101 '&|numb....foo()': &'? impl Fn(S)
|
||||
80..101 '|numbe....foo()': impl Fn(S)
|
||||
@ -2927,13 +2927,13 @@ fn test(x: &dyn Foo) {
|
||||
foo(x);
|
||||
}"#,
|
||||
expect![[r#"
|
||||
21..22 'x': &'? (dyn Foo + 'static)
|
||||
21..22 'x': &'? (dyn Foo + '?)
|
||||
34..36 '{}': ()
|
||||
46..47 'x': &'? (dyn Foo + 'static)
|
||||
46..47 'x': &'? (dyn Foo + '?)
|
||||
59..74 '{ foo(x); }': ()
|
||||
65..68 'foo': fn foo(&'? (dyn Foo + 'static))
|
||||
65..68 'foo': fn foo(&'? (dyn Foo + '?))
|
||||
65..71 'foo(x)': ()
|
||||
69..70 'x': &'? (dyn Foo + 'static)
|
||||
69..70 'x': &'? (dyn Foo + '?)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -3210,13 +3210,13 @@ fn foo() {
|
||||
218..324 '{ ...&s); }': ()
|
||||
228..229 's': Option<i32>
|
||||
232..236 'None': Option<i32>
|
||||
246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static>
|
||||
281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + 'static>
|
||||
246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + '?>
|
||||
281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + '?>
|
||||
294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>)
|
||||
300..307 '|ps| {}': impl FnOnce(&'? Option<i32>)
|
||||
301..303 'ps': &'? Option<i32>
|
||||
305..307 '{}': ()
|
||||
316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static>
|
||||
316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + '?>
|
||||
316..321 'f(&s)': ()
|
||||
318..320 '&s': &'? Option<i32>
|
||||
319..320 's': Option<i32>
|
||||
@ -4252,9 +4252,9 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
|
||||
"#,
|
||||
expect![[r#"
|
||||
90..94 'self': &'? Self
|
||||
127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static)
|
||||
127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
|
||||
164..195 '{ ...f(); }': ()
|
||||
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static)
|
||||
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
|
||||
170..184 'v.get::<i32>()': &'? i32
|
||||
170..192 'v.get:...eref()': &'? i32
|
||||
"#]],
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Helper functions for working with def, which don't need to be a separate
|
||||
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
|
||||
|
||||
use std::iter;
|
||||
use std::{cell::LazyCell, iter};
|
||||
|
||||
use base_db::Crate;
|
||||
use chalk_ir::{
|
||||
@ -161,11 +161,12 @@ impl Iterator for ClauseElaborator<'_> {
|
||||
}
|
||||
|
||||
fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
|
||||
let resolver = trait_.resolver(db);
|
||||
let resolver = LazyCell::new(|| trait_.resolver(db));
|
||||
let (generic_params, store) = db.generic_params_and_store(trait_.into());
|
||||
let trait_self = generic_params.trait_self_param();
|
||||
generic_params
|
||||
.where_predicates()
|
||||
.iter()
|
||||
.filter_map(|pred| match pred {
|
||||
WherePredicate::ForLifetime { target, bound, .. }
|
||||
| WherePredicate::TypeBound { target, bound } => {
|
||||
@ -218,7 +219,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
|
||||
name: &Name,
|
||||
) -> Option<(TraitRef, TypeAliasId)> {
|
||||
all_super_trait_refs(db, trait_ref, |t| {
|
||||
let assoc_type = db.trait_items(t.hir_trait_id()).associated_type_by_name(name)?;
|
||||
let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?;
|
||||
Some((t, assoc_type))
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc-hash.workspace = true
|
||||
|
@ -207,7 +207,7 @@ fn resolve_assoc_or_field(
|
||||
// Doc paths in this context may only resolve to an item of this trait
|
||||
// (i.e. no items of its supertraits), so we need to handle them here
|
||||
// independently of others.
|
||||
return db.trait_items(id).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
|
||||
return id.trait_items(db).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
|
||||
let def = match *assoc_id {
|
||||
AssocItemId::FunctionId(it) => ModuleDef::Function(it.into()),
|
||||
AssocItemId::ConstId(it) => ModuleDef::Const(it.into()),
|
||||
|
@ -490,7 +490,7 @@ impl<'db> AnyDiagnostic<'db> {
|
||||
) -> Option<AnyDiagnostic<'db>> {
|
||||
match diagnostic {
|
||||
BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
|
||||
let variant_data = variant.variant_data(db);
|
||||
let variant_data = variant.fields(db);
|
||||
let missed_fields = missed_fields
|
||||
.into_iter()
|
||||
.map(|idx| variant_data.fields()[idx].name.clone())
|
||||
|
@ -404,7 +404,7 @@ impl HirDisplay for TupleField {
|
||||
impl HirDisplay for Variant {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
|
||||
let data = f.db.variant_fields(self.id.into());
|
||||
let data = self.id.fields(f.db);
|
||||
match data.shape {
|
||||
FieldsShape::Unit => {}
|
||||
FieldsShape::Tuple => {
|
||||
@ -633,7 +633,7 @@ fn has_disaplayable_predicates(
|
||||
params: &GenericParams,
|
||||
store: &ExpressionStore,
|
||||
) -> bool {
|
||||
params.where_predicates().any(|pred| {
|
||||
params.where_predicates().iter().any(|pred| {
|
||||
!matches!(
|
||||
pred,
|
||||
WherePredicate::TypeBound { target, .. }
|
||||
@ -668,7 +668,7 @@ fn write_where_predicates(
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let mut iter = params.where_predicates().peekable();
|
||||
let mut iter = params.where_predicates().iter().peekable();
|
||||
while let Some(pred) = iter.next() {
|
||||
if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(*target)) {
|
||||
continue;
|
||||
|
@ -54,7 +54,7 @@ use hir_def::{
|
||||
},
|
||||
item_tree::ImportAlias,
|
||||
layout::{self, ReprOptions, TargetDataLayout},
|
||||
nameres::{self, diagnostics::DefDiagnostic},
|
||||
nameres::{self, assoc::TraitItems, diagnostics::DefDiagnostic},
|
||||
per_ns::PerNs,
|
||||
resolver::{HasResolver, Resolver},
|
||||
signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields},
|
||||
@ -649,7 +649,7 @@ impl Module {
|
||||
acc.extend(def.diagnostics(db, style_lints))
|
||||
}
|
||||
ModuleDef::Trait(t) => {
|
||||
for diag in db.trait_items_with_diagnostics(t.id).1.iter() {
|
||||
for diag in TraitItems::query_with_diagnostics(db, t.id).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag, edition);
|
||||
}
|
||||
|
||||
@ -668,25 +668,25 @@ impl Module {
|
||||
Adt::Struct(s) => {
|
||||
let source_map = db.struct_signature_with_source_map(s.id).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
let source_map = db.variant_fields_with_source_map(s.id.into()).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
let source_map = &s.id.fields_with_source_map(db).1;
|
||||
expr_store_diagnostics(db, acc, source_map);
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
acc,
|
||||
db.field_types_with_diagnostics(s.id.into()).1,
|
||||
&source_map,
|
||||
source_map,
|
||||
);
|
||||
}
|
||||
Adt::Union(u) => {
|
||||
let source_map = db.union_signature_with_source_map(u.id).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
let source_map = db.variant_fields_with_source_map(u.id.into()).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
let source_map = &u.id.fields_with_source_map(db).1;
|
||||
expr_store_diagnostics(db, acc, source_map);
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
acc,
|
||||
db.field_types_with_diagnostics(u.id.into()).1,
|
||||
&source_map,
|
||||
source_map,
|
||||
);
|
||||
}
|
||||
Adt::Enum(e) => {
|
||||
@ -711,14 +711,14 @@ impl Module {
|
||||
}
|
||||
}
|
||||
for &(v, _, _) in &variants.variants {
|
||||
let source_map = db.variant_fields_with_source_map(v.into()).1;
|
||||
let source_map = &v.fields_with_source_map(db).1;
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
acc,
|
||||
db.field_types_with_diagnostics(v.into()).1,
|
||||
&source_map,
|
||||
source_map,
|
||||
);
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
expr_store_diagnostics(db, acc, source_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -822,7 +822,7 @@ impl Module {
|
||||
|
||||
// Negative impls can't have items, don't emit missing items diagnostic for them
|
||||
if let (false, Some(trait_)) = (impl_is_negative, trait_) {
|
||||
let items = &db.trait_items(trait_.into()).items;
|
||||
let items = &trait_.id.trait_items(db).items;
|
||||
let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
|
||||
AssocItemId::FunctionId(it) => !db.function_signature(it).has_body(),
|
||||
AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
|
||||
@ -1311,7 +1311,7 @@ impl AstNode for FieldSource {
|
||||
|
||||
impl Field {
|
||||
pub fn name(&self, db: &dyn HirDatabase) -> Name {
|
||||
db.variant_fields(self.parent.into()).fields()[self.id].name.clone()
|
||||
VariantId::from(self.parent).fields(db).fields()[self.id].name.clone()
|
||||
}
|
||||
|
||||
pub fn index(&self) -> usize {
|
||||
@ -1380,7 +1380,7 @@ impl Field {
|
||||
|
||||
impl HasVisibility for Field {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let variant_data = db.variant_fields(self.parent.into());
|
||||
let variant_data = VariantId::from(self.parent).fields(db);
|
||||
let visibility = &variant_data.fields()[self.id].visibility;
|
||||
let parent_id: hir_def::VariantId = self.parent.into();
|
||||
// FIXME: RawVisibility::Public doesn't need to construct a resolver
|
||||
@ -1403,7 +1403,8 @@ impl Struct {
|
||||
}
|
||||
|
||||
pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
|
||||
db.variant_fields(self.id.into())
|
||||
self.id
|
||||
.fields(db)
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|(id, _)| Field { parent: self.into(), id })
|
||||
@ -1434,8 +1435,8 @@ impl Struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn variant_fields(self, db: &dyn HirDatabase) -> Arc<VariantFields> {
|
||||
db.variant_fields(self.id.into())
|
||||
fn variant_fields(self, db: &dyn HirDatabase) -> &VariantFields {
|
||||
self.id.fields(db)
|
||||
}
|
||||
|
||||
pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
|
||||
@ -1478,7 +1479,7 @@ impl Union {
|
||||
}
|
||||
|
||||
pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
|
||||
match db.variant_fields(self.id.into()).shape {
|
||||
match self.id.fields(db).shape {
|
||||
hir_def::item_tree::FieldsShape::Record => StructKind::Record,
|
||||
hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple,
|
||||
hir_def::item_tree::FieldsShape::Unit => StructKind::Unit,
|
||||
@ -1486,7 +1487,8 @@ impl Union {
|
||||
}
|
||||
|
||||
pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
|
||||
db.variant_fields(self.id.into())
|
||||
self.id
|
||||
.fields(db)
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|(id, _)| Field { parent: self.into(), id })
|
||||
@ -1626,7 +1628,8 @@ impl Variant {
|
||||
}
|
||||
|
||||
pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
|
||||
db.variant_fields(self.id.into())
|
||||
self.id
|
||||
.fields(db)
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|(id, _)| Field { parent: self.into(), id })
|
||||
@ -1634,7 +1637,7 @@ impl Variant {
|
||||
}
|
||||
|
||||
pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
|
||||
match db.variant_fields(self.id.into()).shape {
|
||||
match self.id.fields(db).shape {
|
||||
hir_def::item_tree::FieldsShape::Record => StructKind::Record,
|
||||
hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple,
|
||||
hir_def::item_tree::FieldsShape::Unit => StructKind::Unit,
|
||||
@ -1727,10 +1730,10 @@ impl Adt {
|
||||
pub fn ty_with_args<'db>(
|
||||
self,
|
||||
db: &'db dyn HirDatabase,
|
||||
args: impl Iterator<Item = Type<'db>>,
|
||||
args: impl IntoIterator<Item = Type<'db>>,
|
||||
) -> Type<'db> {
|
||||
let id = AdtId::from(self);
|
||||
let mut it = args.map(|t| t.ty);
|
||||
let mut it = args.into_iter().map(|t| t.ty);
|
||||
let ty = TyBuilder::def_ty(db, id.into(), None)
|
||||
.fill(|x| {
|
||||
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
|
||||
@ -2883,7 +2886,7 @@ impl Trait {
|
||||
}
|
||||
|
||||
pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
|
||||
db.trait_items(self.id).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
|
||||
self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
|
||||
{
|
||||
AssocItemId::FunctionId(id) => Some(Function { id }),
|
||||
_ => None,
|
||||
@ -2891,7 +2894,7 @@ impl Trait {
|
||||
}
|
||||
|
||||
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
|
||||
db.trait_items(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
|
||||
self.id.trait_items(db).items.iter().map(|(_name, it)| (*it).into()).collect()
|
||||
}
|
||||
|
||||
pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
|
||||
@ -2939,7 +2942,7 @@ impl Trait {
|
||||
}
|
||||
|
||||
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
||||
db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice()
|
||||
self.id.trait_items(db).macro_calls.to_vec().into_boxed_slice()
|
||||
}
|
||||
|
||||
/// `#[rust_analyzer::completions(...)]` mode.
|
||||
@ -3043,10 +3046,17 @@ pub struct BuiltinType {
|
||||
}
|
||||
|
||||
impl BuiltinType {
|
||||
// Constructors are added on demand, feel free to add more.
|
||||
pub fn str() -> BuiltinType {
|
||||
BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
|
||||
}
|
||||
|
||||
pub fn i32() -> BuiltinType {
|
||||
BuiltinType {
|
||||
inner: hir_def::builtin_type::BuiltinType::Int(hir_ty::primitive::BuiltinInt::I32),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
|
||||
let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
|
||||
Type::new_for_crate(core, TyBuilder::builtin(self.inner))
|
||||
@ -3667,7 +3677,7 @@ impl GenericDef {
|
||||
|
||||
let generics = db.generic_params(def);
|
||||
|
||||
if generics.is_empty() && generics.no_predicates() {
|
||||
if generics.is_empty() && generics.has_no_predicates() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5000,7 +5010,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
let output_assoc_type =
|
||||
db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
|
||||
trait_.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
|
||||
self.normalize_trait_assoc_type(db, &[], output_assoc_type.into())
|
||||
}
|
||||
|
||||
@ -5013,8 +5023,8 @@ impl<'db> Type<'db> {
|
||||
/// This does **not** resolve `IntoIterator`, only `Iterator`.
|
||||
pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
|
||||
let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?;
|
||||
let iterator_item = db
|
||||
.trait_items(iterator_trait)
|
||||
let iterator_item = iterator_trait
|
||||
.trait_items(db)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::Item))?;
|
||||
self.normalize_trait_assoc_type(db, &[], iterator_item.into())
|
||||
}
|
||||
@ -5044,8 +5054,8 @@ impl<'db> Type<'db> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let into_iter_assoc_type = db
|
||||
.trait_items(trait_)
|
||||
let into_iter_assoc_type = trait_
|
||||
.trait_items(db)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::IntoIter))?;
|
||||
self.normalize_trait_assoc_type(db, &[], into_iter_assoc_type.into())
|
||||
}
|
||||
|
@ -2199,6 +2199,10 @@ pub struct SemanticsScope<'db> {
|
||||
}
|
||||
|
||||
impl<'db> SemanticsScope<'db> {
|
||||
pub fn file_id(&self) -> HirFileId {
|
||||
self.file_id
|
||||
}
|
||||
|
||||
pub fn module(&self) -> Module {
|
||||
Module { id: self.resolver.module() }
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ pub(crate) trait ChildBySource {
|
||||
|
||||
impl ChildBySource for TraitId {
|
||||
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
||||
let data = db.trait_items(*self);
|
||||
let data = self.trait_items(db);
|
||||
|
||||
data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
|
||||
|(ast_id, call_id)| {
|
||||
@ -191,7 +191,7 @@ impl ChildBySource for VariantId {
|
||||
Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id),
|
||||
}
|
||||
}
|
||||
let (_, sm) = db.variant_fields_with_source_map(*self);
|
||||
let (_, sm) = self.fields_with_source_map(db);
|
||||
sm.expansions().for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id));
|
||||
}
|
||||
}
|
||||
|
@ -156,14 +156,14 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
InFile { file_id, .. }: InFile<&SyntaxNode>,
|
||||
_offset: Option<TextSize>,
|
||||
) -> SourceAnalyzer<'db> {
|
||||
let (fields, source_map) = db.variant_fields_with_source_map(def);
|
||||
let (fields, source_map) = def.fields_with_source_map(db);
|
||||
let resolver = def.resolver(db);
|
||||
SourceAnalyzer {
|
||||
resolver,
|
||||
body_or_sig: Some(BodyOrSig::VariantFields {
|
||||
def,
|
||||
store: fields.store.clone(),
|
||||
source_map,
|
||||
source_map: source_map.clone(),
|
||||
}),
|
||||
file_id,
|
||||
}
|
||||
@ -713,7 +713,7 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
};
|
||||
let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
|
||||
let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
|
||||
let variant_data = variant.variant_data(db);
|
||||
let variant_data = variant.fields(db);
|
||||
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
|
||||
let field_ty =
|
||||
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
|
||||
@ -734,7 +734,7 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
|
||||
let pat_id = self.pat_id(&record_pat.into())?;
|
||||
let variant = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?;
|
||||
let variant_data = variant.variant_data(db);
|
||||
let variant_data = variant.fields(db);
|
||||
let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
|
||||
let (adt, subst) = self.infer()?.type_of_pat.get(pat_id.as_pat()?)?.as_adt()?;
|
||||
let field_ty =
|
||||
@ -803,8 +803,8 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
};
|
||||
container = Either::Right(db.normalize_projection(projection, trait_env.clone()));
|
||||
}
|
||||
let handle_variants = |variant, subst: &Substitution, container: &mut _| {
|
||||
let fields = db.variant_fields(variant);
|
||||
let handle_variants = |variant: VariantId, subst: &Substitution, container: &mut _| {
|
||||
let fields = variant.fields(db);
|
||||
let field = fields.field(&field_name.as_name())?;
|
||||
let field_types = db.field_types(variant);
|
||||
*container = Either::Right(field_types[field].clone().substitute(Interner, subst));
|
||||
@ -1423,7 +1423,7 @@ impl<'db> SourceAnalyzer<'db> {
|
||||
method_name: &Name,
|
||||
) -> Option<(TraitId, FunctionId)> {
|
||||
let trait_id = lang_trait.resolve_trait(db, self.resolver.krate())?;
|
||||
let fn_id = db.trait_items(trait_id).method_by_name(method_name)?;
|
||||
let fn_id = trait_id.trait_items(db).method_by_name(method_name)?;
|
||||
Some((trait_id, fn_id))
|
||||
}
|
||||
|
||||
@ -1580,7 +1580,7 @@ fn resolve_hir_path_(
|
||||
// within the trait's associated types.
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
|
||||
if let Some(type_alias_id) =
|
||||
db.trait_items(trait_id).associated_type_by_name(unresolved.name)
|
||||
trait_id.trait_items(db).associated_type_by_name(unresolved.name)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
@ -1731,7 +1731,7 @@ fn resolve_hir_path_qualifier(
|
||||
// within the trait's associated types.
|
||||
if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
|
||||
if let Some(type_alias_id) =
|
||||
db.trait_items(trait_id).associated_type_by_name(unresolved.name)
|
||||
trait_id.trait_items(db).associated_type_by_name(unresolved.name)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ impl<'a> SymbolCollector<'a> {
|
||||
fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) {
|
||||
let trait_data = self.db.trait_signature(trait_id);
|
||||
self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
|
||||
for &(ref name, assoc_item_id) in &self.db.trait_items(trait_id).items {
|
||||
for &(ref name, assoc_item_id) in &trait_id.trait_items(self.db).items {
|
||||
s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete));
|
||||
}
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::slice;
|
||||
|
||||
use ide_db::assists::GroupLabel;
|
||||
use stdx::to_lower_snake_case;
|
||||
use syntax::ast::HasVisibility;
|
||||
@ -52,7 +54,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||
let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text()));
|
||||
|
||||
// Return early if we've found an existing new fn
|
||||
let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
|
||||
let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?;
|
||||
|
||||
let target = variant.syntax().text_range();
|
||||
acc.add_group(
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::slice;
|
||||
|
||||
use ide_db::assists::GroupLabel;
|
||||
use itertools::Itertools;
|
||||
use stdx::to_lower_snake_case;
|
||||
@ -148,7 +150,7 @@ fn generate_enum_projection_method(
|
||||
let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text()));
|
||||
|
||||
// Return early if we've found an existing new fn
|
||||
let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
|
||||
let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?;
|
||||
|
||||
let target = variant.syntax().text_range();
|
||||
acc.add_group(
|
||||
|
@ -100,9 +100,7 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
|
||||
fn test_complete_todo_with_msg() {
|
||||
check_assist(
|
||||
term_search,
|
||||
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||
// Should implement super let and remove `fmt_before_1_89_0`
|
||||
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||
r#"//- minicore: todo, unimplemented
|
||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||
)
|
||||
@ -112,10 +110,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||
fn test_complete_unimplemented_with_msg() {
|
||||
check_assist(
|
||||
term_search,
|
||||
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||
// Should implement super let and remove `fmt_before_1_89_0`
|
||||
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||
r#"//- minicore: todo, unimplemented
|
||||
fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!("asd") }"#,
|
||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||
)
|
||||
}
|
||||
@ -124,10 +120,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||
fn test_complete_unimplemented() {
|
||||
check_assist(
|
||||
term_search,
|
||||
// FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
|
||||
// Should implement super let and remove `fmt_before_1_89_0`
|
||||
r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
|
||||
fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
|
||||
r#"//- minicore: todo, unimplemented
|
||||
fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!() }"#,
|
||||
r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
|
||||
)
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
};
|
||||
|
||||
let type_ref = &ret_type.ty()?;
|
||||
let ty = ctx.sema.resolve_type(type_ref)?.as_adt();
|
||||
let ty = ctx.sema.resolve_type(type_ref)?;
|
||||
let ty_adt = ty.as_adt();
|
||||
let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate());
|
||||
|
||||
for kind in WrapperKind::ALL {
|
||||
@ -64,7 +65,7 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
continue;
|
||||
};
|
||||
|
||||
if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) {
|
||||
if matches!(ty_adt, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) {
|
||||
// The return type is already wrapped
|
||||
cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped);
|
||||
continue;
|
||||
@ -78,10 +79,23 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
|builder| {
|
||||
let mut editor = builder.make_editor(&parent);
|
||||
let make = SyntaxFactory::with_mappings();
|
||||
let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol());
|
||||
let new_return_ty = alias.unwrap_or_else(|| match kind {
|
||||
WrapperKind::Option => make.ty_option(type_ref.clone()),
|
||||
WrapperKind::Result => make.ty_result(type_ref.clone(), make.ty_infer().into()),
|
||||
let alias = wrapper_alias(ctx, &make, core_wrapper, type_ref, &ty, kind.symbol());
|
||||
let (ast_new_return_ty, semantic_new_return_ty) = alias.unwrap_or_else(|| {
|
||||
let (ast_ty, ty_constructor) = match kind {
|
||||
WrapperKind::Option => {
|
||||
(make.ty_option(type_ref.clone()), famous_defs.core_option_Option())
|
||||
}
|
||||
WrapperKind::Result => (
|
||||
make.ty_result(type_ref.clone(), make.ty_infer().into()),
|
||||
famous_defs.core_result_Result(),
|
||||
),
|
||||
};
|
||||
let semantic_ty = ty_constructor
|
||||
.map(|ty_constructor| {
|
||||
hir::Adt::from(ty_constructor).ty_with_args(ctx.db(), [ty.clone()])
|
||||
})
|
||||
.unwrap_or_else(|| ty.clone());
|
||||
(ast_ty, semantic_ty)
|
||||
});
|
||||
|
||||
let mut exprs_to_wrap = Vec::new();
|
||||
@ -96,6 +110,17 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
for_each_tail_expr(&body_expr, tail_cb);
|
||||
|
||||
for ret_expr_arg in exprs_to_wrap {
|
||||
if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) {
|
||||
if ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) {
|
||||
// The type is already correct, don't wrap it.
|
||||
// We deliberately don't use `could_unify_with_deeply()`, because as long as the outer
|
||||
// enum matches it's okay for us, as we don't trigger the assist if the return type
|
||||
// is already `Option`/`Result`, so mismatched exact type is more likely a mistake
|
||||
// than something intended.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let happy_wrapped = make.expr_call(
|
||||
make.expr_path(make.ident_path(kind.happy_ident())),
|
||||
make.arg_list(iter::once(ret_expr_arg.clone())),
|
||||
@ -103,12 +128,12 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
||||
editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax());
|
||||
}
|
||||
|
||||
editor.replace(type_ref.syntax(), new_return_ty.syntax());
|
||||
editor.replace(type_ref.syntax(), ast_new_return_ty.syntax());
|
||||
|
||||
if let WrapperKind::Result = kind {
|
||||
// Add a placeholder snippet at the first generic argument that doesn't equal the return type.
|
||||
// This is normally the error type, but that may not be the case when we inserted a type alias.
|
||||
let args = new_return_ty
|
||||
let args = ast_new_return_ty
|
||||
.path()
|
||||
.unwrap()
|
||||
.segment()
|
||||
@ -188,27 +213,28 @@ impl WrapperKind {
|
||||
}
|
||||
|
||||
// Try to find an wrapper type alias in the current scope (shadowing the default).
|
||||
fn wrapper_alias(
|
||||
ctx: &AssistContext<'_>,
|
||||
fn wrapper_alias<'db>(
|
||||
ctx: &AssistContext<'db>,
|
||||
make: &SyntaxFactory,
|
||||
core_wrapper: &hir::Enum,
|
||||
ret_type: &ast::Type,
|
||||
core_wrapper: hir::Enum,
|
||||
ast_ret_type: &ast::Type,
|
||||
semantic_ret_type: &hir::Type<'db>,
|
||||
wrapper: hir::Symbol,
|
||||
) -> Option<ast::PathType> {
|
||||
) -> Option<(ast::PathType, hir::Type<'db>)> {
|
||||
let wrapper_path = hir::ModPath::from_segments(
|
||||
hir::PathKind::Plain,
|
||||
iter::once(hir::Name::new_symbol_root(wrapper)),
|
||||
);
|
||||
|
||||
ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| {
|
||||
ctx.sema.resolve_mod_path(ast_ret_type.syntax(), &wrapper_path).and_then(|def| {
|
||||
def.filter_map(|def| match def.into_module_def() {
|
||||
hir::ModuleDef::TypeAlias(alias) => {
|
||||
let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?;
|
||||
(&enum_ty == core_wrapper).then_some(alias)
|
||||
(enum_ty == core_wrapper).then_some((alias, enum_ty))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.find_map(|alias| {
|
||||
.find_map(|(alias, enum_ty)| {
|
||||
let mut inserted_ret_type = false;
|
||||
let generic_args =
|
||||
alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| {
|
||||
@ -216,7 +242,7 @@ fn wrapper_alias(
|
||||
// Replace the very first type parameter with the function's return type.
|
||||
ast::GenericParam::TypeParam(_) if !inserted_ret_type => {
|
||||
inserted_ret_type = true;
|
||||
make.type_arg(ret_type.clone()).into()
|
||||
make.type_arg(ast_ret_type.clone()).into()
|
||||
}
|
||||
ast::GenericParam::LifetimeParam(_) => {
|
||||
make.lifetime_arg(make.lifetime("'_")).into()
|
||||
@ -231,7 +257,10 @@ fn wrapper_alias(
|
||||
make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list),
|
||||
);
|
||||
|
||||
Some(make.ty_path(path))
|
||||
let new_ty =
|
||||
hir::Adt::from(enum_ty).ty_with_args(ctx.db(), [semantic_ret_type.clone()]);
|
||||
|
||||
Some((make.ty_path(path), new_ty))
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -605,29 +634,39 @@ fn foo() -> Option<i32> {
|
||||
check_assist_by_label(
|
||||
wrap_return_type,
|
||||
r#"
|
||||
//- minicore: option
|
||||
//- minicore: option, future
|
||||
struct F(i32);
|
||||
impl core::future::Future for F {
|
||||
type Output = i32;
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
|
||||
}
|
||||
async fn foo() -> i$032 {
|
||||
if true {
|
||||
if false {
|
||||
1.await
|
||||
F(1).await
|
||||
} else {
|
||||
2.await
|
||||
F(2).await
|
||||
}
|
||||
} else {
|
||||
24i32.await
|
||||
F(24i32).await
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct F(i32);
|
||||
impl core::future::Future for F {
|
||||
type Output = i32;
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
|
||||
}
|
||||
async fn foo() -> Option<i32> {
|
||||
if true {
|
||||
if false {
|
||||
Some(1.await)
|
||||
Some(F(1).await)
|
||||
} else {
|
||||
Some(2.await)
|
||||
Some(F(2).await)
|
||||
}
|
||||
} else {
|
||||
Some(24i32.await)
|
||||
Some(F(24i32).await)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
@ -1666,29 +1705,39 @@ fn foo() -> Result<i32, ${0:_}> {
|
||||
check_assist_by_label(
|
||||
wrap_return_type,
|
||||
r#"
|
||||
//- minicore: result
|
||||
//- minicore: result, future
|
||||
struct F(i32);
|
||||
impl core::future::Future for F {
|
||||
type Output = i32;
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
|
||||
}
|
||||
async fn foo() -> i$032 {
|
||||
if true {
|
||||
if false {
|
||||
1.await
|
||||
F(1).await
|
||||
} else {
|
||||
2.await
|
||||
F(2).await
|
||||
}
|
||||
} else {
|
||||
24i32.await
|
||||
F(24i32).await
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct F(i32);
|
||||
impl core::future::Future for F {
|
||||
type Output = i32;
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 }
|
||||
}
|
||||
async fn foo() -> Result<i32, ${0:_}> {
|
||||
if true {
|
||||
if false {
|
||||
Ok(1.await)
|
||||
Ok(F(1).await)
|
||||
} else {
|
||||
Ok(2.await)
|
||||
Ok(F(2).await)
|
||||
}
|
||||
} else {
|
||||
Ok(24i32.await)
|
||||
Ok(F(24i32).await)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
@ -2455,6 +2504,56 @@ type Result<T, const N: usize> = core::result::Result<Foo<T>, Bar<N>>;
|
||||
|
||||
fn foo() -> Result<i32, ${0:_}> {
|
||||
Ok(0)
|
||||
}
|
||||
"#,
|
||||
WrapperKind::Result.label(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn already_wrapped() {
|
||||
check_assist_by_label(
|
||||
wrap_return_type,
|
||||
r#"
|
||||
//- minicore: option
|
||||
fn foo() -> i32$0 {
|
||||
if false {
|
||||
0
|
||||
} else {
|
||||
Some(1)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn foo() -> Option<i32> {
|
||||
if false {
|
||||
Some(0)
|
||||
} else {
|
||||
Some(1)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
WrapperKind::Option.label(),
|
||||
);
|
||||
check_assist_by_label(
|
||||
wrap_return_type,
|
||||
r#"
|
||||
//- minicore: result
|
||||
fn foo() -> i32$0 {
|
||||
if false {
|
||||
0
|
||||
} else {
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn foo() -> Result<i32, ${0:_}> {
|
||||
if false {
|
||||
Ok(0)
|
||||
} else {
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
"#,
|
||||
WrapperKind::Result.label(),
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -195,5 +195,5 @@ fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String
|
||||
matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE);
|
||||
let leading = if has_leading_comma { "" } else { ", " };
|
||||
|
||||
Some((move |label: &_| (format!("{leading}{label}{trailing}")), param.text_range()))
|
||||
Some((move |label: &_| format!("{leading}{label}{trailing}"), param.text_range()))
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use std::iter;
|
||||
use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
|
||||
use ide_db::{RootDatabase, active_parameter::ActiveParameter};
|
||||
use itertools::Either;
|
||||
use stdx::always;
|
||||
use syntax::{
|
||||
AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
|
||||
T, TextRange, TextSize,
|
||||
@ -869,8 +870,15 @@ fn classify_name_ref<'db>(
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
|
||||
if receiver_is_ambiguous_float_literal {
|
||||
// `123.|` is parsed as a float but should actually be an integer.
|
||||
always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
|
||||
receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
|
||||
}
|
||||
|
||||
let kind = NameRefKind::DotAccess(DotAccess {
|
||||
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
|
||||
receiver_ty,
|
||||
kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
|
||||
receiver,
|
||||
ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) }
|
||||
|
@ -2241,3 +2241,37 @@ fn main() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ambiguous_float_literal() {
|
||||
check(
|
||||
r#"
|
||||
#![rustc_coherence_is_core]
|
||||
|
||||
impl i32 {
|
||||
pub fn int_method(self) {}
|
||||
}
|
||||
impl f64 {
|
||||
pub fn float_method(self) {}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
1.$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me int_method() fn(self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn const const {}
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn deref *expr
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn return return expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -550,3 +550,30 @@ fn inside_extern_blocks() {
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tokens_from_macro() {
|
||||
check_edit(
|
||||
"fn as_ref",
|
||||
r#"
|
||||
//- proc_macros: identity
|
||||
//- minicore: as_ref
|
||||
struct Foo;
|
||||
|
||||
#[proc_macros::identity]
|
||||
impl<'a> AsRef<&'a i32> for Foo {
|
||||
$0
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Foo;
|
||||
|
||||
#[proc_macros::identity]
|
||||
impl<'a> AsRef<&'a i32> for Foo {
|
||||
fn as_ref(&self) -> &&'a i32 {
|
||||
$0
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -429,18 +429,18 @@ trait Tr<T> {
|
||||
impl Tr<$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
en Enum Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
sp Self dyn Tr<{unknown}> + 'static
|
||||
st Record Record
|
||||
st S S
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
sp Self dyn Tr<{unknown}>
|
||||
st Record Record
|
||||
st S S
|
||||
st Tuple Tuple
|
||||
st Unit Unit
|
||||
tt Tr
|
||||
tt Trait
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
un Union Union
|
||||
bt u32 u32
|
||||
kw crate::
|
||||
kw self::
|
||||
"#]],
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
use crate::helpers::mod_path_to_ast;
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope};
|
||||
use hir::{
|
||||
AsAssocItem, HirDisplay, HirFileId, ImportPathConfig, ModuleDef, SemanticsScope,
|
||||
prettify_macro_expansion,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::Edition;
|
||||
@ -136,6 +139,25 @@ impl<'a> PathTransform<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
|
||||
match self.target_scope.file_id() {
|
||||
HirFileId::FileId(_) => node,
|
||||
HirFileId::MacroFile(file_id) => {
|
||||
let db = self.target_scope.db;
|
||||
prettify_macro_expansion(
|
||||
db,
|
||||
node,
|
||||
&db.expansion_span_map(file_id),
|
||||
self.target_scope.module().krate().into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prettify_target_ast<N: AstNode>(&self, node: N) -> N {
|
||||
N::cast(self.prettify_target_node(node.syntax().clone())).unwrap()
|
||||
}
|
||||
|
||||
fn build_ctx(&self) -> Ctx<'a> {
|
||||
let db = self.source_scope.db;
|
||||
let target_module = self.target_scope.module();
|
||||
@ -163,7 +185,7 @@ impl<'a> PathTransform<'a> {
|
||||
.for_each(|(k, v)| match (k.split(db), v) {
|
||||
(Either::Right(k), Some(TypeOrConst::Either(v))) => {
|
||||
if let Some(ty) = v.ty() {
|
||||
type_substs.insert(k, ty);
|
||||
type_substs.insert(k, self.prettify_target_ast(ty));
|
||||
}
|
||||
}
|
||||
(Either::Right(k), None) => {
|
||||
@ -178,7 +200,7 @@ impl<'a> PathTransform<'a> {
|
||||
}
|
||||
(Either::Left(k), Some(TypeOrConst::Either(v))) => {
|
||||
if let Some(ty) = v.ty() {
|
||||
const_substs.insert(k, ty.syntax().clone());
|
||||
const_substs.insert(k, self.prettify_target_node(ty.syntax().clone()));
|
||||
}
|
||||
}
|
||||
(Either::Left(k), Some(TypeOrConst::Const(v))) => {
|
||||
@ -189,7 +211,7 @@ impl<'a> PathTransform<'a> {
|
||||
// and sometimes require slight modifications; see
|
||||
// https://doc.rust-lang.org/reference/statements.html#expression-statements
|
||||
// (default values in curly brackets can cause the same problem)
|
||||
const_substs.insert(k, expr.syntax().clone());
|
||||
const_substs.insert(k, self.prettify_target_node(expr.syntax().clone()));
|
||||
}
|
||||
}
|
||||
(Either::Left(k), None) => {
|
||||
@ -204,6 +226,7 @@ impl<'a> PathTransform<'a> {
|
||||
}
|
||||
_ => (), // ignore mismatching params
|
||||
});
|
||||
// No need to prettify lifetimes, there's nothing to prettify.
|
||||
let lifetime_substs: FxHashMap<_, _> = self
|
||||
.generic_def
|
||||
.into_iter()
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -1171,7 +1171,7 @@ trait B {}
|
||||
|
||||
fn test(a: &dyn A) -> &dyn B {
|
||||
a
|
||||
//^ error: expected &(dyn B + 'static), found &(dyn A + 'static)
|
||||
//^ error: expected &dyn B, found &dyn A
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
cov-mark = "2.0.0"
|
||||
|
@ -2,7 +2,7 @@ use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
|
||||
use syntax::{
|
||||
Direction, NodeOrToken, SourceFile,
|
||||
SyntaxKind::{self, *},
|
||||
TextRange, TextSize,
|
||||
SyntaxNode, TextRange, TextSize,
|
||||
ast::{self, AstNode, AstToken},
|
||||
match_ast,
|
||||
};
|
||||
@ -16,16 +16,21 @@ const REGION_END: &str = "// endregion";
|
||||
pub enum FoldKind {
|
||||
Comment,
|
||||
Imports,
|
||||
Mods,
|
||||
Region,
|
||||
Block,
|
||||
ArgList,
|
||||
Region,
|
||||
Consts,
|
||||
Statics,
|
||||
Array,
|
||||
WhereClause,
|
||||
ReturnType,
|
||||
MatchArm,
|
||||
// region: item runs
|
||||
Modules,
|
||||
Consts,
|
||||
Statics,
|
||||
TypeAliases,
|
||||
TraitAliases,
|
||||
ExternCrates,
|
||||
// endregion: item runs
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -41,10 +46,7 @@ pub struct Fold {
|
||||
pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
|
||||
let mut res = vec![];
|
||||
let mut visited_comments = FxHashSet::default();
|
||||
let mut visited_imports = FxHashSet::default();
|
||||
let mut visited_mods = FxHashSet::default();
|
||||
let mut visited_consts = FxHashSet::default();
|
||||
let mut visited_statics = FxHashSet::default();
|
||||
let mut visited_nodes = FxHashSet::default();
|
||||
|
||||
// regions can be nested, here is a LIFO buffer
|
||||
let mut region_starts: Vec<TextSize> = vec![];
|
||||
@ -93,30 +95,40 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
|
||||
if module.item_list().is_none() {
|
||||
if let Some(range) = contiguous_range_for_item_group(
|
||||
module,
|
||||
&mut visited_mods,
|
||||
&mut visited_nodes,
|
||||
) {
|
||||
res.push(Fold { range, kind: FoldKind::Mods })
|
||||
res.push(Fold { range, kind: FoldKind::Modules })
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::Use(use_) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_imports) {
|
||||
if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::Imports })
|
||||
}
|
||||
},
|
||||
ast::Const(konst) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_consts) {
|
||||
if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::Consts })
|
||||
}
|
||||
},
|
||||
ast::Static(statik) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_statics) {
|
||||
if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::Statics })
|
||||
}
|
||||
},
|
||||
ast::WhereClause(where_clause) => {
|
||||
if let Some(range) = fold_range_for_where_clause(where_clause) {
|
||||
res.push(Fold { range, kind: FoldKind::WhereClause })
|
||||
ast::TypeAlias(alias) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::TypeAliases })
|
||||
}
|
||||
},
|
||||
ast::TraitAlias(alias) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::TraitAliases })
|
||||
}
|
||||
},
|
||||
ast::ExternCrate(extern_crate) => {
|
||||
if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) {
|
||||
res.push(Fold { range, kind: FoldKind::ExternCrates })
|
||||
}
|
||||
},
|
||||
ast::MatchArm(match_arm) => {
|
||||
@ -137,9 +149,10 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
|
||||
fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
|
||||
match kind {
|
||||
COMMENT => Some(FoldKind::Comment),
|
||||
ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
|
||||
ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
|
||||
ARRAY_EXPR => Some(FoldKind::Array),
|
||||
RET_TYPE => Some(FoldKind::ReturnType),
|
||||
WHERE_CLAUSE => Some(FoldKind::WhereClause),
|
||||
ASSOC_ITEM_LIST
|
||||
| RECORD_FIELD_LIST
|
||||
| RECORD_PAT_FIELD_LIST
|
||||
@ -155,11 +168,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
|
||||
}
|
||||
}
|
||||
|
||||
fn contiguous_range_for_item_group<N>(first: N, visited: &mut FxHashSet<N>) -> Option<TextRange>
|
||||
fn contiguous_range_for_item_group<N>(
|
||||
first: N,
|
||||
visited: &mut FxHashSet<SyntaxNode>,
|
||||
) -> Option<TextRange>
|
||||
where
|
||||
N: ast::HasVisibility + Clone + Hash + Eq,
|
||||
{
|
||||
if !visited.insert(first.clone()) {
|
||||
if !visited.insert(first.syntax().clone()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -183,7 +199,7 @@ where
|
||||
if let Some(next) = N::cast(node) {
|
||||
let next_vis = next.visibility();
|
||||
if eq_visibility(next_vis.clone(), last_vis) {
|
||||
visited.insert(next.clone());
|
||||
visited.insert(next.syntax().clone());
|
||||
last_vis = next_vis;
|
||||
last = next;
|
||||
continue;
|
||||
@ -259,18 +275,6 @@ fn contiguous_range_for_comment(
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option<TextRange> {
|
||||
let first_where_pred = where_clause.predicates().next();
|
||||
let last_where_pred = where_clause.predicates().last();
|
||||
|
||||
if first_where_pred != last_where_pred {
|
||||
let start = where_clause.where_token()?.text_range().end();
|
||||
let end = where_clause.syntax().text_range().end();
|
||||
return Some(TextRange::new(start, end));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> {
|
||||
if fold_kind(match_arm.expr()?.syntax().kind()).is_some() {
|
||||
None
|
||||
@ -307,16 +311,19 @@ mod tests {
|
||||
let kind = match fold.kind {
|
||||
FoldKind::Comment => "comment",
|
||||
FoldKind::Imports => "imports",
|
||||
FoldKind::Mods => "mods",
|
||||
FoldKind::Modules => "mods",
|
||||
FoldKind::Block => "block",
|
||||
FoldKind::ArgList => "arglist",
|
||||
FoldKind::Region => "region",
|
||||
FoldKind::Consts => "consts",
|
||||
FoldKind::Statics => "statics",
|
||||
FoldKind::TypeAliases => "typealiases",
|
||||
FoldKind::Array => "array",
|
||||
FoldKind::WhereClause => "whereclause",
|
||||
FoldKind::ReturnType => "returntype",
|
||||
FoldKind::MatchArm => "matcharm",
|
||||
FoldKind::TraitAliases => "traitaliases",
|
||||
FoldKind::ExternCrates => "externcrates",
|
||||
};
|
||||
assert_eq!(kind, &attr.unwrap());
|
||||
}
|
||||
@ -594,19 +601,18 @@ static SECOND_STATIC: &str = "second";</fold>
|
||||
|
||||
#[test]
|
||||
fn fold_where_clause() {
|
||||
// fold multi-line and don't fold single line.
|
||||
check(
|
||||
r#"
|
||||
fn foo()
|
||||
where<fold whereclause>
|
||||
<fold whereclause>where
|
||||
A: Foo,
|
||||
B: Foo,
|
||||
C: Foo,
|
||||
D: Foo,</fold> {}
|
||||
|
||||
fn bar()
|
||||
where
|
||||
A: Bar, {}
|
||||
<fold whereclause>where
|
||||
A: Bar,</fold> {}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
@ -621,6 +627,18 @@ fn foo()<fold returntype>-> (
|
||||
)</fold> { (true, true) }
|
||||
|
||||
fn bar() -> (bool, bool) { (true, true) }
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fold_generics() {
|
||||
check(
|
||||
r#"
|
||||
type Foo<T, U> = foo<fold arglist><
|
||||
T,
|
||||
U,
|
||||
></fold>;
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
@ -291,13 +291,14 @@ fn handle_control_flow_keywords(
|
||||
token: &SyntaxToken,
|
||||
) -> Option<Vec<NavigationTarget>> {
|
||||
match token.kind() {
|
||||
// For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self,
|
||||
// For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self,
|
||||
// so that VSCode will find the references when using `ctrl + click`
|
||||
T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),
|
||||
T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),
|
||||
T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
|
||||
nav_for_break_points(sema, token)
|
||||
}
|
||||
T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -407,6 +408,91 @@ fn nav_for_exit_points(
|
||||
Some(navs)
|
||||
}
|
||||
|
||||
pub(crate) fn find_branch_root(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: &SyntaxToken,
|
||||
) -> Vec<SyntaxNode> {
|
||||
let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {
|
||||
sema.descend_into_macros(token.clone())
|
||||
.into_iter()
|
||||
.filter_map(|token| node_filter(token.parent()?))
|
||||
.collect_vec()
|
||||
};
|
||||
|
||||
match token.kind() {
|
||||
T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),
|
||||
T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),
|
||||
T![if] => find_nodes(|node| {
|
||||
let if_expr = ast::IfExpr::cast(node)?;
|
||||
|
||||
let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {
|
||||
let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;
|
||||
let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {
|
||||
return None;
|
||||
};
|
||||
|
||||
(else_branch.syntax() == if_expr.syntax()).then_some(parent_if)
|
||||
})
|
||||
.last()?;
|
||||
|
||||
Some(root_if.syntax().clone())
|
||||
}),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn nav_for_branch_exit_points(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: &SyntaxToken,
|
||||
) -> Option<Vec<NavigationTarget>> {
|
||||
let db = sema.db;
|
||||
|
||||
let navs = match token.kind() {
|
||||
T![match] => find_branch_root(sema, token)
|
||||
.into_iter()
|
||||
.filter_map(|node| {
|
||||
let file_id = sema.hir_file_for(&node);
|
||||
let match_expr = ast::MatchExpr::cast(node)?;
|
||||
let focus_range = match_expr.match_token()?.text_range();
|
||||
let match_expr_in_file = InFile::new(file_id, match_expr.into());
|
||||
Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
|
||||
})
|
||||
.flatten()
|
||||
.collect_vec(),
|
||||
|
||||
T![=>] => find_branch_root(sema, token)
|
||||
.into_iter()
|
||||
.filter_map(|node| {
|
||||
let match_arm = ast::MatchArm::cast(node)?;
|
||||
let match_expr = sema
|
||||
.ancestors_with_macros(match_arm.syntax().clone())
|
||||
.find_map(ast::MatchExpr::cast)?;
|
||||
let file_id = sema.hir_file_for(match_expr.syntax());
|
||||
let focus_range = match_arm.fat_arrow_token()?.text_range();
|
||||
let match_expr_in_file = InFile::new(file_id, match_expr.into());
|
||||
Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
|
||||
})
|
||||
.flatten()
|
||||
.collect_vec(),
|
||||
|
||||
T![if] => find_branch_root(sema, token)
|
||||
.into_iter()
|
||||
.filter_map(|node| {
|
||||
let file_id = sema.hir_file_for(&node);
|
||||
let if_expr = ast::IfExpr::cast(node)?;
|
||||
let focus_range = if_expr.if_token()?.text_range();
|
||||
let if_expr_in_file = InFile::new(file_id, if_expr.into());
|
||||
Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))
|
||||
})
|
||||
.flatten()
|
||||
.collect_vec(),
|
||||
|
||||
_ => return Some(Vec::new()),
|
||||
};
|
||||
|
||||
Some(navs)
|
||||
}
|
||||
|
||||
pub(crate) fn find_loops(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: &SyntaxToken,
|
||||
@ -3614,4 +3700,155 @@ fn foo() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_match_keyword() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match$0 0 {
|
||||
// ^^^^^
|
||||
0 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_match_arm_fat_arrow() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match 0 {
|
||||
0 =>$0 {},
|
||||
// ^^
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_if_keyword() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
if$0 true {
|
||||
// ^^
|
||||
()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_match_nested_in_if() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
match$0 0 {
|
||||
// ^^^^^
|
||||
0 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_multiple_match_expressions() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match 0 {
|
||||
0 => {},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
match$0 1 {
|
||||
// ^^^^^
|
||||
1 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_nested_match_expressions() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match 0 {
|
||||
0 => match$0 1 {
|
||||
// ^^^^^
|
||||
1 => {},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_if_else_chains() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
// ^^
|
||||
()
|
||||
} else if$0 false {
|
||||
()
|
||||
} else {
|
||||
()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_match_with_guards() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match 42 {
|
||||
x if x > 0 =>$0 {},
|
||||
// ^^
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_def_for_match_with_macro_arm() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! arm {
|
||||
() => { 0 => {} };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match$0 0 {
|
||||
// ^^^^^
|
||||
arm!(),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -70,11 +70,10 @@ pub(crate) fn goto_type_definition(
|
||||
}
|
||||
|
||||
let range = token.text_range();
|
||||
sema.descend_into_macros_no_opaque(token,false)
|
||||
sema.descend_into_macros_no_opaque(token, false)
|
||||
.into_iter()
|
||||
.filter_map(|token| {
|
||||
sema
|
||||
.token_ancestors_with_macros(token.value)
|
||||
sema.token_ancestors_with_macros(token.value)
|
||||
// When `token` is within a macro call, we can't determine its type. Don't continue
|
||||
// this traversal because otherwise we'll end up returning the type of *that* macro
|
||||
// call, which is not what we want in general.
|
||||
@ -103,7 +102,6 @@ pub(crate) fn goto_type_definition(
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
|
||||
Some(ty)
|
||||
})
|
||||
})
|
||||
|
@ -37,8 +37,11 @@ pub struct HighlightRelatedConfig {
|
||||
pub break_points: bool,
|
||||
pub closure_captures: bool,
|
||||
pub yield_points: bool,
|
||||
pub branch_exit_points: bool,
|
||||
}
|
||||
|
||||
type HighlightMap = FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>;
|
||||
|
||||
// Feature: Highlight Related
|
||||
//
|
||||
// Highlights constructs related to the thing under the cursor:
|
||||
@ -64,7 +67,7 @@ pub(crate) fn highlight_related(
|
||||
|
||||
let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
|
||||
T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
|
||||
T![->] => 4,
|
||||
T![->] | T![=>] => 4,
|
||||
kind if kind.is_keyword(file_id.edition(sema.db)) => 3,
|
||||
IDENT | INT_NUMBER => 2,
|
||||
T![|] => 1,
|
||||
@ -78,6 +81,9 @@ pub(crate) fn highlight_related(
|
||||
T![fn] | T![return] | T![->] if config.exit_points => {
|
||||
highlight_exit_points(sema, token).remove(&file_id)
|
||||
}
|
||||
T![match] | T![=>] | T![if] if config.branch_exit_points => {
|
||||
highlight_branch_exit_points(sema, token).remove(&file_id)
|
||||
}
|
||||
T![await] | T![async] if config.yield_points => {
|
||||
highlight_yield_points(sema, token).remove(&file_id)
|
||||
}
|
||||
@ -300,11 +306,93 @@ fn highlight_references(
|
||||
if res.is_empty() { None } else { Some(res.into_iter().collect()) }
|
||||
}
|
||||
|
||||
pub(crate) fn highlight_branch_exit_points(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: SyntaxToken,
|
||||
) -> FxHashMap<EditionedFileId, Vec<HighlightedRange>> {
|
||||
let mut highlights: HighlightMap = FxHashMap::default();
|
||||
|
||||
let push_to_highlights = |file_id, range, highlights: &mut HighlightMap| {
|
||||
if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) {
|
||||
let hrange = HighlightedRange { category: ReferenceCategory::empty(), range };
|
||||
highlights.entry(file_id).or_default().insert(hrange);
|
||||
}
|
||||
};
|
||||
|
||||
let push_tail_expr = |tail: Option<ast::Expr>, highlights: &mut HighlightMap| {
|
||||
let Some(tail) = tail else {
|
||||
return;
|
||||
};
|
||||
|
||||
for_each_tail_expr(&tail, &mut |tail| {
|
||||
let file_id = sema.hir_file_for(tail.syntax());
|
||||
let range = tail.syntax().text_range();
|
||||
push_to_highlights(file_id, Some(range), highlights);
|
||||
});
|
||||
};
|
||||
|
||||
let nodes = goto_definition::find_branch_root(sema, &token).into_iter();
|
||||
match token.kind() {
|
||||
T![match] => {
|
||||
for match_expr in nodes.filter_map(ast::MatchExpr::cast) {
|
||||
let file_id = sema.hir_file_for(match_expr.syntax());
|
||||
let range = match_expr.match_token().map(|token| token.text_range());
|
||||
push_to_highlights(file_id, range, &mut highlights);
|
||||
|
||||
let Some(arm_list) = match_expr.match_arm_list() else {
|
||||
continue;
|
||||
};
|
||||
for arm in arm_list.arms() {
|
||||
push_tail_expr(arm.expr(), &mut highlights);
|
||||
}
|
||||
}
|
||||
}
|
||||
T![=>] => {
|
||||
for arm in nodes.filter_map(ast::MatchArm::cast) {
|
||||
let file_id = sema.hir_file_for(arm.syntax());
|
||||
let range = arm.fat_arrow_token().map(|token| token.text_range());
|
||||
push_to_highlights(file_id, range, &mut highlights);
|
||||
|
||||
push_tail_expr(arm.expr(), &mut highlights);
|
||||
}
|
||||
}
|
||||
T![if] => {
|
||||
for mut if_to_process in nodes.map(ast::IfExpr::cast) {
|
||||
while let Some(cur_if) = if_to_process.take() {
|
||||
let file_id = sema.hir_file_for(cur_if.syntax());
|
||||
|
||||
let if_kw_range = cur_if.if_token().map(|token| token.text_range());
|
||||
push_to_highlights(file_id, if_kw_range, &mut highlights);
|
||||
|
||||
if let Some(then_block) = cur_if.then_branch() {
|
||||
push_tail_expr(Some(then_block.into()), &mut highlights);
|
||||
}
|
||||
|
||||
match cur_if.else_branch() {
|
||||
Some(ast::ElseBranch::Block(else_block)) => {
|
||||
push_tail_expr(Some(else_block.into()), &mut highlights);
|
||||
if_to_process = None;
|
||||
}
|
||||
Some(ast::ElseBranch::IfExpr(nested_if)) => if_to_process = Some(nested_if),
|
||||
None => if_to_process = None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
highlights
|
||||
.into_iter()
|
||||
.map(|(file_id, ranges)| (file_id, ranges.into_iter().collect()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn hl_exit_points(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
def_token: Option<SyntaxToken>,
|
||||
body: ast::Expr,
|
||||
) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
|
||||
) -> Option<HighlightMap> {
|
||||
let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
|
||||
|
||||
let mut push_to_highlights = |file_id, range| {
|
||||
@ -411,7 +499,7 @@ pub(crate) fn highlight_break_points(
|
||||
loop_token: Option<SyntaxToken>,
|
||||
label: Option<ast::Label>,
|
||||
expr: ast::Expr,
|
||||
) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
|
||||
) -> Option<HighlightMap> {
|
||||
let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
|
||||
|
||||
let mut push_to_highlights = |file_id, range| {
|
||||
@ -504,7 +592,7 @@ pub(crate) fn highlight_yield_points(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
async_token: Option<SyntaxToken>,
|
||||
body: Option<ast::Expr>,
|
||||
) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> {
|
||||
) -> Option<HighlightMap> {
|
||||
let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default();
|
||||
|
||||
let mut push_to_highlights = |file_id, range| {
|
||||
@ -597,10 +685,7 @@ fn original_frange(
|
||||
InFile::new(file_id, text_range?).original_node_file_range_opt(db).map(|(frange, _)| frange)
|
||||
}
|
||||
|
||||
fn merge_map(
|
||||
res: &mut FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>,
|
||||
new: Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>>,
|
||||
) {
|
||||
fn merge_map(res: &mut HighlightMap, new: Option<HighlightMap>) {
|
||||
let Some(new) = new else {
|
||||
return;
|
||||
};
|
||||
@ -750,6 +835,7 @@ mod tests {
|
||||
references: true,
|
||||
closure_captures: true,
|
||||
yield_points: true,
|
||||
branch_exit_points: true,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
@ -2134,6 +2220,62 @@ fn main() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_match() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match$0 0 {
|
||||
// ^^^^^
|
||||
0 => match 1 {
|
||||
1 => 2,
|
||||
// ^
|
||||
_ => 3,
|
||||
// ^
|
||||
},
|
||||
_ => 4,
|
||||
// ^
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_arm_highlight() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match 0 {
|
||||
0 =>$0 {
|
||||
// ^^
|
||||
let x = 1;
|
||||
x
|
||||
// ^
|
||||
}
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_branches_when_disabled() {
|
||||
let config = HighlightRelatedConfig { branch_exit_points: false, ..ENABLED_CONFIG };
|
||||
check_with_config(
|
||||
r#"
|
||||
fn main() {
|
||||
match$0 0 {
|
||||
0 => 1,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
"#,
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asm() {
|
||||
check(
|
||||
@ -2164,6 +2306,200 @@ pub unsafe fn bootstrap() -> ! {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_arms_highlight() {
|
||||
check(
|
||||
r#"
|
||||
fn calculate(n: i32) -> i32 { n * 2 }
|
||||
|
||||
fn main() {
|
||||
match$0 Some(1) {
|
||||
// ^^^^^
|
||||
Some(x) => match x {
|
||||
0 => { let y = x; y },
|
||||
// ^
|
||||
1 => calculate(x),
|
||||
//^^^^^^^^^^^^
|
||||
_ => (|| 6)(),
|
||||
// ^^^^^^^^
|
||||
},
|
||||
None => loop {
|
||||
break 5;
|
||||
// ^^^^^^^
|
||||
},
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_in_macro_highlight() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! M {
|
||||
($e:expr) => { $e };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
M!{
|
||||
match$0 Some(1) {
|
||||
// ^^^^^
|
||||
Some(x) => x,
|
||||
// ^
|
||||
None => 0,
|
||||
// ^
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_in_macro_highlight_2() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( $( $path:ident )::+ ($it:pat) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match_ast! {
|
||||
match$0 Some(1) {
|
||||
Some(x) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_if_else() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
if$0 true {
|
||||
// ^^
|
||||
if false {
|
||||
1
|
||||
// ^
|
||||
} else {
|
||||
2
|
||||
// ^
|
||||
}
|
||||
} else {
|
||||
3
|
||||
// ^
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_if_highlight() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
if$0 true {
|
||||
// ^^
|
||||
1
|
||||
// ^
|
||||
} else if false {
|
||||
// ^^
|
||||
2
|
||||
// ^
|
||||
} else {
|
||||
3
|
||||
// ^
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_if_branches() {
|
||||
check(
|
||||
r#"
|
||||
fn calculate(n: i32) -> i32 { n * 2 }
|
||||
|
||||
fn main() {
|
||||
if$0 true {
|
||||
// ^^
|
||||
let x = 5;
|
||||
calculate(x)
|
||||
// ^^^^^^^^^^^^
|
||||
} else if false {
|
||||
// ^^
|
||||
(|| 10)()
|
||||
// ^^^^^^^^^
|
||||
} else {
|
||||
loop {
|
||||
break 15;
|
||||
// ^^^^^^^^
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_in_macro_highlight() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! M {
|
||||
($e:expr) => { $e };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
M!{
|
||||
if$0 true {
|
||||
// ^^
|
||||
5
|
||||
// ^
|
||||
} else {
|
||||
10
|
||||
// ^^
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_in_macro() {
|
||||
// We should not highlight the outer `match` expression.
|
||||
check(
|
||||
r#"
|
||||
macro_rules! M {
|
||||
(match) => { 1 };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match Some(1) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
M!(match$0)
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn labeled_block_tail_expr() {
|
||||
check(
|
||||
|
@ -380,9 +380,9 @@ fn main() {
|
||||
let foo = foo3();
|
||||
// ^^^ impl Fn(f64, f64) -> u32
|
||||
let foo = foo4();
|
||||
// ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static)
|
||||
// ^^^ &'static dyn Fn(f64, f64) -> u32
|
||||
let foo = foo5();
|
||||
// ^^^ &'static (dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 + 'static)
|
||||
// ^^^ &'static dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
|
||||
let foo = foo6();
|
||||
// ^^^ impl Fn(f64, f64) -> u32
|
||||
let foo = foo7();
|
||||
@ -413,7 +413,7 @@ fn main() {
|
||||
let foo = foo3();
|
||||
// ^^^ impl Fn(f64, f64) -> u32
|
||||
let foo = foo4();
|
||||
// ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static)
|
||||
// ^^^ &'static dyn Fn(f64, f64) -> u32
|
||||
let foo = foo5();
|
||||
let foo = foo6();
|
||||
let foo = foo7();
|
||||
|
@ -143,7 +143,7 @@ fn foo<T>() {}
|
||||
file_id: FileId(
|
||||
1,
|
||||
),
|
||||
range: 135..140,
|
||||
range: 446..451,
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -193,7 +193,7 @@ impl Tr for () {
|
||||
//^ impl Tr for ()
|
||||
impl dyn Tr {
|
||||
}
|
||||
//^ impl dyn Tr + 'static
|
||||
//^ impl dyn Tr
|
||||
|
||||
static S0: () = 0;
|
||||
static S1: () = {};
|
||||
|
@ -21,6 +21,7 @@ use hir::{PathResolution, Semantics};
|
||||
use ide_db::{
|
||||
FileId, RootDatabase,
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
helpers::pick_best_token,
|
||||
search::{ReferenceCategory, SearchScope, UsageSearchResult},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
@ -397,7 +398,11 @@ fn handle_control_flow_keywords(
|
||||
.attach_first_edition(file_id)
|
||||
.map(|it| it.edition(sema.db))
|
||||
.unwrap_or(Edition::CURRENT);
|
||||
let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?;
|
||||
let token = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind {
|
||||
_ if kind.is_keyword(edition) => 4,
|
||||
T![=>] => 3,
|
||||
_ => 1,
|
||||
})?;
|
||||
|
||||
let references = match token.kind() {
|
||||
T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token),
|
||||
@ -408,6 +413,7 @@ fn handle_control_flow_keywords(
|
||||
T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
|
||||
highlight_related::highlight_break_points(sema, token)
|
||||
}
|
||||
T![if] | T![=>] | T![match] => highlight_related::highlight_branch_exit_points(sema, token),
|
||||
_ => return None,
|
||||
}
|
||||
.into_iter()
|
||||
@ -1344,6 +1350,159 @@ impl Foo {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_if_branches() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
let x = if$0 true {
|
||||
1
|
||||
} else if false {
|
||||
2
|
||||
} else {
|
||||
3
|
||||
};
|
||||
|
||||
println!("x: {}", x);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 24..26
|
||||
FileId(0) 42..43
|
||||
FileId(0) 55..57
|
||||
FileId(0) 74..75
|
||||
FileId(0) 97..98
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_match_branches() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
$0match Some(42) {
|
||||
Some(x) if x > 0 => println!("positive"),
|
||||
Some(0) => println!("zero"),
|
||||
Some(_) => println!("negative"),
|
||||
None => println!("none"),
|
||||
};
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 16..21
|
||||
FileId(0) 61..81
|
||||
FileId(0) 102..118
|
||||
FileId(0) 139..159
|
||||
FileId(0) 177..193
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_match_arm_arrow() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
match Some(42) {
|
||||
Some(x) if x > 0 $0=> println!("positive"),
|
||||
Some(0) => println!("zero"),
|
||||
Some(_) => println!("negative"),
|
||||
None => println!("none"),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 58..60
|
||||
FileId(0) 61..81
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_nested_branches() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
let x = $0if true {
|
||||
if false {
|
||||
1
|
||||
} else {
|
||||
match Some(42) {
|
||||
Some(_) => 2,
|
||||
None => 3,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
4
|
||||
};
|
||||
|
||||
println!("x: {}", x);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 24..26
|
||||
FileId(0) 65..66
|
||||
FileId(0) 140..141
|
||||
FileId(0) 167..168
|
||||
FileId(0) 215..216
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_match_with_complex_guards() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
let x = $0match (x, y) {
|
||||
(a, b) if a > b && a % 2 == 0 => 1,
|
||||
(a, b) if a < b || b % 2 == 1 => 2,
|
||||
(a, _) if a > 40 => 3,
|
||||
_ => 4,
|
||||
};
|
||||
|
||||
println!("x: {}", x);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 24..29
|
||||
FileId(0) 80..81
|
||||
FileId(0) 124..125
|
||||
FileId(0) 155..156
|
||||
FileId(0) 171..172
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_mixed_if_match_expressions() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
let x = $0if let Some(x) = Some(42) {
|
||||
1
|
||||
} else if let None = None {
|
||||
2
|
||||
} else {
|
||||
match 42 {
|
||||
0 => 3,
|
||||
_ => 4,
|
||||
}
|
||||
};
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 24..26
|
||||
FileId(0) 60..61
|
||||
FileId(0) 73..75
|
||||
FileId(0) 102..103
|
||||
FileId(0) 153..154
|
||||
FileId(0) 173..174
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
check_with_scope(ra_fixture, None, expect)
|
||||
}
|
||||
@ -2867,4 +3026,66 @@ const FOO$0: i32 = 0;
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_if_let_match_combined() {
|
||||
check(
|
||||
r#"
|
||||
enum MyEnum { A(i32), B(String), C }
|
||||
|
||||
fn main() {
|
||||
let val = MyEnum::A(42);
|
||||
|
||||
let x = $0if let MyEnum::A(x) = val {
|
||||
1
|
||||
} else if let MyEnum::B(s) = val {
|
||||
2
|
||||
} else {
|
||||
match val {
|
||||
MyEnum::C => 3,
|
||||
_ => 4,
|
||||
}
|
||||
};
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 92..94
|
||||
FileId(0) 128..129
|
||||
FileId(0) 141..143
|
||||
FileId(0) 177..178
|
||||
FileId(0) 237..238
|
||||
FileId(0) 257..258
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_highlight_nested_match_expressions() {
|
||||
check(
|
||||
r#"
|
||||
enum Outer { A(Inner), B }
|
||||
enum Inner { X, Y(i32) }
|
||||
|
||||
fn main() {
|
||||
let val = Outer::A(Inner::Y(42));
|
||||
|
||||
$0match val {
|
||||
Outer::A(inner) => match inner {
|
||||
Inner::X => println!("Inner::X"),
|
||||
Inner::Y(n) if n > 0 => println!("Inner::Y positive: {}", n),
|
||||
Inner::Y(_) => println!("Inner::Y non-positive"),
|
||||
},
|
||||
Outer::B => println!("Outer::B"),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
FileId(0) 108..113
|
||||
FileId(0) 185..205
|
||||
FileId(0) 243..279
|
||||
FileId(0) 308..341
|
||||
FileId(0) 374..394
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user