Auto merge of #127617 - lnicola:sync-from-ra, r=lnicola

Subtree update of `rust-analyzer`

r? `@ghost`
This commit is contained in:
bors 2024-07-16 10:54:30 +00:00
commit f5efae854c
275 changed files with 7403 additions and 4464 deletions

View file

@ -132,7 +132,7 @@ jobs:
run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
- name: Upload artifacts
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.target }}
path: ./dist
@ -177,7 +177,7 @@ jobs:
- run: rm -rf editors/code/server
- name: Upload artifacts
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
with:
name: dist-x86_64-unknown-linux-musl
path: ./dist
@ -206,39 +206,39 @@ jobs:
- run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- run: 'echo "HEAD_SHA: $HEAD_SHA"'
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-aarch64-apple-darwin
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-x86_64-apple-darwin
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-x86_64-unknown-linux-gnu
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-x86_64-unknown-linux-musl
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-aarch64-unknown-linux-gnu
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-arm-unknown-linux-gnueabihf
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-x86_64-pc-windows-msvc
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-i686-pc-windows-msvc
path: dist
- uses: actions/download-artifact@v1
- uses: actions/download-artifact@v4
with:
name: dist-aarch64-pc-windows-msvc
path: dist

85
Cargo.lock generated
View file

@ -167,9 +167,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chalk-derive"
version = "0.97.0"
version = "0.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92a0aedc4ac2adc5c0b7dc9ec38c5c816284ad28da6d4ecd01873b9683f54972"
checksum = "9426c8fd0fe61c3da880b801d3b510524df17843a8f9ec1f5b9cec24fb7412df"
dependencies = [
"proc-macro2",
"quote",
@ -179,9 +179,9 @@ dependencies = [
[[package]]
name = "chalk-ir"
version = "0.97.0"
version = "0.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119"
checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093"
dependencies = [
"bitflags 2.5.0",
"chalk-derive",
@ -189,9 +189,9 @@ dependencies = [
[[package]]
name = "chalk-recursive"
version = "0.97.0"
version = "0.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae4ba8ce5bd2e1b59f1f79495bc8704db09a8285e51cc5ddf01d9baee1bf447d"
checksum = "129dc03458f71cfb9c3cd621c9c68166a94e87b85b16ccd29af015d7ff9a1c61"
dependencies = [
"chalk-derive",
"chalk-ir",
@ -202,9 +202,9 @@ dependencies = [
[[package]]
name = "chalk-solve"
version = "0.97.0"
version = "0.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ec1b3b7f7b1ec38f099ef39c2bc3ea29335be1b8316d114baff46d96d131e9"
checksum = "d7e8a8c1e928f98cdf227b868416ef21dcd8cc3c61b347576d783713444d41c8"
dependencies = [
"chalk-derive",
"chalk-ir",
@ -221,11 +221,6 @@ name = "countme"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
dependencies = [
"dashmap",
"once_cell",
"rustc-hash",
]
[[package]]
name = "cov-mark"
@ -548,10 +543,10 @@ dependencies = [
"limit",
"mbe",
"once_cell",
"profile",
"ra-ap-rustc_abi",
"ra-ap-rustc_parse_format",
"rustc-hash",
"rustc_apfloat",
"smallvec",
"span",
"stdx",
@ -616,9 +611,10 @@ dependencies = [
"oorandom",
"project-model",
"ra-ap-rustc_abi",
"ra-ap-rustc_index 0.53.0",
"ra-ap-rustc_index",
"ra-ap-rustc_pattern_analysis",
"rustc-hash",
"rustc_apfloat",
"scoped-tls",
"smallvec",
"span",
@ -664,6 +660,7 @@ dependencies = [
"profile",
"pulldown-cmark",
"pulldown-cmark-to-cmark",
"rustc_apfloat",
"smallvec",
"span",
"stdx",
@ -809,7 +806,6 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
"serde",
]
[[package]]
@ -1046,6 +1042,7 @@ checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
name = "mbe"
version = "0.0.0"
dependencies = [
"arrayvec",
"cov-mark",
"parser",
"rustc-hash",
@ -1250,7 +1247,6 @@ dependencies = [
"expect-test",
"limit",
"ra-ap-rustc_lexer",
"sourcegen",
"stdx",
"tracing",
]
@ -1328,18 +1324,14 @@ dependencies = [
"base-db",
"indexmap",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap2",
"object 0.33.0",
"paths",
"rustc-hash",
"serde",
"serde_json",
"snap",
"span",
"stdx",
"text-size",
"tracing",
"triomphe",
"tt",
]
@ -1357,6 +1349,7 @@ dependencies = [
"proc-macro-api",
"proc-macro-test",
"ra-ap-rustc_lexer",
"snap",
"span",
"stdx",
"tt",
@ -1403,13 +1396,9 @@ name = "profile"
version = "0.0.0"
dependencies = [
"cfg-if",
"countme",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"once_cell",
"perf-event",
"tikv-jemalloc-ctl",
"tracing",
"windows-sys 0.52.0",
]
@ -1492,21 +1481,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46"
dependencies = [
"bitflags 2.5.0",
"ra-ap-rustc_index 0.53.0",
"ra-ap-rustc_index",
"tracing",
]
[[package]]
name = "ra-ap-rustc_index"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros 0.44.0",
"smallvec",
]
[[package]]
name = "ra-ap-rustc_index"
version = "0.53.0"
@ -1514,22 +1492,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros 0.53.0",
"ra-ap-rustc_index_macros",
"smallvec",
]
[[package]]
name = "ra-ap-rustc_index_macros"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8782aaf3a113837c533dfb1c45df91cd17e1fdd1d2f9a20c2e0d1976025c4f1f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "ra-ap-rustc_index_macros"
version = "0.53.0"
@ -1558,17 +1524,17 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135"
dependencies = [
"ra-ap-rustc_index 0.53.0",
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
]
[[package]]
name = "ra-ap-rustc_pattern_analysis"
version = "0.44.0"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334"
checksum = "34768e1faf88c31f2e9ad57b48318a52b507dafac0cddbf01b5d63bfc0b0a365"
dependencies = [
"ra-ap-rustc_index 0.44.0",
"ra-ap-rustc_index",
"rustc-hash",
"rustc_apfloat",
"smallvec",
@ -1685,7 +1651,6 @@ dependencies = [
"ide",
"ide-db",
"ide-ssr",
"indexmap",
"itertools",
"load-cargo",
"lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1708,7 +1673,6 @@ dependencies = [
"semver",
"serde",
"serde_json",
"sourcegen",
"stdx",
"syntax",
"test-fixture",
@ -1907,13 +1871,6 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b"
[[package]]
name = "sourcegen"
version = "0.0.0"
dependencies = [
"xshell",
]
[[package]]
name = "span"
version = "0.0.0"
@ -1985,6 +1942,7 @@ dependencies = [
"rayon",
"rowan",
"rustc-hash",
"rustc_apfloat",
"smol_str",
"stdx",
"test-utils",
@ -2251,6 +2209,7 @@ dependencies = [
name = "tt"
version = "0.0.0"
dependencies = [
"arrayvec",
"smol_str",
"stdx",
"text-size",

View file

@ -10,9 +10,7 @@ license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
[profile.dev]
# Disabling debug info speeds up builds a bunch,
# and we don't rely on it for debugging that much.
debug = 0
debug = 1
[profile.dev.package]
# These speed up local tests.
@ -89,10 +87,9 @@ ra-ap-rustc_lexer = { version = "0.53.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false }
ra-ap-rustc_index = { version = "0.53.0", default-features = false }
ra-ap-rustc_abi = { version = "0.53.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.53.0", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
sourcegen = { path = "./crates/sourcegen" }
test-fixture = { path = "./crates/test-fixture" }
test-utils = { path = "./crates/test-utils" }
@ -107,10 +104,10 @@ arrayvec = "0.7.4"
bitflags = "2.4.1"
cargo_metadata = "0.18.1"
camino = "1.1.6"
chalk-solve = { version = "0.97.0", default-features = false }
chalk-ir = "0.97.0"
chalk-recursive = { version = "0.97.0", default-features = false }
chalk-derive = "0.97.0"
chalk-solve = { version = "0.98.0", default-features = false }
chalk-ir = "0.98.0"
chalk-recursive = { version = "0.98.0", default-features = false }
chalk-derive = "0.98.0"
crossbeam-channel = "0.5.8"
dissimilar = "1.0.7"
dot = "0.1.4"
@ -122,6 +119,8 @@ hashbrown = { version = "0.14", features = [
indexmap = "2.1.0"
itertools = "0.12.0"
libc = "0.2.150"
libloading = "0.8.0"
memmap2 = "0.5.4"
nohash-hasher = "0.2.0"
oorandom = "11.1.3"
object = { version = "0.33.0", default-features = false, features = [
@ -145,6 +144,7 @@ smallvec = { version = "1.10.0", features = [
"const_generics",
] }
smol_str = "0.2.1"
snap = "1.1.0"
text-size = "1.1.1"
tracing = "0.1.40"
tracing-tree = "0.3.0"
@ -158,6 +158,7 @@ url = "2.3.1"
xshell = "0.2.5"
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
dashmap = { version = "=5.5.3", features = ["raw-api"] }

View file

@ -1,7 +1,5 @@
//! base_db defines basic database traits. The concrete DB is defined by ide.
#![warn(rust_2018_idioms, unused_lifetimes)]
mod change;
mod input;

View file

@ -1,7 +1,5 @@
//! cfg defines conditional compiling options, `cfg` attribute parser and evaluator
#![warn(rust_2018_idioms, unused_lifetimes)]
mod cfg_expr;
mod dnf;
#[cfg(test)]

View file

@ -6,8 +6,6 @@
// addition to `cargo check`. Either split it into 3 crates (one for test, one for check
// and one common utilities) or change its name and docs to reflect the current state.
#![warn(rust_2018_idioms, unused_lifetimes)]
use std::{fmt, io, process::Command, time::Duration};
use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
@ -428,6 +426,8 @@ impl FlycheckActor {
}
}
cmd.arg("--keep-going");
options.apply_on_command(&mut cmd);
(cmd, options.extra_args.clone())
}

View file

@ -28,6 +28,7 @@ tracing.workspace = true
smallvec.workspace = true
hashbrown.workspace = true
triomphe.workspace = true
rustc_apfloat = "0.2.0"
ra-ap-rustc_parse_format.workspace = true
ra-ap-rustc_abi.workspace = true
@ -37,7 +38,6 @@ stdx.workspace = true
intern.workspace = true
base-db.workspace = true
syntax.workspace = true
profile.workspace = true
hir-expand.workspace = true
mbe.workspace = true
cfg.workspace = true

View file

@ -15,8 +15,8 @@ use span::AstIdMap;
use stdx::never;
use syntax::{
ast::{
self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName,
RangeItem, SlicePatComponents,
self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,
HasLoopBody, HasName, RangeItem, SlicePatComponents,
},
AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
};

View file

@ -30,8 +30,10 @@ pub enum BuiltinUint {
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BuiltinFloat {
F16,
F32,
F64,
F128,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -65,8 +67,10 @@ impl BuiltinType {
(name![u64], BuiltinType::Uint(BuiltinUint::U64)),
(name![u128], BuiltinType::Uint(BuiltinUint::U128)),
(name![f16], BuiltinType::Float(BuiltinFloat::F16)),
(name![f32], BuiltinType::Float(BuiltinFloat::F32)),
(name![f64], BuiltinType::Float(BuiltinFloat::F64)),
(name![f128], BuiltinType::Float(BuiltinFloat::F128)),
];
pub fn by_name(name: &Name) -> Option<Self> {
@ -97,8 +101,10 @@ impl AsName for BuiltinType {
BuiltinUint::U128 => name![u128],
},
BuiltinType::Float(it) => match it {
BuiltinFloat::F16 => name![f16],
BuiltinFloat::F32 => name![f32],
BuiltinFloat::F64 => name![f64],
BuiltinFloat::F128 => name![f128],
},
}
}
@ -155,8 +161,10 @@ impl BuiltinUint {
impl BuiltinFloat {
pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> {
let res = match suffix {
"f16" => BuiltinFloat::F16,
"f32" => BuiltinFloat::F32,
"f64" => BuiltinFloat::F64,
"f128" => BuiltinFloat::F128,
_ => return None,
};
Some(res)
@ -192,8 +200,10 @@ impl fmt::Display for BuiltinUint {
impl fmt::Display for BuiltinFloat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
BuiltinFloat::F16 => "f16",
BuiltinFloat::F32 => "f32",
BuiltinFloat::F64 => "f64",
BuiltinFloat::F128 => "f128",
})
}
}

View file

@ -214,8 +214,8 @@ impl ChildBySource for GenericDefId {
}
let generic_params = db.generic_params(*self);
let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx);
let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx);
// For traits the first type index is `Self`, skip it.
if let GenericDefId::TraitId(_) = *self {

View file

@ -323,7 +323,7 @@ impl TraitAliasData {
pub struct ImplData {
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
pub items: Vec<AssocItemId>,
pub items: Box<[AssocItemId]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
@ -637,10 +637,6 @@ impl<'a> AssocItemCollector<'a> {
attr,
) {
Ok(ResolvedAttr::Macro(call_id)) => {
// If proc attribute macro expansion is disabled, skip expanding it here
if !self.db.expand_proc_attr_macros() {
continue 'attrs;
}
let loc = self.db.lookup_intern_macro_call(call_id);
if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind {
// If there's no expander for the proc macro (e.g. the

View file

@ -80,9 +80,11 @@ pub trait InternDatabase: SourceDatabase {
#[salsa::query_group(DefDatabaseStorage)]
pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> {
/// Whether to expand procedural macros during name resolution.
#[salsa::input]
fn expand_proc_attr_macros(&self) -> bool;
/// Computes an [`ItemTree`] for the given file or macro expansion.
#[salsa::invoke(ItemTree::file_item_tree_query)]
fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
@ -96,6 +98,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(DefMap::block_def_map_query)]
fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
fn macro_def(&self, m: MacroId) -> MacroDefId;
// region:data
@ -190,6 +193,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(Attrs::fields_attrs_query)]
fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
// should this really be a query?
#[salsa::invoke(crate::attr::fields_attrs_source_map)]
fn fields_attrs_source_map(
&self,

View file

@ -183,6 +183,8 @@ fn find_path_for_module(
let kind = if name_already_occupied_in_type_ns {
cov_mark::hit!(ambiguous_crate_start);
PathKind::Abs
} else if ctx.cfg.prefer_absolute {
PathKind::Abs
} else {
PathKind::Plain
};
@ -564,7 +566,13 @@ mod tests {
/// item the `path` refers to returns that same path when called from the
/// module the cursor is in.
#[track_caller]
fn check_found_path_(ra_fixture: &str, path: &str, prefer_prelude: bool, expect: Expect) {
fn check_found_path_(
ra_fixture: &str,
path: &str,
prefer_prelude: bool,
prefer_absolute: bool,
expect: Expect,
) {
let (db, pos) = TestDB::with_position(ra_fixture);
let module = db.module_at_position(pos);
let parsed_path_file =
@ -604,7 +612,7 @@ mod tests {
module,
prefix,
ignore_local_imports,
ImportPathConfig { prefer_no_std: false, prefer_prelude },
ImportPathConfig { prefer_no_std: false, prefer_prelude, prefer_absolute },
);
format_to!(
res,
@ -619,11 +627,15 @@ mod tests {
}
fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, false, expect);
check_found_path_(ra_fixture, path, false, false, expect);
}
fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, true, expect);
check_found_path_(ra_fixture, path, true, false, expect);
}
fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, false, true, expect);
}
#[test]
@ -870,6 +882,39 @@ pub mod ast {
);
}
#[test]
fn partially_imported_with_prefer_absolute() {
cov_mark::check!(partially_imported);
// Similar to partially_imported test case above, but with prefer_absolute enabled.
// Even if the actual imported item is in external crate, if the path to that item
// is starting from the imported name, then the path should not start from "::".
// i.e. The first line in the expected output should not start from "::".
check_found_path_absolute(
r#"
//- /main.rs crate:main deps:syntax
use syntax::ast;
$0
//- /lib.rs crate:syntax
pub mod ast {
pub enum ModuleItem {
A, B, C,
}
}
"#,
"syntax::ast::ModuleItem",
expect![[r#"
Plain (imports ): ast::ModuleItem
Plain (imports ): ::syntax::ast::ModuleItem
ByCrate(imports ): crate::ast::ModuleItem
ByCrate(imports ): ::syntax::ast::ModuleItem
BySelf (imports ): self::ast::ModuleItem
BySelf (imports ): ::syntax::ast::ModuleItem
"#]],
);
}
#[test]
fn same_crate_reexport() {
check_found_path(
@ -1769,6 +1814,43 @@ pub mod foo {
);
}
#[test]
fn respects_absolute_setting() {
let ra_fixture = r#"
//- /main.rs crate:main deps:krate
$0
//- /krate.rs crate:krate
pub mod foo {
pub struct Foo;
}
"#;
check_found_path(
ra_fixture,
"krate::foo::Foo",
expect![[r#"
Plain (imports ): krate::foo::Foo
Plain (imports ): krate::foo::Foo
ByCrate(imports ): krate::foo::Foo
ByCrate(imports ): krate::foo::Foo
BySelf (imports ): krate::foo::Foo
BySelf (imports ): krate::foo::Foo
"#]],
);
check_found_path_absolute(
ra_fixture,
"krate::foo::Foo",
expect![[r#"
Plain (imports ): ::krate::foo::Foo
Plain (imports ): ::krate::foo::Foo
ByCrate(imports ): ::krate::foo::Foo
ByCrate(imports ): ::krate::foo::Foo
BySelf (imports ): ::krate::foo::Foo
BySelf (imports ): ::krate::foo::Foo
"#]],
);
}
#[test]
fn respect_segment_length() {
check_found_path(

View file

@ -28,6 +28,7 @@ use crate::{
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
/// The index of the self param in the generic of the non-parent definition.
const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
@ -158,9 +159,9 @@ pub enum GenericParamDataRef<'a> {
/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericParams {
pub type_or_consts: Arena<TypeOrConstParamData>,
pub lifetimes: Arena<LifetimeParamData>,
pub where_predicates: Box<[WherePredicate]>,
type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>,
where_predicates: Box<[WherePredicate]>,
}
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@ -205,6 +206,219 @@ pub enum WherePredicateTypeTarget {
TypeOrConstParam(LocalTypeOrConstParamId),
}
impl GenericParams {
/// Number of Generic parameters (type_or_consts + lifetimes)
#[inline]
pub fn len(&self) -> usize {
self.type_or_consts.len() + self.lifetimes.len()
}
#[inline]
pub fn len_lifetimes(&self) -> usize {
self.lifetimes.len()
}
#[inline]
pub fn len_type_or_consts(&self) -> usize {
self.type_or_consts.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
self.where_predicates.iter()
}
/// Iterator of type_or_consts field
#[inline]
pub fn iter_type_or_consts(
&self,
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
self.type_or_consts.iter()
}
/// Iterator of lifetimes field
#[inline]
pub fn iter_lt(
&self,
) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
self.lifetimes.iter()
}
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
self.type_or_consts.iter().find_map(|(id, p)| {
if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
} else {
None
}
})
}
pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
self.type_or_consts.iter().find_map(|(id, p)| {
if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
} else {
None
}
})
}
#[inline]
pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
if self.type_or_consts.is_empty() {
return None;
}
matches!(
self.type_or_consts[SELF_PARAM_ID_IN_SELF],
TypeOrConstParamData::TypeParamData(TypeParamData {
provenance: TypeParamProvenance::TraitSelf,
..
})
)
.then(|| SELF_PARAM_ID_IN_SELF)
}
pub fn find_lifetime_by_name(
&self,
name: &Name,
parent: GenericDefId,
) -> Option<LifetimeParamId> {
self.lifetimes.iter().find_map(|(id, p)| {
if &p.name == name {
Some(LifetimeParamId { local_id: id, parent })
} else {
None
}
})
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db);
let cfg_options = db.crate_graph();
let cfg_options = &cfg_options[krate].cfg_options;
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
let all_lifetimes_enabled =
params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
fn id_to_generics<Id: GenericsItemTreeNode>(
db: &dyn DefDatabase,
id: impl for<'db> Lookup<
Database<'db> = dyn DefDatabase + 'db,
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
&Interned<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(item.generic_params(), &tree, id.value.into())
}
match def {
GenericDefId::FunctionId(id) => {
let loc = id.lookup(db);
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
let enabled_params =
enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
enabled_params
} else {
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = Lazy::new(|| {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
});
for param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
}
Interned::new(generic_params.finish())
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ConstId(_) => Interned::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
}),
}
}
}
#[derive(Clone, Default)]
pub(crate) struct GenericParamsCollector {
pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
@ -441,202 +655,3 @@ impl GenericParamsCollector {
}
}
}
impl GenericParams {
/// Number of Generic parameters (type_or_consts + lifetimes)
#[inline]
pub fn len(&self) -> usize {
self.type_or_consts.len() + self.lifetimes.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Iterator of type_or_consts field
#[inline]
pub fn iter_type_or_consts(
&self,
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
self.type_or_consts.iter()
}
/// Iterator of lifetimes field
#[inline]
pub fn iter_lt(
&self,
) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
self.lifetimes.iter()
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.module(db).krate;
let cfg_options = db.crate_graph();
let cfg_options = &cfg_options[krate].cfg_options;
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
let all_lifetimes_enabled =
params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
fn id_to_generics<Id: GenericsItemTreeNode>(
db: &dyn DefDatabase,
id: impl for<'db> Lookup<
Database<'db> = dyn DefDatabase + 'db,
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
&Interned<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(item.generic_params(), &tree, id.value.into())
}
match def {
GenericDefId::FunctionId(id) => {
let loc = id.lookup(db);
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
let enabled_params =
enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
enabled_params
} else {
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = Lazy::new(|| {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
});
for param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
}
Interned::new(generic_params.finish())
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params),
GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
Interned::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
})
}
}
}
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
self.type_or_consts.iter().find_map(|(id, p)| {
if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
} else {
None
}
})
}
pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
self.type_or_consts.iter().find_map(|(id, p)| {
if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
} else {
None
}
})
}
pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
if self.type_or_consts.is_empty() {
return None;
}
matches!(
self.type_or_consts[SELF_PARAM_ID_IN_SELF],
TypeOrConstParamData::TypeParamData(TypeParamData {
provenance: TypeParamProvenance::TraitSelf,
..
})
)
.then(|| SELF_PARAM_ID_IN_SELF)
}
pub fn find_lifetime_by_name(
&self,
name: &Name,
parent: GenericDefId,
) -> Option<LifetimeParamId> {
self.lifetimes.iter().find_map(|(id, p)| {
if &p.name == name {
Some(LifetimeParamId { local_id: id, parent })
} else {
None
}
})
}
}

View file

@ -20,6 +20,7 @@ use std::fmt;
use hir_expand::name::Name;
use intern::Interned;
use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use smallvec::SmallVec;
use syntax::ast;
@ -56,29 +57,38 @@ pub struct Label {
}
pub type LabelId = Idx<Label>;
// We convert float values into bits and that's how we don't need to deal with f32 and f64.
// For PartialEq, bits comparison should work, as ordering is not important
// We leave float values as a string to avoid double rounding.
// For PartialEq, string comparison should work, as ordering is not important
// https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct FloatTypeWrapper(u64);
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct FloatTypeWrapper(Box<str>);
// FIXME(#17451): Use builtin types once stabilised.
impl FloatTypeWrapper {
pub fn new(value: f64) -> Self {
Self(value.to_bits())
pub fn new(value: String) -> Self {
Self(value.into())
}
pub fn into_f64(self) -> f64 {
f64::from_bits(self.0)
pub fn to_f128(&self) -> f128 {
self.0.parse().unwrap_or_default()
}
pub fn into_f32(self) -> f32 {
f64::from_bits(self.0) as f32
pub fn to_f64(&self) -> f64 {
self.0.parse().unwrap_or_default()
}
pub fn to_f32(&self) -> f32 {
self.0.parse().unwrap_or_default()
}
pub fn to_f16(&self) -> f16 {
self.0.parse().unwrap_or_default()
}
}
impl fmt::Display for FloatTypeWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", f64::from_bits(self.0))
f.write_str(&self.0)
}
}
@ -91,7 +101,7 @@ pub enum Literal {
Bool(bool),
Int(i128, Option<BuiltinInt>),
Uint(u128, Option<BuiltinUint>),
// Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
// Here we are using a wrapper around float because float primitives do not implement Eq, so they
// could not be used directly here, to understand how the wrapper works go to definition of
// FloatTypeWrapper
Float(FloatTypeWrapper, Option<BuiltinFloat>),
@ -120,10 +130,7 @@ impl From<ast::LiteralKind> for Literal {
match ast_lit_kind {
LiteralKind::IntNumber(lit) => {
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
Literal::Float(
FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
builtin,
)
Literal::Float(FloatTypeWrapper::new(lit.value_string()), builtin)
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) {
Literal::Uint(lit.value().unwrap_or(0), builtin)
} else {
@ -133,7 +140,7 @@ impl From<ast::LiteralKind> for Literal {
}
LiteralKind::FloatNumber(lit) => {
let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
Literal::Float(FloatTypeWrapper::new(lit.value_string()), ty)
}
LiteralKind::ByteString(bs) => {
let text = bs.value().map_or_else(|_| Default::default(), Box::from);

View file

@ -10,7 +10,7 @@ use hir_expand::{
AstId,
};
use intern::Interned;
use syntax::ast::{self, HasName, IsString};
use syntax::ast::{self, HasGenericArgs, HasName, IsString};
use crate::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
@ -245,7 +245,13 @@ impl TypeRef {
// for types are close enough for our purposes to the inner type for now...
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::ImplTraitType(inner) => {
TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
if ctx.outer_impl_trait() {
// Disallow nested impl traits
TypeRef::Error
} else {
let _guard = ctx.outer_impl_trait_scope(true);
TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
}
}
ast::Type::DynTraitType(inner) => {
TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))

View file

@ -8,7 +8,6 @@ use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCall
use itertools::Itertools;
use la_arena::Idx;
use once_cell::sync::Lazy;
use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec};
use stdx::format_to;
@ -65,8 +64,6 @@ pub struct ImportId {
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
_c: Count<Self>,
/// Defs visible in this scope. This includes `declarations`, but also
/// imports. The imports belong to this module and can be resolved by using them on
/// the `use_imports_*` fields.
@ -722,7 +719,6 @@ impl ItemScope {
pub(crate) fn shrink_to_fit(&mut self) {
// Exhaustive match to require handling new fields.
let Self {
_c: _,
types,
values,
macros,

View file

@ -48,6 +48,7 @@ use either::Either;
use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
use intern::Interned;
use la_arena::{Arena, Idx, IdxRange, RawIdx};
use once_cell::sync::OnceCell;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use span::{AstIdNode, FileAstId, SyntaxContextId};
@ -100,6 +101,7 @@ pub struct ItemTree {
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
let syntax = db.parse_or_expand(file_id);
@ -131,18 +133,47 @@ impl ItemTree {
if let Some(attrs) = top_attrs {
item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
}
item_tree.shrink_to_fit();
Arc::new(item_tree)
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
})
.clone()
} else {
item_tree.shrink_to_fit();
Arc::new(item_tree)
}
}
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
let loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
let mut item_tree = ctx.lower_block(&block);
item_tree.shrink_to_fit();
Arc::new(item_tree)
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
})
.clone()
} else {
item_tree.shrink_to_fit();
Arc::new(item_tree)
}
}
/// Returns an iterator over all items located at the top level of the `HirFileId` this
@ -585,24 +616,30 @@ impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility;
fn index(&self, index: RawVisibilityId) -> &Self::Output {
static VIS_PUB: RawVisibility = RawVisibility::Public;
static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module(
ModPath::from_kind(PathKind::SELF),
VisibilityExplicitness::Implicit,
);
static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module(
ModPath::from_kind(PathKind::SELF),
VisibilityExplicitness::Explicit,
);
static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(
ModPath::from_kind(PathKind::Crate),
VisibilityExplicitness::Explicit,
);
static VIS_PRIV_IMPLICIT: OnceCell<RawVisibility> = OnceCell::new();
static VIS_PRIV_EXPLICIT: OnceCell<RawVisibility> = OnceCell::new();
static VIS_PUB_CRATE: OnceCell<RawVisibility> = OnceCell::new();
match index {
RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::SELF)),
VisibilityExplicitness::Implicit,
)
}),
RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::SELF)),
VisibilityExplicitness::Explicit,
)
}),
RawVisibilityId::PUB => &VIS_PUB,
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::Crate)),
VisibilityExplicitness::Explicit,
)
}),
_ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
}
}

View file

@ -532,7 +532,7 @@ impl Printer<'_> {
w!(self, "<");
let mut first = true;
for (idx, lt) in params.lifetimes.iter() {
for (idx, lt) in params.iter_lt() {
if !first {
w!(self, ", ");
}
@ -540,7 +540,7 @@ impl Printer<'_> {
self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
w!(self, "{}", lt.name.display(self.db.upcast()));
}
for (idx, x) in params.type_or_consts.iter() {
for (idx, x) in params.iter_type_or_consts() {
if !first {
w!(self, ", ");
}
@ -570,13 +570,13 @@ impl Printer<'_> {
}
fn print_where_clause(&mut self, params: &GenericParams) -> bool {
if params.where_predicates.is_empty() {
if params.where_predicates().next().is_none() {
return false;
}
w!(self, "\nwhere");
self.indented(|this| {
for (i, pred) in params.where_predicates.iter().enumerate() {
for (i, pred) in params.where_predicates().enumerate() {
if i != 0 {
wln!(this, ",");
}
@ -607,12 +607,10 @@ impl Printer<'_> {
match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeOrConstParam(id) => {
match &params.type_or_consts[*id].name() {
Some(name) => w!(this, "{}", name.display(self.db.upcast())),
None => w!(this, "_anon_{}", id.into_raw()),
}
}
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => w!(this, "{}", name.display(self.db.upcast())),
None => w!(this, "_anon_{}", id.into_raw()),
},
}
w!(this, ": ");
this.print_type_bounds(std::slice::from_ref(bound));

View file

@ -7,7 +7,6 @@
//! Note that `hir_def` is a work in progress, so not all of the above is
//! actually true.
#![warn(rust_2018_idioms, unused_lifetimes)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[cfg(feature = "in-rust-tree")]
@ -117,6 +116,8 @@ pub struct ImportPathConfig {
pub prefer_no_std: bool,
/// If true, prefer import paths containing a prelude module.
pub prefer_prelude: bool,
/// If true, prefer abs path (starting with `::`) where it is available.
pub prefer_absolute: bool,
}
#[derive(Debug)]
@ -689,7 +690,7 @@ pub enum TypeOwnerId {
}
impl TypeOwnerId {
fn as_generic_def_id(self) -> Option<GenericDefId> {
fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
Some(match self {
TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it),
TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it),
@ -698,7 +699,9 @@ impl TypeOwnerId {
TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it),
TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it),
TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
TypeOwnerId::EnumVariantId(it) => {
GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
}
TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None,
})
}
@ -740,7 +743,6 @@ impl From<GenericDefId> for TypeOwnerId {
GenericDefId::TraitAliasId(it) => it.into(),
GenericDefId::TypeAliasId(it) => it.into(),
GenericDefId::ImplId(it) => it.into(),
GenericDefId::EnumVariantId(it) => it.into(),
GenericDefId::ConstId(it) => it.into(),
}
}
@ -849,8 +851,8 @@ impl GeneralConstId {
pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
match self {
GeneralConstId::ConstId(it) => Some(it.into()),
GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(),
GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(),
GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db),
GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db),
}
}
@ -888,12 +890,12 @@ impl From<EnumVariantId> for DefWithBodyId {
}
impl DefWithBodyId {
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
pub fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
match self {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(c) => Some(c.into()),
DefWithBodyId::VariantId(c) => Some(c.into()),
DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()),
// FIXME: stable rust doesn't allow generics in constants, but we should
// use `TypeOwnerId::as_generic_def_id` when it does.
DefWithBodyId::InTypeConstId(_) => None,
@ -921,10 +923,6 @@ pub enum GenericDefId {
TraitAliasId(TraitAliasId),
TypeAliasId(TypeAliasId),
ImplId(ImplId),
// enum variants cannot have generics themselves, but their parent enums
// can, and this makes some code easier to write
// FIXME: Try to remove this as that will reduce the amount of query slots generated per enum?
EnumVariantId(EnumVariantId),
// consts can have type parameters from their parents (i.e. associated consts of traits)
ConstId(ConstId),
}
@ -935,7 +933,6 @@ impl_from!(
TraitAliasId,
TypeAliasId,
ImplId,
EnumVariantId,
ConstId
for GenericDefId
);
@ -967,7 +964,6 @@ impl GenericDefId {
GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None),
}
}
@ -982,6 +978,14 @@ impl GenericDefId {
_ => None,
}
}
pub fn from_callable(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId {
match def {
CallableDefId::FunctionId(f) => f.into(),
CallableDefId::StructId(s) => s.into(),
CallableDefId::EnumVariantId(e) => e.lookup(db).parent.into(),
}
}
}
impl From<AssocItemId> for GenericDefId {
@ -994,6 +998,36 @@ impl From<AssocItemId> for GenericDefId {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CallableDefId {
FunctionId(FunctionId),
StructId(StructId),
EnumVariantId(EnumVariantId),
}
impl InternValueTrivial for CallableDefId {}
impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
impl From<CallableDefId> for ModuleDefId {
fn from(def: CallableDefId) -> ModuleDefId {
match def {
CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
}
}
}
impl CallableDefId {
pub fn krate(self, db: &dyn DefDatabase) -> CrateId {
match self {
CallableDefId::FunctionId(f) => f.krate(db),
CallableDefId::StructId(s) => s.krate(db),
CallableDefId::EnumVariantId(e) => e.krate(db),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AttrDefId {
ModuleId(ModuleId),
@ -1310,7 +1344,6 @@ impl HasModule for GenericDefId {
GenericDefId::TraitAliasId(it) => it.module(db),
GenericDefId::TypeAliasId(it) => it.module(db),
GenericDefId::ImplId(it) => it.module(db),
GenericDefId::EnumVariantId(it) => it.module(db),
GenericDefId::ConstId(it) => it.module(db),
}
}

View file

@ -18,6 +18,26 @@ pub struct LowerCtx<'a> {
span_map: OnceCell<SpanMap>,
ast_id_map: OnceCell<Arc<AstIdMap>>,
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
// Prevent nested impl traits like `impl Foo<impl Bar>`.
outer_impl_trait: RefCell<bool>,
}
pub(crate) struct OuterImplTraitGuard<'a> {
ctx: &'a LowerCtx<'a>,
old: bool,
}
impl<'a> OuterImplTraitGuard<'a> {
fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
let old = ctx.outer_impl_trait.replace(impl_trait);
Self { ctx, old }
}
}
impl<'a> Drop for OuterImplTraitGuard<'a> {
fn drop(&mut self) {
self.ctx.outer_impl_trait.replace(self.old);
}
}
impl<'a> LowerCtx<'a> {
@ -28,6 +48,7 @@ impl<'a> LowerCtx<'a> {
span_map: OnceCell::new(),
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
}
}
@ -42,6 +63,7 @@ impl<'a> LowerCtx<'a> {
span_map,
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
}
}
@ -67,4 +89,12 @@ impl<'a> LowerCtx<'a> {
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
self.impl_trait_bounds.take()
}
pub(crate) fn outer_impl_trait(&self) -> bool {
*self.outer_impl_trait.borrow()
}
pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
OuterImplTraitGuard::new(self, impl_trait)
}
}

View file

@ -36,6 +36,7 @@ macro_rules! m {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = 45E+1234_f128;
let _ = "rust1";
let _ = -92;
}
@ -50,6 +51,7 @@ macro_rules! m {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = 45E+1234_f128;
let _ = "rust1";
let _ = -92;
}
@ -58,6 +60,7 @@ fn f() {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = 45E+1234_f128;
let _ = "rust1";
let _ = -92;
}

View file

@ -103,12 +103,13 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
/// is computed by the `block_def_map` query.
#[derive(Debug, PartialEq, Eq)]
pub struct DefMap {
/// The crate this `DefMap` belongs to.
krate: CrateId,
/// When this is a block def map, this will hold the block id of the block and module that
/// contains this block.
block: Option<BlockInfo>,
/// The modules and their data declared in this crate.
pub modules: Arena<ModuleData>,
krate: CrateId,
/// The prelude module for this crate. This either comes from an import
/// marked with the `prelude_import` attribute, or (in the normal case) from
/// a dependency (`std` or `core`).
@ -124,6 +125,7 @@ pub struct DefMap {
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
// FIXME: Figure out a better way for the IDE layer to resolve these?
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
/// The diagnostics that need to be emitted for this crate.

View file

@ -83,7 +83,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
let name = Name::new_text_dont_use(it.name.clone());
(
name,
if it.disabled {
if !db.expand_proc_attr_macros() {
CustomProcMacroExpander::dummy()
} else if it.disabled {
CustomProcMacroExpander::disabled()
} else {
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new(
@ -1331,16 +1333,6 @@ impl DefCollector<'_> {
let call_id = call_id();
if let MacroDefKind::ProcMacro(_, exp, _) = def.kind {
// If proc attribute macro expansion is disabled, skip expanding it here
if !self.db.expand_proc_attr_macros() {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
directive.module_id,
self.db.lookup_intern_macro_call(call_id).kind,
def.krate,
));
return recollect_without(self);
}
// If there's no expander for the proc macro (e.g.
// because proc macros are disabled, or building the
// proc macro crate failed), report this and skip

View file

@ -17,16 +17,47 @@ use crate::{
#[derive(Debug, PartialEq, Eq)]
pub enum DefDiagnosticKind {
UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
MalformedDerive { ast: AstId<ast::Adt>, id: usize },
MacroDefError { ast: AstId<ast::Macro>, message: String },
UnresolvedModule {
ast: AstId<ast::Module>,
candidates: Box<[String]>,
},
UnresolvedExternCrate {
ast: AstId<ast::ExternCrate>,
},
UnresolvedImport {
id: ItemTreeId<item_tree::Use>,
index: Idx<ast::UseTree>,
},
UnconfiguredCode {
ast: ErasedAstId,
cfg: CfgExpr,
opts: CfgOptions,
},
/// A proc-macro that is lacking an expander, this might be due to build scripts not yet having
/// run or proc-macro expansion being disabled.
UnresolvedProcMacro {
ast: MacroCallKind,
krate: CrateId,
},
UnresolvedMacroCall {
ast: MacroCallKind,
path: ModPath,
},
UnimplementedBuiltinMacro {
ast: AstId<ast::Macro>,
},
InvalidDeriveTarget {
ast: AstId<ast::Item>,
id: usize,
},
MalformedDerive {
ast: AstId<ast::Adt>,
id: usize,
},
MacroDefError {
ast: AstId<ast::Macro>,
message: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -92,10 +123,6 @@ impl DefDiagnostic {
Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
}
// FIXME: Whats the difference between this and unresolved_macro_call
// FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
// yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
// struct loses all that information!
pub fn unresolved_proc_macro(
container: LocalModuleId,
ast: MacroCallKind,

View file

@ -9,7 +9,7 @@ use hir_expand::{
name::{name, AsName},
};
use intern::Interned;
use syntax::ast::{self, AstNode, HasTypeBounds};
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
use crate::{
path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind},
@ -202,6 +202,8 @@ pub(super) fn lower_generic_args(
continue;
}
if let Some(name_ref) = assoc_type_arg.name_ref() {
// Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
let _guard = lower_ctx.outer_impl_trait_scope(false);
let name = name_ref.as_name();
let args = assoc_type_arg
.generic_arg_list()

View file

@ -596,7 +596,7 @@ impl Resolver {
Scope::GenericParams { params, def } => Some((params, def)),
_ => None,
})
.flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def)))
.flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def)))
}
pub fn generic_def(&self) -> Option<GenericDefId> {
@ -758,10 +758,10 @@ impl Scope {
}
Scope::GenericParams { params, def: parent } => {
let parent = *parent;
for (local_id, param) in params.type_or_consts.iter() {
for (local_id, param) in params.iter_type_or_consts() {
if let Some(name) = &param.name() {
let id = TypeOrConstParamId { parent, local_id };
let data = &db.generic_params(parent).type_or_consts[local_id];
let data = &db.generic_params(parent)[local_id];
acc.add(
name,
ScopeDef::GenericParam(match data {
@ -775,7 +775,7 @@ impl Scope {
);
}
}
for (local_id, param) in params.lifetimes.iter() {
for (local_id, param) in params.iter_lt() {
let id = LifetimeParamId { parent, local_id };
acc.add(&param.name, ScopeDef::GenericParam(id.into()))
}
@ -1164,7 +1164,6 @@ impl HasResolver for GenericDefId {
GenericDefId::TraitAliasId(inner) => inner.resolver(db),
GenericDefId::TypeAliasId(inner) => inner.resolver(db),
GenericDefId::ImplId(inner) => inner.resolver(db),
GenericDefId::EnumVariantId(inner) => inner.resolver(db),
GenericDefId::ConstId(inner) => inner.resolver(db),
}
}

View file

@ -64,7 +64,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
db: &dyn DefDatabase,
) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
let generic_params = db.generic_params(*self);
let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
let mut idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx);
let (file_id, generic_params_list) = self.file_id_and_params_of(db);
@ -103,7 +103,7 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
db: &dyn DefDatabase,
) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
let generic_params = db.generic_params(*self);
let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
let idx_iter = generic_params.iter_lt().map(|(idx, _)| idx);
let (file_id, generic_params_list) = self.file_id_and_params_of(db);

View file

@ -2,6 +2,7 @@
use std::iter;
use intern::Interned;
use la_arena::ArenaMap;
use span::SyntaxContextId;
use syntax::ast;
@ -20,14 +21,17 @@ use crate::{
pub enum RawVisibility {
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
/// equivalent to `pub(self)`.
Module(ModPath, VisibilityExplicitness),
Module(Interned<ModPath>, VisibilityExplicitness),
/// `pub`.
Public,
}
impl RawVisibility {
pub(crate) const fn private() -> RawVisibility {
RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit)
pub(crate) fn private() -> RawVisibility {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::SELF)),
VisibilityExplicitness::Implicit,
)
}
pub(crate) fn from_ast(
@ -60,7 +64,7 @@ impl RawVisibility {
ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
ast::VisibilityKind::Pub => return RawVisibility::Public,
};
RawVisibility::Module(path, VisibilityExplicitness::Explicit)
RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
}
pub fn resolve(

View file

@ -25,7 +25,8 @@ impl ChangeWithProcMacros {
pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) {
self.source_change.apply(db);
if let Some(proc_macros) = self.proc_macros {
if let Some(mut proc_macros) = self.proc_macros {
proc_macros.shrink_to_fit();
db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
}
if let Some(target_data_layouts) = self.target_data_layouts {

View file

@ -172,15 +172,30 @@ impl DeclarativeMacroExpander {
),
ast::Macro::MacroDef(macro_def) => (
match macro_def.body() {
Some(arg) => {
let tt = mbe::syntax_node_to_token_tree(
arg.syntax(),
Some(body) => {
let span =
map.span_for_range(macro_def.macro_token().unwrap().text_range());
let args = macro_def.args().map(|args| {
mbe::syntax_node_to_token_tree(
args.syntax(),
map.as_ref(),
span,
DocCommentDesugarMode::Mbe,
)
});
let body = mbe::syntax_node_to_token_tree(
body.syntax(),
map.as_ref(),
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
span,
DocCommentDesugarMode::Mbe,
);
mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
mbe::DeclarativeMacro::parse_macro2(
args.as_ref(),
&body,
edition,
new_meta_vars,
)
}
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
"expected a token tree".into(),

View file

@ -1,4 +1,6 @@
//! Things to wrap other things in file ids.
use std::borrow::Borrow;
use either::Either;
use span::{
AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr,
@ -76,6 +78,13 @@ impl<FileKind: Copy, T> InFileWrapper<FileKind, T> {
pub fn as_ref(&self) -> InFileWrapper<FileKind, &T> {
self.with_value(&self.value)
}
pub fn borrow<U>(&self) -> InFileWrapper<FileKind, &U>
where
T: Borrow<U>,
{
self.with_value(self.value.borrow())
}
}
impl<FileKind: Copy, T: Clone> InFileWrapper<FileKind, &T> {
@ -156,14 +165,61 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
}
// region:specific impls
impl<SN: Borrow<SyntaxNode>> InRealFile<SN> {
pub fn file_range(&self) -> FileRange {
FileRange { file_id: self.file_id, range: self.value.borrow().text_range() }
}
}
impl<SN: Borrow<SyntaxNode>> InFile<SN> {
pub fn parent_ancestors_with_macros(
self,
db: &dyn db::ExpandDatabase,
) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
Some(parent) => Some(node.with_value(parent)),
None => db
.lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id)
.to_node_item(db)
.syntax()
.cloned()
.map(|node| node.parent())
.transpose(),
};
std::iter::successors(succ(&self.borrow().cloned()), succ)
}
pub fn ancestors_with_macros(
self,
db: &dyn db::ExpandDatabase,
) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
Some(parent) => Some(node.with_value(parent)),
None => db
.lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id)
.to_node_item(db)
.syntax()
.cloned()
.map(|node| node.parent())
.transpose(),
};
std::iter::successors(Some(self.borrow().cloned()), succ)
}
pub fn kind(&self) -> parser::SyntaxKind {
self.value.borrow().kind()
}
pub fn text_range(&self) -> TextRange {
self.value.borrow().text_range()
}
impl InFile<&SyntaxNode> {
/// Falls back to the macro call range if the node cannot be mapped up fully.
///
/// For attributes and derives, this will point back to the attribute only.
/// For the entire item use [`InFile::original_file_range_full`].
pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange {
self.map(SyntaxNode::text_range).original_node_file_range_rooted(db)
self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db)
}
/// Falls back to the macro call range if the node cannot be mapped up fully.
@ -171,15 +227,7 @@ impl InFile<&SyntaxNode> {
self,
db: &dyn db::ExpandDatabase,
) -> FileRange {
self.map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db)
}
/// Attempts to map the syntax node back up its macro calls.
pub fn original_file_range_opt(
self,
db: &dyn db::ExpandDatabase,
) -> Option<(FileRange, SyntaxContextId)> {
self.map(SyntaxNode::text_range).original_node_file_range_opt(db)
self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db)
}
pub fn original_syntax_node_rooted(
@ -190,16 +238,19 @@ impl InFile<&SyntaxNode> {
// as we don't have node inputs otherwise and therefore can't find an `N` node in the input
let file_id = match self.file_id.repr() {
HirFileIdRepr::FileId(file_id) => {
return Some(InRealFile { file_id, value: self.value.clone() })
return Some(InRealFile { file_id, value: self.value.borrow().clone() })
}
HirFileIdRepr::MacroFile(m) if m.is_attr_macro(db) => m,
_ => return None,
};
let FileRange { file_id, range } =
map_node_range_up_rooted(db, &db.expansion_span_map(file_id), self.value.text_range())?;
let FileRange { file_id, range } = map_node_range_up_rooted(
db,
&db.expansion_span_map(file_id),
self.value.borrow().text_range(),
)?;
let kind = self.value.kind();
let kind = self.kind();
let value = db
.parse(file_id)
.syntax_node()
@ -211,6 +262,16 @@ impl InFile<&SyntaxNode> {
}
}
impl InFile<&SyntaxNode> {
/// Attempts to map the syntax node back up its macro calls.
pub fn original_file_range_opt(
self,
db: &dyn db::ExpandDatabase,
) -> Option<(FileRange, SyntaxContextId)> {
self.borrow().map(SyntaxNode::text_range).original_node_file_range_opt(db)
}
}
impl InMacroFile<SyntaxToken> {
pub fn upmap_once(
self,

View file

@ -4,7 +4,6 @@
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#![warn(rust_2018_idioms, unused_lifetimes)]
pub mod attrs;
pub mod builtin_attr_macro;

View file

@ -275,8 +275,10 @@ pub mod known {
u32,
u64,
u128,
f16,
f32,
f64,
f128,
bool,
char,
str,

View file

@ -33,6 +33,7 @@ triomphe.workspace = true
nohash-hasher.workspace = true
typed-arena = "2.0.1"
indexmap.workspace = true
rustc_apfloat = "0.2.0"
ra-ap-rustc_abi.workspace = true
ra-ap-rustc_index.workspace = true

View file

@ -63,7 +63,14 @@ impl<D> TyBuilder<D> {
}
fn build_internal(self) -> (D, Substitution) {
assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds);
assert_eq!(
self.vec.len(),
self.param_kinds.len(),
"{} args received, {} expected ({:?})",
self.vec.len(),
self.param_kinds.len(),
&self.param_kinds
);
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
self.assert_match_kind(a, e);
}
@ -252,8 +259,9 @@ impl TyBuilder<()> {
/// This method prepopulates the builder with placeholder substitution of `parent`, so you
/// should only push exactly 3 `GenericArg`s before building.
pub fn subst_for_coroutine(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
let parent_subst =
parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
let parent_subst = parent
.as_generic_def_id(db.upcast())
.map(|p| generics(db.upcast(), p).placeholder_subst(db));
// These represent resume type, yield type, and return type of coroutine.
let params = std::iter::repeat(ParamKind::Type).take(3).collect();
TyBuilder::new((), params, parent_subst)
@ -266,7 +274,7 @@ impl TyBuilder<()> {
) -> Substitution {
let sig_ty = sig_ty.cast(Interner);
let self_subst = iter::once(&sig_ty);
let Some(parent) = parent.as_generic_def_id() else {
let Some(parent) = parent.as_generic_def_id(db.upcast()) else {
return Substitution::from_iter(Interner, self_subst);
};
Substitution::from_iter(
@ -296,7 +304,8 @@ impl TyBuilder<hir_def::AdtId> {
) -> Self {
// Note that we're building ADT, so we never have parent generic parameters.
let defaults = db.generic_defaults(self.data.into());
for default_ty in defaults.iter().skip(self.vec.len()) {
for default_ty in &defaults[self.vec.len()..] {
// NOTE(skip_binders): we only check if the arg type is error type.
if let Some(x) = default_ty.skip_binders().ty(Interner) {
if x.is_unknown() {

View file

@ -13,7 +13,8 @@ use hir_def::{
data::adt::StructFlags,
hir::Movability,
lang_item::{LangItem, LangItemTarget},
AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId,
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
TypeAliasId, VariantId,
};
use hir_expand::name::name;
@ -28,9 +29,9 @@ use crate::{
to_assoc_type_id, to_chalk_trait_id,
traits::ChalkContext,
utils::ClosureSubst,
wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
wrap_empty_binders, AliasEq, AliasTy, BoundVar, DebruijnIndex, FnDefId, Interner, ProjectionTy,
ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
TyExt, TyKind, WhereClause,
};
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
@ -102,7 +103,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
&self,
fn_def_id: chalk_ir::FnDefId<Interner>,
) -> Arc<rust_ir::FnDefDatum<Interner>> {
self.db.fn_def_datum(self.krate, fn_def_id)
self.db.fn_def_datum(fn_def_id)
}
fn impls_for_trait(
@ -912,16 +913,13 @@ fn type_alias_associated_ty_value(
Arc::new(value)
}
pub(crate) fn fn_def_datum_query(
db: &dyn HirDatabase,
_krate: CrateId,
fn_def_id: FnDefId,
) -> Arc<FnDefDatum> {
pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Arc<FnDefDatum> {
let callable_def: CallableDefId = from_chalk(db, fn_def_id);
let generic_params = generics(db.upcast(), callable_def.into());
let generic_def = GenericDefId::from_callable(db.upcast(), callable_def);
let generic_params = generics(db.upcast(), generic_def);
let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
let where_clauses = convert_where_clauses(db, generic_def, &bound_vars);
let bound = rust_ir::FnDefDatumBound {
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
inputs_and_output: chalk_ir::Binders::empty(
@ -948,7 +946,8 @@ pub(crate) fn fn_def_datum_query(
pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances {
let callable_def: CallableDefId = from_chalk(db, fn_def_id);
let generic_params = generics(db.upcast(), callable_def.into());
let generic_params =
generics(db.upcast(), GenericDefId::from_callable(db.upcast(), callable_def));
Variances::from_iter(
Interner,
std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),

View file

@ -119,8 +119,10 @@ impl TyExt for Ty {
TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool),
TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char),
TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty {
FloatTy::F128 => BuiltinFloat::F128,
FloatTy::F64 => BuiltinFloat::F64,
FloatTy::F32 => BuiltinFloat::F32,
FloatTy::F16 => BuiltinFloat::F16,
})),
TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity {
IntTy::Isize => BuiltinInt::Isize,
@ -188,9 +190,10 @@ impl TyExt for Ty {
fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
match *self.kind(Interner) {
TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
TyKind::FnDef(callable, ..) => {
Some(db.lookup_intern_callable_def(callable.into()).into())
}
TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
db.upcast(),
db.lookup_intern_callable_def(callable.into()),
)),
TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
_ => None,
@ -308,7 +311,7 @@ impl TyExt for Ty {
TyKind::Placeholder(idx) => {
let id = from_placeholder_idx(db, *idx);
let generic_params = db.generic_params(id.parent);
let param_data = &generic_params.type_or_consts[id.local_id];
let param_data = &generic_params[id.local_id];
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {

View file

@ -1,6 +1,10 @@
use base_db::FileId;
use chalk_ir::Substitution;
use hir_def::db::DefDatabase;
use rustc_apfloat::{
ieee::{Half as f16, Quad as f128},
Float,
};
use test_fixture::WithFixture;
use test_utils::skip_slow_tests;
@ -140,6 +144,14 @@ fn bit_op() {
#[test]
fn floating_point() {
check_number(
r#"const GOAL: f128 = 2.0 + 3.0 * 5.5 - 8.;"#,
"10.5".parse::<f128>().unwrap().to_bits() as i128,
);
check_number(
r#"const GOAL: f128 = -90.0 + 36.0;"#,
"-54.0".parse::<f128>().unwrap().to_bits() as i128,
);
check_number(
r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#,
i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)),
@ -152,6 +164,20 @@ fn floating_point() {
r#"const GOAL: f32 = -90.0 + 36.0;"#,
i128::from_le_bytes(pad16(&f32::to_le_bytes(-54.0), true)),
);
check_number(
r#"const GOAL: f16 = 2.0 + 3.0 * 5.5 - 8.;"#,
i128::from_le_bytes(pad16(
&u16::try_from("10.5".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(),
true,
)),
);
check_number(
r#"const GOAL: f16 = -90.0 + 36.0;"#,
i128::from_le_bytes(pad16(
&u16::try_from("-54.0".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(),
true,
)),
);
}
#[test]

View file

@ -411,6 +411,7 @@ fn likely() {
#[test]
fn floating_point() {
// FIXME(#17451): Add `f16` and `f128` tests once intrinsics are added.
check_number(
r#"
extern "rust-intrinsic" {
@ -426,6 +427,7 @@ fn floating_point() {
true,
)),
);
#[allow(unknown_lints, clippy::unnecessary_min_or_max)]
check_number(
r#"
extern "rust-intrinsic" {

View file

@ -9,8 +9,8 @@ use base_db::{
CrateId, Upcast,
};
use hir_def::{
db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, CallableDefId,
ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId,
};
use la_arena::ArenaMap;
@ -24,9 +24,8 @@ use crate::{
lower::{GenericDefaults, GenericPredicates},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError},
Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult,
Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty,
TyDefId, ValueTyDefId,
Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner,
PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
};
use hir_expand::name::Name;
@ -81,8 +80,32 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
fn lookup_impl_method(
&self,
env: Arc<TraitEnvironment>,
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution);
// endregion:mir
#[salsa::invoke(crate::layout::layout_of_adt_query)]
#[salsa::cycle(crate::layout::layout_of_adt_recover)]
fn layout_of_adt(
&self,
def: AdtId,
subst: Substitution,
env: Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke(crate::lower::ty_query)]
#[salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>;
@ -105,30 +128,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::field_types_query)]
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
#[salsa::invoke(crate::layout::layout_of_adt_query)]
#[salsa::cycle(crate::layout::layout_of_adt_recover)]
fn layout_of_adt(
&self,
def: AdtId,
subst: Substitution,
env: Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
fn lookup_impl_method(
&self,
env: Arc<TraitEnvironment>,
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution);
#[salsa::invoke(crate::lower::callable_item_sig)]
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
@ -145,7 +144,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
def: GenericDefId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]>;
) -> GenericPredicates;
#[salsa::invoke(crate::lower::generic_predicates_query)]
fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
@ -232,7 +231,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
) -> sync::Arc<chalk_db::ImplDatum>;
#[salsa::invoke(chalk_db::fn_def_datum_query)]
fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;
fn fn_def_datum(&self, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;
#[salsa::invoke(chalk_db::fn_def_variance_query)]
fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances;

View file

@ -196,6 +196,9 @@ impl ExprValidator {
let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else {
return;
};
if pat_ty.contains_unknown() {
return;
}
// We only include patterns whose type matches the type
// of the scrutinee expression. If we had an InvalidMatchArmPattern

View file

@ -51,6 +51,7 @@ pub(crate) struct Pat {
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum PatKind {
Wild,
Never,
/// `x`, `ref x`, `x @ P`, etc.
Binding {
@ -294,6 +295,7 @@ impl HirDisplay for Pat {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match &*self.kind {
PatKind::Wild => write!(f, "_"),
PatKind::Never => write!(f, "!"),
PatKind::Binding { name, subpattern } => {
write!(f, "{}", name.display(f.db.upcast()))?;
if let Some(subpattern) = subpattern {

View file

@ -4,12 +4,10 @@ use std::fmt;
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
use once_cell::unsync::Lazy;
use rustc_hash::FxHashMap;
use rustc_pattern_analysis::{
constructor::{Constructor, ConstructorSet, VariantVisibility},
index::IdxContainer,
usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport},
Captures, PatCx, PrivateUninhabitedField,
Captures, IndexVec, PatCx, PrivateUninhabitedField,
};
use smallvec::{smallvec, SmallVec};
use stdx::never;
@ -26,10 +24,10 @@ use super::{is_box, FieldPat, Pat, PatKind};
use Constructor::*;
// Re-export r-a-specific versions of all these types.
pub(crate) type DeconstructedPat<'p> =
rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'p>>;
pub(crate) type MatchArm<'p> = rustc_pattern_analysis::MatchArm<'p, MatchCheckCtx<'p>>;
pub(crate) type WitnessPat<'p> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'p>>;
pub(crate) type DeconstructedPat<'db> =
rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'db>>;
pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>;
pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'db>>;
/// [Constructor] uses this in unimplemented variants.
/// It allows porting match expressions from upstream algorithm without losing semantics.
@ -54,23 +52,27 @@ impl EnumVariantContiguousIndex {
}
}
impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex {
fn new(idx: usize) -> Self {
EnumVariantContiguousIndex(idx)
}
fn index(self) -> usize {
self.0
}
}
#[derive(Clone)]
pub(crate) struct MatchCheckCtx<'p> {
pub(crate) struct MatchCheckCtx<'db> {
module: ModuleId,
body: DefWithBodyId,
pub(crate) db: &'p dyn HirDatabase,
pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool,
min_exhaustive_patterns: bool,
}
#[derive(Clone)]
pub(crate) struct PatData<'p> {
/// Keep db around so that we can print variant names in `Debug`.
pub(crate) db: &'p dyn HirDatabase,
}
impl<'p> MatchCheckCtx<'p> {
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'p dyn HirDatabase) -> Self {
impl<'db> MatchCheckCtx<'db> {
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
let def_map = db.crate_def_map(module.krate());
let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
let min_exhaustive_patterns =
@ -80,9 +82,9 @@ impl<'p> MatchCheckCtx<'p> {
pub(crate) fn compute_match_usefulness(
&self,
arms: &[MatchArm<'p>],
arms: &[MatchArm<'db>],
scrut_ty: Ty,
) -> Result<UsefulnessReport<'p, Self>, ()> {
) -> Result<UsefulnessReport<'db, Self>, ()> {
// FIXME: Determine place validity correctly. For now, err on the safe side.
let place_validity = PlaceValidity::MaybeInvalid;
// Measured to take ~100ms on modern hardware.
@ -101,7 +103,7 @@ impl<'p> MatchCheckCtx<'p> {
}
fn variant_id_for_adt(
db: &'p dyn HirDatabase,
db: &'db dyn HirDatabase,
ctor: &Constructor<Self>,
adt: hir_def::AdtId,
) -> Option<VariantId> {
@ -126,7 +128,7 @@ impl<'p> MatchCheckCtx<'p> {
&'a self,
ty: &'a Ty,
variant: VariantId,
) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'p> {
) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> {
let (_, substs) = ty.as_adt().unwrap();
let field_tys = self.db.field_types(variant);
@ -139,8 +141,8 @@ impl<'p> MatchCheckCtx<'p> {
})
}
pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> {
let singleton = |pat: DeconstructedPat<'p>| vec![pat.at_index(0)];
pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> {
let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)];
let ctor;
let mut fields: Vec<_>;
let arity;
@ -228,6 +230,11 @@ impl<'p> MatchCheckCtx<'p> {
fields = Vec::new();
arity = 0;
}
PatKind::Never => {
ctor = Never;
fields = Vec::new();
arity = 0;
}
PatKind::Or { pats } => {
ctor = Or;
fields = pats
@ -238,11 +245,10 @@ impl<'p> MatchCheckCtx<'p> {
arity = pats.len();
}
}
let data = PatData { db: self.db };
DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), data)
DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ())
}
pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'p>) -> Pat {
pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat {
let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p));
let kind = match pat.ctor() {
&Bool(value) => PatKind::LiteralBool { value },
@ -290,6 +296,7 @@ impl<'p> MatchCheckCtx<'p> {
Slice(_) => unimplemented!(),
&Str(void) => match void {},
Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
Never => PatKind::Never,
Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => {
never!("can't convert to pattern: {:?}", pat.ctor());
PatKind::Wild
@ -299,13 +306,13 @@ impl<'p> MatchCheckCtx<'p> {
}
}
impl<'p> PatCx for MatchCheckCtx<'p> {
impl<'db> PatCx for MatchCheckCtx<'db> {
type Error = ();
type Ty = Ty;
type VariantIdx = EnumVariantContiguousIndex;
type StrLit = Void;
type ArmData = ();
type PatData = PatData<'p>;
type PatData = ();
fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.exhaustive_patterns
@ -339,8 +346,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
},
Ref => 1,
Slice(..) => unimplemented!(),
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
| NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0,
Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..)
| Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0,
Or => {
never!("The `Or` constructor doesn't have a fixed arity");
0
@ -402,8 +409,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
}
},
Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
| NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => smallvec![],
Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..)
| Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => {
smallvec![]
}
Or => {
never!("called `Fields::wildcards` on an `Or` ctor");
smallvec![]
@ -442,11 +451,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
ConstructorSet::NoConstructors
} else {
let mut variants = FxHashMap::with_capacity_and_hasher(
enum_data.variants.len(),
Default::default(),
);
for (i, &(variant, _)) in enum_data.variants.iter().enumerate() {
let mut variants = IndexVec::with_capacity(enum_data.variants.len());
for &(variant, _) in enum_data.variants.iter() {
let is_uninhabited =
is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module);
let visibility = if is_uninhabited {
@ -454,13 +460,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
} else {
VariantVisibility::Visible
};
variants.insert(EnumVariantContiguousIndex(i), visibility);
variants.push(visibility);
}
ConstructorSet::Variants {
variants: IdxContainer(variants),
non_exhaustive: is_declared_nonexhaustive,
}
ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
}
}
TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union,
@ -476,26 +479,27 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
fn write_variant_name(
f: &mut fmt::Formatter<'_>,
pat: &rustc_pattern_analysis::pat::DeconstructedPat<Self>,
_ctor: &Constructor<Self>,
_ty: &Self::Ty,
) -> fmt::Result {
let db = pat.data().db;
let variant =
pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, pat.ctor(), adt));
write!(f, "<write_variant_name unsupported>")
// We lack the database here ...
// let variant = ty.as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, ctor, adt));
if let Some(variant) = variant {
match variant {
VariantId::EnumVariantId(v) => {
write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?;
}
VariantId::StructId(s) => {
write!(f, "{}", db.struct_data(s).name.display(db.upcast()))?
}
VariantId::UnionId(u) => {
write!(f, "{}", db.union_data(u).name.display(db.upcast()))?
}
}
}
Ok(())
// if let Some(variant) = variant {
// match variant {
// VariantId::EnumVariantId(v) => {
// write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?;
// }
// VariantId::StructId(s) => {
// write!(f, "{}", db.struct_data(s).name.display(db.upcast()))?
// }
// VariantId::UnionId(u) => {
// write!(f, "{}", db.union_data(u).name.display(db.upcast()))?
// }
// }
// }
// Ok(())
}
fn bug(&self, fmt: fmt::Arguments<'_>) {
@ -507,7 +511,7 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
}
}
impl<'p> fmt::Debug for MatchCheckCtx<'p> {
impl<'db> fmt::Debug for MatchCheckCtx<'db> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish()
}

View file

@ -21,13 +21,17 @@ use hir_def::{
path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility,
HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
TraitId,
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
ModuleId, TraitId,
};
use hir_expand::name::Name;
use intern::{Internable, Interned};
use itertools::Itertools;
use la_arena::ArenaMap;
use rustc_apfloat::{
ieee::{Half as f16, Quad as f128},
Float,
};
use smallvec::SmallVec;
use stdx::{never, IsNoneOr};
use triomphe::Arc;
@ -545,6 +549,17 @@ fn render_const_scalar(
write!(f, "{it}")
}
Scalar::Float(fl) => match fl {
chalk_ir::FloatTy::F16 => {
// FIXME(#17451): Replace with builtins once they are stabilised.
let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into());
let s = it.to_string();
if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
// Match Rust debug formatting
write!(f, "{s}.0")
} else {
write!(f, "{s}")
}
}
chalk_ir::FloatTy::F32 => {
let it = f32::from_le_bytes(b.try_into().unwrap());
write!(f, "{it:?}")
@ -553,6 +568,17 @@ fn render_const_scalar(
let it = f64::from_le_bytes(b.try_into().unwrap());
write!(f, "{it:?}")
}
chalk_ir::FloatTy::F128 => {
// FIXME(#17451): Replace with builtins once they are stabilised.
let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap()));
let s = it.to_string();
if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
// Match Rust debug formatting
write!(f, "{s}.0")
} else {
write!(f, "{s}")
}
}
},
},
TyKind::Ref(_, _, t) => match t.kind(Interner) {
@ -988,7 +1014,8 @@ impl HirDisplay for Ty {
f.end_location_link();
if parameters.len(Interner) > 0 {
let generics = generics(db.upcast(), def.into());
let generic_def_id = GenericDefId::from_callable(db.upcast(), def);
let generics = generics(db.upcast(), generic_def_id);
let (parent_len, self_param, type_, const_, impl_, lifetime) =
generics.provenance_split();
let parameters = parameters.as_slice(Interner);
@ -1002,8 +1029,9 @@ impl HirDisplay for Ty {
debug_assert_eq!(parent_params.len(), parent_len);
let parent_params =
generic_args_sans_defaults(f, Some(def.into()), parent_params);
let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params);
generic_args_sans_defaults(f, Some(generic_def_id), parent_params);
let fn_params =
generic_args_sans_defaults(f, Some(generic_def_id), fn_params);
write!(f, "<")?;
hir_fmt_generic_arguments(f, parent_params, None)?;
@ -1041,7 +1069,11 @@ impl HirDisplay for Ty {
module_id,
PrefixKind::Plain,
false,
ImportPathConfig { prefer_no_std: false, prefer_prelude: true },
ImportPathConfig {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
},
) {
write!(f, "{}", path.display(f.db.upcast()))?;
} else {

View file

@ -2,8 +2,8 @@
//!
//! The layout for generics as expected by chalk are as follows:
//! - Optional Self parameter
//! - Type or Const parameters
//! - Lifetime parameters
//! - Type or Const parameters
//! - Parent parameters
//!
//! where parent follows the same scheme.
@ -20,18 +20,23 @@ use hir_def::{
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
use intern::Interned;
use itertools::chain;
use stdx::TupleExt;
use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
Generics { def, params: db.generic_params(def), parent_generics }
let params = db.generic_params(def);
let has_trait_self_param = params.trait_self_param().is_some();
Generics { def, params, parent_generics, has_trait_self_param }
}
#[derive(Clone, Debug)]
pub(crate) struct Generics {
def: GenericDefId,
params: Interned<GenericParams>,
parent_generics: Option<Box<Generics>>,
has_trait_self_param: bool,
}
impl<T> ops::Index<T> for Generics
@ -57,7 +62,7 @@ impl Generics {
self.iter_self().map(|(id, _)| id)
}
fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
self.iter_parent().map(|(id, _)| id)
}
@ -67,6 +72,12 @@ impl Generics {
self.params.iter_type_or_consts()
}
pub(crate) fn iter_self_type_or_consts_id(
&self,
) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head)
}
/// Iterate over the params followed by the parent params.
pub(crate) fn iter(
&self,
@ -78,10 +89,9 @@ impl Generics {
pub(crate) fn iter_self(
&self,
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
self.params
.iter_type_or_consts()
.map(from_toc_id(self))
.chain(self.params.iter_lt().map(from_lt_id(self)))
let mut toc = self.params.iter_type_or_consts().map(from_toc_id(self));
let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten();
chain!(trait_self_param, self.params.iter_lt().map(from_lt_id(self)), toc)
}
/// Iterator over types and const params of parent.
@ -89,8 +99,9 @@ impl Generics {
&self,
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
self.parent_generics().into_iter().flat_map(|it| {
let lt_iter = it.params.iter_lt().map(from_lt_id(it));
it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter)
let mut toc = it.params.iter_type_or_consts().map(from_toc_id(it));
let trait_self_param = it.has_trait_self_param.then(|| toc.next()).flatten();
chain!(trait_self_param, it.params.iter_lt().map(from_lt_id(it)), toc)
})
}
@ -134,8 +145,11 @@ impl Generics {
fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> {
if param.parent == self.def {
let idx = param.local_id.into_raw().into_u32() as usize;
debug_assert!(idx <= self.params.type_or_consts.len());
Some(idx)
debug_assert!(idx <= self.params.len_type_or_consts());
if self.params.trait_self_param() == Some(param.local_id) {
return Some(idx);
}
Some(self.params.len_lifetimes() + idx)
} else {
debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent));
self.parent_generics()
@ -152,8 +166,8 @@ impl Generics {
fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> {
if lifetime.parent == self.def {
let idx = lifetime.local_id.into_raw().into_u32() as usize;
debug_assert!(idx <= self.params.lifetimes.len());
Some(self.params.type_or_consts.len() + idx)
debug_assert!(idx <= self.params.len_lifetimes());
Some(self.params.trait_self_param().is_some() as usize + idx)
} else {
debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent));
self.parent_generics()
@ -216,7 +230,6 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
GenericDefId::FunctionId(it) => it.lookup(db).container,
GenericDefId::TypeAliasId(it) => it.lookup(db).container,
GenericDefId::ConstId(it) => it.lookup(db).container,
GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()),
GenericDefId::AdtId(_)
| GenericDefId::TraitId(_)
| GenericDefId::ImplId(_)

View file

@ -701,18 +701,23 @@ impl<'a> InferenceContext<'a> {
table.propagate_diverging_flag();
for ty in type_of_expr.values_mut() {
*ty = table.resolve_completely(ty.clone());
*has_errors = *has_errors || ty.contains_unknown();
}
for ty in type_of_pat.values_mut() {
*ty = table.resolve_completely(ty.clone());
*has_errors = *has_errors || ty.contains_unknown();
}
for ty in type_of_binding.values_mut() {
*ty = table.resolve_completely(ty.clone());
*has_errors = *has_errors || ty.contains_unknown();
}
for ty in type_of_rpit.values_mut() {
*ty = table.resolve_completely(ty.clone());
*has_errors = *has_errors || ty.contains_unknown();
}
for ty in type_of_for_iterator.values_mut() {
*ty = table.resolve_completely(ty.clone());
*has_errors = *has_errors || ty.contains_unknown();
}
*has_errors = !type_mismatches.is_empty();
@ -835,11 +840,7 @@ impl<'a> InferenceContext<'a> {
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
// RPIT opaque types use substitution of their parent function.
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
let result = self.insert_inference_vars_for_impl_trait(
return_ty,
rpits.clone(),
fn_placeholders,
);
let result = self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders);
let rpits = rpits.skip_binders();
for (id, _) in rpits.impl_traits.iter() {
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
@ -862,12 +863,7 @@ impl<'a> InferenceContext<'a> {
self.insert_atpit_coercion_table(params_and_ret_tys.iter());
}
fn insert_inference_vars_for_impl_trait<T>(
&mut self,
t: T,
rpits: Arc<chalk_ir::Binders<crate::ImplTraits>>,
placeholders: Substitution,
) -> T
fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T
where
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
{
@ -878,13 +874,21 @@ impl<'a> InferenceContext<'a> {
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
_ => return ty,
};
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
ImplTraitId::AssociatedTypeImplTrait(_, idx) => idx,
_ => unreachable!(),
let (impl_traits, idx) =
match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
ImplTraitId::ReturnTypeImplTrait(def, idx) => {
(self.db.return_type_impl_traits(def), idx)
}
ImplTraitId::AssociatedTypeImplTrait(def, idx) => {
(self.db.type_alias_impl_traits(def), idx)
}
_ => unreachable!(),
};
let Some(impl_traits) = impl_traits else {
return ty;
};
let bounds =
(*rpits).map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter()));
let bounds = (*impl_traits)
.map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter()));
let var = self.table.new_type_var();
let var_subst = Substitution::from1(Interner, var.clone());
for bound in bounds {
@ -892,11 +896,8 @@ impl<'a> InferenceContext<'a> {
let (var_predicate, binders) =
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
let var_predicate = self.insert_inference_vars_for_impl_trait(
var_predicate,
rpits.clone(),
placeholders.clone(),
);
let var_predicate = self
.insert_inference_vars_for_impl_trait(var_predicate, placeholders.clone());
self.push_obligation(var_predicate.cast(Interner));
}
self.result.type_of_rpit.insert(idx, var.clone());
@ -983,16 +984,8 @@ impl<'a> InferenceContext<'a> {
self.db.lookup_intern_impl_trait_id(opaque_ty_id.into())
{
if assoc_tys.contains(&alias_id) {
let atpits = self
.db
.type_alias_impl_traits(alias_id)
.expect("Marked as ATPIT but no impl traits!");
let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
let ty = self.insert_inference_vars_for_impl_trait(
ty,
atpits,
alias_placeholders,
);
let ty = self.insert_inference_vars_for_impl_trait(ty, alias_placeholders);
return Some((opaque_ty_id, ty));
}
}

View file

@ -13,7 +13,7 @@ use hir_def::{
},
lang_item::{LangItem, LangItemTarget},
path::{GenericArgs, Path},
BlockId, FieldId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
};
use hir_expand::name::{name, Name};
use stdx::always;
@ -440,7 +440,8 @@ impl InferenceContext<'_> {
let ty = match self.infer_path(p, tgt_expr.into()) {
Some(ty) => ty,
None => {
if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident()) {
if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self())
{
self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
expr: tgt_expr,
});
@ -1895,7 +1896,8 @@ impl InferenceContext<'_> {
let callable_ty = self.resolve_ty_shallow(callable_ty);
if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
let def: CallableDefId = from_chalk(self.db, *fn_def);
let generic_predicates = self.db.generic_predicates(def.into());
let generic_predicates =
self.db.generic_predicates(GenericDefId::from_callable(self.db.upcast(), def));
for predicate in generic_predicates.iter() {
let (predicate, binders) = predicate
.clone()

View file

@ -41,14 +41,7 @@ impl InferenceContext<'_> {
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
let value_def = match value {
ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
Some(ty) => return Some(ValuePathResolution::NonGeneric(ty.clone())),
None => {
never!("uninferred pattern?");
return None;
}
},
let value_def: ValueTyDefId = match value {
ValueNs::FunctionId(it) => it.into(),
ValueNs::ConstId(it) => it.into(),
ValueNs::StaticId(it) => it.into(),
@ -62,48 +55,79 @@ impl InferenceContext<'_> {
it.into()
}
ValueNs::LocalBinding(pat) => {
return match self.result.type_of_binding.get(pat) {
Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())),
None => {
never!("uninferred pattern?");
None
}
}
}
ValueNs::ImplSelf(impl_id) => {
let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
let substs = generics.placeholder_subst(self.db);
let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
return Some(ValuePathResolution::GenericDef(
return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
Some(ValuePathResolution::GenericDef(
struct_id.into(),
struct_id.into(),
substs.clone(),
));
))
} else {
// FIXME: report error, invalid Self reference
return None;
}
None
};
}
ValueNs::GenericParam(it) => {
return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it)))
}
};
let generic_def_id = value_def.to_generic_def_id(self.db);
let Some(generic_def) = generic_def_id else {
// `value_def` is the kind of item that can never be generic (i.e. statics, at least
// currently). We can just skip the binders to get its type.
let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",);
return Some(ValuePathResolution::NonGeneric(ty));
};
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let substs = ctx.substs_from_path(path, value_def, true);
let substs = substs.as_slice(Interner);
if let ValueNs::EnumVariantId(_) = value {
let mut it = self_subst
.as_ref()
.map_or(&[][..], |s| s.as_slice(Interner))
.iter()
.chain(substs)
.cloned();
let builder = TyBuilder::subst_for_def(self.db, generic_def, None);
let substs = builder
.fill(|x| {
it.next().unwrap_or_else(|| match x {
ParamKind::Type => {
self.result.standard_types.unknown.clone().cast(Interner)
}
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
})
})
.build();
return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs));
}
let parent_substs = self_subst.or_else(|| {
let generics = generics(self.db.upcast(), value_def.to_generic_def_id()?);
let generics = generics(self.db.upcast(), generic_def_id?);
let parent_params_len = generics.parent_generics()?.len();
let parent_args = &substs[substs.len() - parent_params_len..];
Some(Substitution::from_iter(Interner, parent_args))
});
let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
let Some(generic_def) = value_def.to_generic_def_id() else {
// `value_def` is the kind of item that can never be generic (i.e. statics, at least
// currently). We can just skip the binders to get its type.
let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
stdx::always!(
parent_substs.is_none() && binders.is_empty(Interner),
"non-empty binders for non-generic def",
);
return Some(ValuePathResolution::NonGeneric(ty));
};
let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs);
let substs = builder
.fill(|x| {

View file

@ -265,8 +265,10 @@ pub fn layout_of_ty_query(
chalk_ir::Scalar::Float(f) => scalar(
dl,
Primitive::Float(match f {
FloatTy::F16 => Float::F16,
FloatTy::F32 => Float::F32,
FloatTy::F64 => Float::F64,
FloatTy::F128 => Float::F128,
}),
),
},

View file

@ -426,6 +426,7 @@ fn enums() {
#[test]
fn primitives() {
// FIXME(#17451): Add `f16` and `f128` once they are stabilised.
size_and_align! {
struct Goal(i32, i128, isize, usize, f32, f64, bool, char);
}

View file

@ -1,6 +1,6 @@
//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
#![warn(rust_2018_idioms, unused_lifetimes)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[cfg(feature = "in-rust-tree")]
@ -60,7 +60,7 @@ use chalk_ir::{
NoSolution,
};
use either::Either;
use hir_def::{hir::ExprId, type_ref::Rawness, GeneralConstId, TypeOrConstParamId};
use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId};
use hir_expand::name;
use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
@ -84,8 +84,8 @@ pub use infer::{
};
pub use interner::Interner;
pub use lower::{
associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, ParamLoweringMode,
TyDefId, TyLoweringContext, ValueTyDefId,
associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId,
TyLoweringContext, ValueTyDefId,
};
pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,

View file

@ -11,10 +11,7 @@ use std::{
ops::{self, Not as _},
};
use base_db::{
salsa::{Cycle, InternValueTrivial},
CrateId,
};
use base_db::{salsa::Cycle, CrateId};
use chalk_ir::{
cast::Cast,
fold::{Shift, TypeFoldable},
@ -38,10 +35,10 @@ use hir_def::{
type_ref::{
ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
},
AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId,
Lookup, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
UnionId, VariantId,
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
TypeOwnerId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
use intern::Interned;
@ -387,14 +384,18 @@ impl<'a> TyLoweringContext<'a> {
type_params,
const_params,
_impl_trait_params,
_lifetime_params,
lifetime_params,
) = self
.generics()
.expect("variable impl trait lowering must be in a generic def")
.provenance_split();
TyKind::BoundVar(BoundVar::new(
self.in_binders,
idx as usize + self_param as usize + type_params + const_params,
idx as usize
+ self_param as usize
+ type_params
+ const_params
+ lifetime_params,
))
.intern(Interner)
}
@ -815,13 +816,13 @@ impl<'a> TyLoweringContext<'a> {
infer_args: bool,
explicit_self_ty: Option<Ty>,
) -> Substitution {
// Remember that the item's own generic args come before its parent's.
let mut substs = Vec::new();
let def = if let Some(d) = def {
d
} else {
return Substitution::empty(Interner);
};
let Some(def) = def else { return Substitution::empty(Interner) };
// Order is
// - Optional Self parameter
// - Lifetime parameters
// - Type or Const parameters
// - Parent parameters
let def_generics = generics(self.db.upcast(), def);
let (
parent_params,
@ -835,130 +836,121 @@ impl<'a> TyLoweringContext<'a> {
self_param as usize + type_params + const_params + impl_trait_params + lifetime_params;
let total_len = parent_params + item_len;
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
let mut substs = Vec::new();
let mut def_generic_iter = def_generics.iter_id();
// we need to iterate the lifetime and type/const params separately as our order of them
// differs from the supplied syntax
let fill_self_params = || {
let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
let fill_self_param = || {
if self_param {
let self_ty =
explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone());
let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
if let Some(id) = def_generic_iter.next() {
assert!(matches!(
id,
GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
));
if let Some(id) = def_toc_iter.next() {
assert!(matches!(id, GenericParamId::TypeParamId(_)));
substs.push(self_ty);
}
}
};
let mut had_explicit_args = false;
if let Some(generic_args) = &args_and_bindings {
if !generic_args.has_self_type {
fill_self_params();
}
let expected_num = if generic_args.has_self_type {
self_param as usize + type_params + const_params
if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
// Fill in the self param first
if has_self_type && self_param {
had_explicit_args = true;
if let Some(id) = def_toc_iter.next() {
assert!(matches!(id, GenericParamId::TypeParamId(_)));
had_explicit_args = true;
if let GenericArg::Type(ty) = &args[0] {
substs.push(self.lower_ty(ty).cast(Interner));
}
}
} else {
type_params + const_params
fill_self_param()
};
let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 };
// if args are provided, it should be all of them, but we can't rely on that
for arg in generic_args
.args
// Then fill in the supplied lifetime args, or error lifetimes if there are too few
// (default lifetimes aren't a thing)
for arg in args
.iter()
.filter_map(|arg| match arg {
GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)),
_ => None,
})
.chain(iter::repeat(error_lifetime()))
.take(lifetime_params)
{
substs.push(arg.cast(Interner));
}
let skip = if has_self_type { 1 } else { 0 };
// Fill in supplied type and const args
// Note if non-lifetime args are provided, it should be all of them, but we can't rely on that
for (arg, id) in args
.iter()
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.skip(skip)
.take(expected_num)
.take(type_params + const_params)
.zip(def_toc_iter)
{
if let Some(id) = def_generic_iter.next() {
let arg = generic_arg_to_chalk(
self.db,
id,
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
);
had_explicit_args = true;
substs.push(arg);
}
}
for arg in generic_args
.args
.iter()
.filter(|arg| matches!(arg, GenericArg::Lifetime(_)))
.take(lifetime_params)
{
// Taking into the fact that def_generic_iter will always have lifetimes at the end
// Should have some test cases tho to test this behaviour more properly
if let Some(id) = def_generic_iter.next() {
let arg = generic_arg_to_chalk(
self.db,
id,
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
);
had_explicit_args = true;
substs.push(arg);
}
had_explicit_args = true;
let arg = generic_arg_to_chalk(
self.db,
id,
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
);
substs.push(arg);
}
} else {
fill_self_params();
fill_self_param();
}
// These params include those of parent.
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
.map(|id| match id {
GenericParamId::ConstParamId(x) => {
unknown_const_as_generic(self.db.const_param_ty(x))
}
GenericParamId::TypeParamId(_) => ty_error.clone(),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
})
.collect();
assert_eq!(remaining_params.len() + substs.len(), total_len);
let param_to_err = |id| match id {
GenericParamId::ConstParamId(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
GenericParamId::TypeParamId(_) => ty_error(),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
};
// handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used).
// Generic parameters for associated types are not supposed to have defaults, so we just
// ignore them.
let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
let container = id.lookup(self.db.upcast()).container;
matches!(container, ItemContainerId::TraitId(_))
} else {
false
let is_assoc_ty = || match def {
GenericDefId::TypeAliasId(id) => {
matches!(id.lookup(self.db.upcast()).container, ItemContainerId::TraitId(_))
}
_ => false,
};
if !is_assoc_ty && (!infer_args || had_explicit_args) {
let defaults = self.db.generic_defaults(def);
assert_eq!(total_len, defaults.len());
let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
if fill_defaults {
let defaults = &*self.db.generic_defaults(def);
let (item, _parent) = defaults.split_at(item_len);
let parent_from = item_len - substs.len();
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
let mut rem =
def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
// Fill in defaults for type/const params
for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
// each default can depend on the previous parameters
let substs_so_far = Substitution::from_iter(
Interner,
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
substs.iter().cloned().chain(rem[idx..].iter().cloned()),
);
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
}
// Keep parent's params as unknown.
let mut remaining_params = remaining_params;
substs.extend(remaining_params.drain(parent_from..));
// Fill in remaining parent params
substs.extend(rem.drain(parent_from..));
} else {
substs.extend(remaining_params);
// Fill in remaining def params and parent params
substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
}
assert_eq!(substs.len(), total_len);
assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len());
Substitution::from_iter(Interner, substs)
}
@ -1535,7 +1527,7 @@ pub(crate) fn generic_predicates_for_param_query(
def: GenericDefId,
param_id: TypeOrConstParamId,
assoc_name: Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
) -> GenericPredicates {
let resolver = def.resolver(db.upcast());
let ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, def.into())
@ -1611,7 +1603,7 @@ pub(crate) fn generic_predicates_for_param_query(
);
};
}
predicates.into()
GenericPredicates(predicates.is_empty().not().then(|| predicates.into()))
}
pub(crate) fn generic_predicates_for_param_recover(
@ -1620,15 +1612,15 @@ pub(crate) fn generic_predicates_for_param_recover(
_def: &GenericDefId,
_param_id: &TypeOrConstParamId,
_assoc_name: &Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
Arc::from_iter(None)
) -> GenericPredicates {
GenericPredicates(None)
}
pub(crate) fn trait_environment_for_body_query(
db: &dyn HirDatabase,
def: DefWithBodyId,
) -> Arc<TraitEnvironment> {
let Some(def) = def.as_generic_def_id() else {
let Some(def) = def.as_generic_def_id(db.upcast()) else {
let krate = def.module(db.upcast()).krate();
return TraitEnvironment::empty(krate);
};
@ -1725,8 +1717,8 @@ pub(crate) fn generic_predicates_query(
})
.collect::<Vec<_>>();
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
if !subst.is_empty(Interner) {
if generics.len() > 0 {
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
if let Some(implicitly_sized_predicates) =
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
@ -1995,47 +1987,6 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CallableDefId {
FunctionId(FunctionId),
StructId(StructId),
EnumVariantId(EnumVariantId),
}
impl InternValueTrivial for CallableDefId {}
impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
impl From<CallableDefId> for ModuleDefId {
fn from(def: CallableDefId) -> ModuleDefId {
match def {
CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
}
}
}
impl CallableDefId {
pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
let db = db.upcast();
match self {
CallableDefId::FunctionId(f) => f.krate(db),
CallableDefId::StructId(s) => s.krate(db),
CallableDefId::EnumVariantId(e) => e.krate(db),
}
}
}
impl From<CallableDefId> for GenericDefId {
fn from(def: CallableDefId) -> GenericDefId {
match def {
CallableDefId::FunctionId(f) => f.into(),
CallableDefId::StructId(s) => s.into(),
CallableDefId::EnumVariantId(e) => e.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TyDefId {
BuiltinType(BuiltinType),
@ -2056,12 +2007,12 @@ pub enum ValueTyDefId {
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
impl ValueTyDefId {
pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> Option<GenericDefId> {
match self {
Self::FunctionId(id) => Some(id.into()),
Self::StructId(id) => Some(id.into()),
Self::UnionId(id) => Some(id.into()),
Self::EnumVariantId(var) => Some(var.into()),
Self::EnumVariantId(var) => Some(var.lookup(db.upcast()).parent.into()),
Self::ConstId(id) => Some(id.into()),
Self::StaticId(_) => None,
}
@ -2112,7 +2063,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
// returns None if def is a type arg
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
let parent_data = db.generic_params(def.parent());
let data = &parent_data.type_or_consts[def.local_id()];
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.parent().into());
match data {

View file

@ -127,9 +127,11 @@ pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)),
];
pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 4] = [
TyFingerprint::Scalar(Scalar::Float(FloatTy::F16)),
TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)),
TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
TyFingerprint::Scalar(Scalar::Float(FloatTy::F128)),
];
type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>;
@ -1322,7 +1324,7 @@ fn iterate_inherent_methods(
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
for &impl_id in impls.for_self_ty(self_ty) {
for &item in &table.db.impl_data(impl_id).items {
for &item in table.db.impl_data(impl_id).items.iter() {
let visible = match is_valid_impl_method_candidate(
table,
self_ty,

View file

@ -18,6 +18,10 @@ use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile};
use intern::Interned;
use la_arena::ArenaMap;
use rustc_abi::TargetDataLayout;
use rustc_apfloat::{
ieee::{Half as f16, Quad as f128},
Float,
};
use rustc_hash::{FxHashMap, FxHashSet};
use stdx::never;
use syntax::{SyntaxNodePtr, TextRange};
@ -55,6 +59,13 @@ macro_rules! from_bytes {
Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())),
}))
};
($apfloat:tt, $bits:tt, $value:expr) => {
// FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable.
$apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() {
Ok(it) => it,
Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())),
}).into())
};
}
macro_rules! not_supported {
@ -1110,6 +1121,10 @@ impl Evaluator<'_> {
}
if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) {
match f {
chalk_ir::FloatTy::F16 => {
let c = -from_bytes!(f16, u16, c);
Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into())
}
chalk_ir::FloatTy::F32 => {
let c = -from_bytes!(f32, c);
Owned(c.to_le_bytes().into())
@ -1118,6 +1133,10 @@ impl Evaluator<'_> {
let c = -from_bytes!(f64, c);
Owned(c.to_le_bytes().into())
}
chalk_ir::FloatTy::F128 => {
let c = -from_bytes!(f128, u128, c);
Owned(c.to_bits().to_le_bytes().into())
}
}
} else {
let mut c = c.to_vec();
@ -1169,6 +1188,39 @@ impl Evaluator<'_> {
}
if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) {
match f {
chalk_ir::FloatTy::F16 => {
let l = from_bytes!(f16, u16, lc);
let r = from_bytes!(f16, u16, rc);
match op {
BinOp::Ge
| BinOp::Gt
| BinOp::Le
| BinOp::Lt
| BinOp::Eq
| BinOp::Ne => {
let r = op.run_compare(l, r) as u8;
Owned(vec![r])
}
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
let r = match op {
BinOp::Add => l + r,
BinOp::Sub => l - r,
BinOp::Mul => l * r,
BinOp::Div => l / r,
_ => unreachable!(),
};
Owned(
u16::try_from(r.value.to_bits())
.unwrap()
.to_le_bytes()
.into(),
)
}
it => not_supported!(
"invalid binop {it:?} on floating point operators"
),
}
}
chalk_ir::FloatTy::F32 => {
let l = from_bytes!(f32, lc);
let r = from_bytes!(f32, rc);
@ -1225,6 +1277,34 @@ impl Evaluator<'_> {
),
}
}
chalk_ir::FloatTy::F128 => {
let l = from_bytes!(f128, u128, lc);
let r = from_bytes!(f128, u128, rc);
match op {
BinOp::Ge
| BinOp::Gt
| BinOp::Le
| BinOp::Lt
| BinOp::Eq
| BinOp::Ne => {
let r = op.run_compare(l, r) as u8;
Owned(vec![r])
}
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
let r = match op {
BinOp::Add => l + r,
BinOp::Sub => l - r,
BinOp::Mul => l * r,
BinOp::Div => l / r,
_ => unreachable!(),
};
Owned(r.value.to_bits().to_le_bytes().into())
}
it => not_supported!(
"invalid binop {it:?} on floating point operators"
),
}
}
}
} else {
let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));

View file

@ -627,6 +627,7 @@ impl Evaluator<'_> {
if let Some(name) = name.strip_prefix("atomic_") {
return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span);
}
// FIXME(#17451): Add `f16` and `f128` intrinsics.
if let Some(name) = name.strip_suffix("f64") {
let result = match name {
"sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs"

View file

@ -19,6 +19,7 @@ use hir_def::{
};
use hir_expand::name::Name;
use la_arena::ArenaMap;
use rustc_apfloat::Float;
use rustc_hash::FxHashMap;
use syntax::TextRange;
use triomphe::Arc;
@ -183,7 +184,7 @@ impl MirLowerError {
},
MirLowerError::GenericArgNotProvided(id, subst) => {
let parent = id.parent;
let param = &db.generic_params(parent).type_or_consts[id.local_id];
let param = &db.generic_params(parent)[id.local_id];
writeln!(
f,
"Generic arg not provided for {}",
@ -483,7 +484,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
Ok(Some(current))
}
ValueNs::GenericParam(p) => {
let Some(def) = self.owner.as_generic_def_id() else {
let Some(def) = self.owner.as_generic_def_id(self.db.upcast()) else {
not_supported!("owner without generic def id");
};
let gen = generics(self.db.upcast(), def);
@ -1330,7 +1331,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
fn placeholder_subst(&mut self) -> Substitution {
match self.owner.as_generic_def_id() {
match self.owner.as_generic_def_id(self.db.upcast()) {
Some(it) => TyBuilder::placeholder_subst(self.db, it),
None => Substitution::empty(Interner),
}
@ -1432,10 +1433,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),
hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]),
hir_def::hir::Literal::Float(f, _) => match size()? {
8 => Box::new(f.into_f64().to_le_bytes()),
4 => Box::new(f.into_f32().to_le_bytes()),
16 => Box::new(f.to_f128().to_bits().to_le_bytes()),
8 => Box::new(f.to_f64().to_le_bytes()),
4 => Box::new(f.to_f32().to_le_bytes()),
2 => Box::new(u16::try_from(f.to_f16().to_bits()).unwrap().to_le_bytes()),
_ => {
return Err(MirLowerError::TypeError("float with size other than 4 or 8 bytes"))
return Err(MirLowerError::TypeError(
"float with size other than 2, 4, 8 or 16 bytes",
))
}
},
};
@ -2160,9 +2165,7 @@ pub fn lower_to_mir(
root_expr: ExprId,
) -> Result<MirBody> {
if infer.has_errors {
return Err(MirLowerError::TypeMismatch(
infer.type_mismatches().next().map(|(_, it)| it.clone()),
));
return Err(MirLowerError::TypeMismatch(None));
}
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
// 0 is return local

View file

@ -302,7 +302,7 @@ pub fn monomorphized_mir_body_query(
subst: Substitution,
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError> {
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
let body = db.mir_body(owner)?;
let mut body = (*body).clone();
@ -327,7 +327,7 @@ pub fn monomorphized_mir_body_for_closure_query(
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError> {
let InternedClosure(owner, _) = db.lookup_intern_closure(closure.into());
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
let body = db.mir_body_for_closure(closure)?;
let mut body = (*body).clone();
@ -343,7 +343,7 @@ pub fn monomorphize_mir_body_bad(
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<MirBody, MirLowerError> {
let owner = body.owner;
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
filler.fill_body(&mut body)?;
Ok(body)

View file

@ -27,8 +27,10 @@ pub fn uint_ty_to_string(ty: UintTy) -> &'static str {
pub fn float_ty_to_string(ty: FloatTy) -> &'static str {
match ty {
FloatTy::F16 => "f16",
FloatTy::F32 => "f32",
FloatTy::F64 => "f64",
FloatTy::F128 => "f128",
}
}
@ -56,7 +58,9 @@ pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy {
pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy {
match t {
BuiltinFloat::F16 => FloatTy::F16,
BuiltinFloat::F32 => FloatTy::F32,
BuiltinFloat::F64 => FloatTy::F64,
BuiltinFloat::F128 => FloatTy::F128,
}
}

View file

@ -111,8 +111,10 @@ fn infer_literal_pattern() {
if let "foo" = any() {}
if let 1 = any() {}
if let 1u32 = any() {}
if let 1f16 = any() {}
if let 1f32 = any() {}
if let 1.0 = any() {}
if let 1f128 = any() {}
if let true = any() {}
}
"#,
@ -121,7 +123,7 @@ fn infer_literal_pattern() {
19..26 'loop {}': !
24..26 '{}': ()
37..38 'x': &'? i32
46..208 '{ ...) {} }': ()
46..263 '{ ...) {} }': ()
52..75 'if let...y() {}': ()
55..72 'let "f... any()': bool
59..64 '"foo"': &'static str
@ -145,25 +147,39 @@ fn infer_literal_pattern() {
124..126 '{}': ()
131..153 'if let...y() {}': ()
134..150 'let 1f... any()': bool
138..142 '1f32': f32
138..142 '1f32': f32
145..148 'any': fn any<f32>() -> f32
145..150 'any()': f32
138..142 '1f16': f16
138..142 '1f16': f16
145..148 'any': fn any<f16>() -> f16
145..150 'any()': f16
151..153 '{}': ()
158..179 'if let...y() {}': ()
161..176 'let 1.0 = any()': bool
165..168 '1.0': f64
165..168 '1.0': f64
171..174 'any': fn any<f64>() -> f64
171..176 'any()': f64
177..179 '{}': ()
184..206 'if let...y() {}': ()
187..203 'let tr... any()': bool
191..195 'true': bool
191..195 'true': bool
198..201 'any': fn any<bool>() -> bool
198..203 'any()': bool
158..180 'if let...y() {}': ()
161..177 'let 1f... any()': bool
165..169 '1f32': f32
165..169 '1f32': f32
172..175 'any': fn any<f32>() -> f32
172..177 'any()': f32
178..180 '{}': ()
185..206 'if let...y() {}': ()
188..203 'let 1.0 = any()': bool
192..195 '1.0': f64
192..195 '1.0': f64
198..201 'any': fn any<f64>() -> f64
198..203 'any()': f64
204..206 '{}': ()
211..234 'if let...y() {}': ()
214..231 'let 1f... any()': bool
218..223 '1f128': f128
218..223 '1f128': f128
226..229 'any': fn any<f128>() -> f128
226..231 'any()': f128
232..234 '{}': ()
239..261 'if let...y() {}': ()
242..258 'let tr... any()': bool
246..250 'true': bool
246..250 'true': bool
253..256 'any': fn any<bool>() -> bool
253..258 'any()': bool
259..261 '{}': ()
"#]],
);
}

View file

@ -1999,3 +1999,45 @@ where
"#,
);
}
#[test]
fn tait_async_stack_overflow_17199() {
check_types(
r#"
//- minicore: fmt, future
type Foo = impl core::fmt::Debug;
async fn foo() -> Foo {
()
}
async fn test() {
let t = foo().await;
// ^ impl Debug
}
"#,
);
}
#[test]
fn lifetime_params_move_param_defaults() {
check_types(
r#"
pub struct Thing<'s, T = u32>;
impl <'s> Thing<'s> {
pub fn new() -> Thing<'s> {
Thing
//^^^^^ Thing<'?, u32>
}
}
fn main() {
let scope =
//^^^^^ &'? Thing<'?, u32>
&Thing::new();
//^^^^^^^^^^^^ Thing<'?, u32>
}
"#,
);
}

View file

@ -397,8 +397,10 @@ fn infer_literals() {
r##"
fn test() {
5i32;
5f16;
5f32;
5f64;
5f128;
"hello";
b"bytes";
'c';
@ -421,26 +423,28 @@ h";
}
"##,
expect![[r##"
18..478 '{ ... }': ()
18..515 '{ ... }': ()
32..36 '5i32': i32
50..54 '5f32': f32
68..72 '5f64': f64
86..93 '"hello"': &'static str
107..115 'b"bytes"': &'static [u8; 5]
129..132 ''c'': char
146..150 'b'b'': u8
164..168 '3.14': f64
182..186 '5000': i32
200..205 'false': bool
219..223 'true': bool
237..333 'r#" ... "#': &'static str
347..357 'br#"yolo"#': &'static [u8; 4]
375..376 'a': &'static [u8; 4]
379..403 'b"a\x2... c"': &'static [u8; 4]
421..422 'b': &'static [u8; 4]
425..433 'br"g\ h"': &'static [u8; 4]
451..452 'c': &'static [u8; 6]
455..467 'br#"x"\"yb"#': &'static [u8; 6]
50..54 '5f16': f16
68..72 '5f32': f32
86..90 '5f64': f64
104..109 '5f128': f128
123..130 '"hello"': &'static str
144..152 'b"bytes"': &'static [u8; 5]
166..169 ''c'': char
183..187 'b'b'': u8
201..205 '3.14': f64
219..223 '5000': i32
237..242 'false': bool
256..260 'true': bool
274..370 'r#" ... "#': &'static str
384..394 'br#"yolo"#': &'static [u8; 4]
412..413 'a': &'static [u8; 4]
416..440 'b"a\x2... c"': &'static [u8; 4]
458..459 'b': &'static [u8; 4]
462..470 'br"g\ h"': &'static [u8; 4]
488..489 'c': &'static [u8; 6]
492..504 'br#"x"\"yb"#': &'static [u8; 6]
"##]],
);
}

View file

@ -4824,3 +4824,76 @@ fn foo() {
"#,
)
}
#[test]
fn nested_impl_traits() {
check_infer(
r#"
//- minicore: fn
trait Foo {}
trait Bar<T> {}
trait Baz {
type Assoc;
}
struct Qux<T> {
qux: T,
}
struct S;
impl Foo for S {}
fn not_allowed1(f: impl Fn(impl Foo)) {
let foo = S;
f(foo);
}
// This caused stack overflow in #17498
fn not_allowed2(f: impl Fn(&impl Foo)) {
let foo = S;
f(&foo);
}
fn not_allowed3(bar: impl Bar<impl Foo>) {}
// This also caused stack overflow
fn not_allowed4(bar: impl Bar<&impl Foo>) {}
fn allowed1(baz: impl Baz<Assoc = impl Foo>) {}
fn allowed2<'a>(baz: impl Baz<Assoc = &'a (impl Foo + 'a)>) {}
fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
"#,
expect![[r#"
139..140 'f': impl Fn({unknown}) + ?Sized
161..193 '{ ...oo); }': ()
171..174 'foo': S
177..178 'S': S
184..185 'f': impl Fn({unknown}) + ?Sized
184..190 'f(foo)': ()
186..189 'foo': S
251..252 'f': impl Fn(&'? {unknown}) + ?Sized
274..307 '{ ...oo); }': ()
284..287 'foo': S
290..291 'S': S
297..298 'f': impl Fn(&'? {unknown}) + ?Sized
297..304 'f(&foo)': ()
299..303 '&foo': &'? S
300..303 'foo': S
325..328 'bar': impl Bar<{unknown}> + ?Sized
350..352 '{}': ()
405..408 'bar': impl Bar<&'? {unknown}> + ?Sized
431..433 '{}': ()
447..450 'baz': impl Baz<Assoc = impl Foo + ?Sized> + ?Sized
480..482 '{}': ()
500..503 'baz': impl Baz<Assoc = &'a impl Foo + 'a + ?Sized> + ?Sized
544..546 '{}': ()
560..563 'baz': impl Baz<Assoc = Qux<impl Foo + ?Sized>> + ?Sized
598..600 '{}': ()
"#]],
)
}

View file

@ -157,8 +157,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
let generic_params = db.generic_params(trait_.into());
let trait_self = generic_params.trait_self_param();
generic_params
.where_predicates
.iter()
.where_predicates()
.filter_map(|pred| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {

View file

@ -452,7 +452,7 @@ impl HirDisplay for TypeOrConstParam {
impl HirDisplay for TypeParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let params = f.db.generic_params(self.id.parent());
let param_data = &params.type_or_consts[self.id.local_id()];
let param_data = &params[self.id.local_id()];
let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
let krate = self.id.parent().krate(f.db).id;
let ty =
@ -539,11 +539,10 @@ fn write_generic_params(
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
let params = f.db.generic_params(def);
if params.lifetimes.is_empty()
&& params.type_or_consts.iter().all(|it| it.1.const_param().is_none())
if params.iter_lt().next().is_none()
&& params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
&& params
.type_or_consts
.iter()
.iter_type_or_consts()
.filter_map(|it| it.1.type_param())
.all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
{
@ -560,11 +559,11 @@ fn write_generic_params(
f.write_str(", ")
}
};
for (_, lifetime) in params.lifetimes.iter() {
for (_, lifetime) in params.iter_lt() {
delim(f)?;
write!(f, "{}", lifetime.name.display(f.db.upcast()))?;
}
for (_, ty) in params.type_or_consts.iter() {
for (_, ty) in params.iter_type_or_consts() {
if let Some(name) = &ty.name() {
match ty {
TypeOrConstParamData::TypeParamData(ty) => {
@ -612,11 +611,11 @@ fn write_where_clause(
}
fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
params.where_predicates.iter().any(|pred| {
params.where_predicates().any(|pred| {
!matches!(
pred,
WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. }
if params.type_or_consts[*id].name().is_none()
if params[*id].name().is_none()
)
})
}
@ -631,13 +630,13 @@ fn write_where_predicates(
let is_unnamed_type_target =
|params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
matches!(target,
WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none()
WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
)
};
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() {
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => write!(f, "{}", name.display(f.db.upcast())),
None => f.write_str("{unnamed}"),
},
@ -653,7 +652,7 @@ fn write_where_predicates(
_ => false,
};
let mut iter = params.where_predicates.iter().peekable();
let mut iter = params.where_predicates().peekable();
while let Some(pred) = iter.next() {
if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) {
continue;

View file

@ -182,7 +182,6 @@ impl From<GenericDef> for GenericDefId {
GenericDef::TraitAlias(it) => GenericDefId::TraitAliasId(it.id),
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()),
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
}
}
@ -197,7 +196,6 @@ impl From<GenericDefId> for GenericDef {
GenericDefId::TraitAliasId(it) => GenericDef::TraitAlias(it.into()),
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()),
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
}
}

View file

@ -5,10 +5,10 @@ use either::Either;
use hir_def::{
nameres::{ModuleOrigin, ModuleSource},
src::{HasChildSource, HasSource as _},
Lookup, MacroId, VariantId,
CallableDefId, Lookup, MacroId, VariantId,
};
use hir_expand::{HirFileId, InFile};
use hir_ty::{db::InternedClosure, CallableDefId};
use hir_ty::db::InternedClosure;
use syntax::ast;
use tt::TextRange;

View file

@ -17,7 +17,6 @@
//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
#![warn(rust_2018_idioms, unused_lifetimes)]
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#![recursion_limit = "512"]
@ -52,11 +51,11 @@ use hir_def::{
path::ImportAlias,
per_ns::PerNs,
resolver::{HasResolver, Resolver},
AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule,
ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId,
TypeParamId, UnionId,
AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId,
DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
MacroExpander, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId,
TypeOrConstParamId, TypeParamId, UnionId,
};
use hir_expand::{
attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
@ -71,7 +70,7 @@ use hir_ty::{
mir::{interpret_mir, MutBorrowKind},
primitive::UintTy,
traits::FnTrait,
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
WhereClause,
@ -666,7 +665,7 @@ impl Module {
}
let parent = impl_def.id.into();
let generic_params = db.generic_params(parent);
let lifetime_params = generic_params.lifetimes.iter().map(|(local_id, _)| {
let lifetime_params = generic_params.iter_lt().map(|(local_id, _)| {
GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id })
});
let type_params = generic_params
@ -760,7 +759,7 @@ impl Module {
impl_assoc_items_scratch.clear();
}
for &item in &db.impl_data(impl_def.id).items {
for &item in db.impl_data(impl_def.id).items.iter() {
AssocItem::from(item).diagnostics(db, acc, style_lints);
}
}
@ -1144,7 +1143,7 @@ impl Field {
let generic_def_id: GenericDefId = match self.parent {
VariantDef::Struct(it) => it.id.into(),
VariantDef::Union(it) => it.id.into(),
VariantDef::Variant(it) => it.id.into(),
VariantDef::Variant(it) => it.id.lookup(db.upcast()).parent.into(),
};
let substs = TyBuilder::placeholder_subst(db, generic_def_id);
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@ -1177,7 +1176,9 @@ impl Field {
db.layout_of_ty(
self.ty(db).ty,
db.trait_environment(match hir_def::VariantId::from(self.parent) {
hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id),
hir_def::VariantId::EnumVariantId(id) => {
GenericDefId::AdtId(id.lookup(db.upcast()).parent.into())
}
hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
}),
@ -1539,8 +1540,7 @@ impl Adt {
resolver
.generic_params()
.and_then(|gp| {
gp.lifetimes
.iter()
gp.iter_lt()
// there should only be a single lifetime
// but `Arena` requires to use an iterator
.nth(0)
@ -2501,9 +2501,8 @@ impl Trait {
db: &dyn HirDatabase,
count_required_only: bool,
) -> usize {
db.generic_params(GenericDefId::from(self.id))
.type_or_consts
.iter()
db.generic_params(self.id.into())
.iter_type_or_consts()
.filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList))
.filter(|(_, ty)| !count_required_only || !ty.has_default())
.count()
@ -2623,6 +2622,13 @@ impl BuiltinType {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
}
pub fn is_f16(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F16)
)
}
pub fn is_f32(&self) -> bool {
matches!(
self.inner,
@ -2637,6 +2643,13 @@ impl BuiltinType {
)
}
pub fn is_f128(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F128)
)
}
pub fn is_char(&self) -> bool {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
}
@ -3107,9 +3120,6 @@ pub enum GenericDef {
TraitAlias(TraitAlias),
TypeAlias(TypeAlias),
Impl(Impl),
// enum variants cannot have generics themselves, but their parent enums
// can, and this makes some code easier to write
Variant(Variant),
// consts can have type parameters from their parents (i.e. associated consts of traits)
Const(Const),
}
@ -3120,7 +3130,6 @@ impl_from!(
TraitAlias,
TypeAlias,
Impl,
Variant,
Const
for GenericDef
);
@ -3128,7 +3137,7 @@ impl_from!(
impl GenericDef {
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
let generics = db.generic_params(self.into());
let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| {
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
match toc.split(db) {
Either::Left(it) => GenericParam::ConstParam(it),
@ -3145,8 +3154,7 @@ impl GenericDef {
pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> {
let generics = db.generic_params(self.into());
generics
.lifetimes
.iter()
.iter_lt()
.map(|(local_id, _)| LifetimeParam {
id: LifetimeParamId { parent: self.into(), local_id },
})
@ -3156,8 +3164,7 @@ impl GenericDef {
pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
let generics = db.generic_params(self.into());
generics
.type_or_consts
.iter()
.iter_type_or_consts()
.map(|(local_id, _)| TypeOrConstParam {
id: TypeOrConstParamId { parent: self.into(), local_id },
})
@ -3499,7 +3506,7 @@ impl TypeParam {
/// argument)?
pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
let params = db.generic_params(self.id.parent());
let data = &params.type_or_consts[self.id.local_id()];
let data = &params[self.id.local_id()];
match data.type_param().unwrap().provenance {
hir_def::generics::TypeParamProvenance::TypeParamList => false,
hir_def::generics::TypeParamProvenance::TraitSelf
@ -3553,7 +3560,7 @@ pub struct LifetimeParam {
impl LifetimeParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
params.lifetimes[self.id.local_id].name.clone()
params[self.id.local_id].name.clone()
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
@ -3577,7 +3584,7 @@ impl ConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent());
match params.type_or_consts[self.id.local_id()].name() {
match params[self.id.local_id()].name() {
Some(it) => it.clone(),
None => {
never!();
@ -3605,9 +3612,9 @@ impl ConstParam {
}
fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> {
let params = db.generic_defaults(id.parent);
let local_idx = hir_ty::param_idx(db, id)?;
let ty = params.get(local_idx)?.clone();
let defaults = db.generic_defaults(id.parent);
let ty = defaults.get(local_idx)?.clone();
let subst = TyBuilder::placeholder_subst(db, id.parent);
Some(ty.substitute(Interner, &subst))
}
@ -3620,7 +3627,7 @@ pub struct TypeOrConstParam {
impl TypeOrConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
match params.type_or_consts[self.id.local_id].name() {
match params[self.id.local_id].name() {
Some(n) => n.clone(),
_ => Name::missing(),
}
@ -3636,7 +3643,7 @@ impl TypeOrConstParam {
pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
let params = db.generic_params(self.id.parent);
match &params.type_or_consts[self.id.local_id] {
match &params[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
}
@ -3655,7 +3662,7 @@ impl TypeOrConstParam {
pub fn as_type_param(self, db: &dyn HirDatabase) -> Option<TypeParam> {
let params = db.generic_params(self.id.parent);
match &params.type_or_consts[self.id.local_id] {
match &params[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
Some(TypeParam { id: TypeParamId::from_unchecked(self.id) })
}
@ -3665,7 +3672,7 @@ impl TypeOrConstParam {
pub fn as_const_param(self, db: &dyn HirDatabase) -> Option<ConstParam> {
let params = db.generic_params(self.id.parent);
match &params.type_or_consts[self.id.local_id] {
match &params[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
Some(ConstParam { id: ConstParamId::from_unchecked(self.id) })
@ -4052,7 +4059,9 @@ impl Type {
ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it),
ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)),
ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)),
ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
ValueTyDefId::EnumVariantId(it) => {
GenericDefId::AdtId(AdtId::EnumId(it.lookup(db.upcast()).parent))
}
ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()),
},
);

View file

@ -68,38 +68,44 @@ impl SourceAnalyzer {
pub(crate) fn new_for_body(
db: &dyn HirDatabase,
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
None => scope_for(&scopes, &source_map, node),
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
};
let resolver = resolver_for_scope(db.upcast(), def, scope);
SourceAnalyzer {
resolver,
def: Some((def, body, source_map)),
infer: Some(db.infer(def)),
file_id,
}
Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
}
pub(crate) fn new_for_body_no_infer(
db: &dyn HirDatabase,
def: DefWithBodyId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
) -> SourceAnalyzer {
Self::new_for_body_(db, def, node, offset, None)
}
pub(crate) fn new_for_body_(
db: &dyn HirDatabase,
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
infer: Option<Arc<InferenceResult>>,
) -> SourceAnalyzer {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
None => scope_for(&scopes, &source_map, node),
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
None => scope_for(db, &scopes, &source_map, node),
Some(offset) => {
debug_assert!(
node.text_range().contains_inclusive(offset),
"{:?} not in {:?}",
offset,
node.text_range()
);
scope_for_offset(db, &scopes, &source_map, node.file_id, offset)
}
};
let resolver = resolver_for_scope(db.upcast(), def, scope);
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer, file_id }
}
pub(crate) fn new_for_resolver(
@ -662,7 +668,6 @@ impl SourceAnalyzer {
return resolved;
}
// This must be a normal source file rather than macro file.
let ctx = LowerCtx::new(db.upcast(), self.file_id);
let hir_path = Path::from_src(&ctx, path.clone())?;
@ -955,14 +960,15 @@ impl SourceAnalyzer {
}
fn scope_for(
db: &dyn HirDatabase,
scopes: &ExprScopes,
source_map: &BodySourceMap,
node: InFile<&SyntaxNode>,
) -> Option<ScopeId> {
node.value
.ancestors()
.filter_map(ast::Expr::cast)
.filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
node.ancestors_with_macros(db.upcast())
.take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
.filter_map(|it| it.map(ast::Expr::cast).transpose())
.filter_map(|it| source_map.node_expr(it.as_ref()))
.find_map(|it| scopes.scope_for(it))
}
@ -988,8 +994,8 @@ fn scope_for_offset(
Some(it.file_id.macro_file()?.call_node(db.upcast()))
})
.find(|it| it.file_id == from_file)
.filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
Some((source.value.text_range(), scope))
.filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;
Some((source.text_range(), scope))
})
.filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
// find containing scope

View file

@ -231,7 +231,7 @@ impl<'a> SymbolCollector<'a> {
let impl_data = self.db.impl_data(impl_id);
let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string()));
self.with_container_name(impl_name, |s| {
for &assoc_item_id in &impl_data.items {
for &assoc_item_id in impl_data.items.iter() {
s.push_assoc_item(assoc_item_id)
}
})

View file

@ -93,12 +93,6 @@ struct LookupTable {
data: FxHashMap<Type, AlternativeExprs>,
/// New types reached since last query by the `NewTypesKey`
new_types: FxHashMap<NewTypesKey, Vec<Type>>,
/// ScopeDefs that are not interesting any more
exhausted_scopedefs: FxHashSet<ScopeDef>,
/// ScopeDefs that were used in current round
round_scopedef_hits: FxHashSet<ScopeDef>,
/// Amount of rounds since scopedef was first used.
rounds_since_sopedef_hit: FxHashMap<ScopeDef, u32>,
/// Types queried but not present
types_wishlist: FxHashSet<Type>,
/// Threshold to squash trees to `Many`
@ -212,37 +206,6 @@ impl LookupTable {
}
}
/// Mark `ScopeDef` as exhausted meaning it is not interesting for us any more
fn mark_exhausted(&mut self, def: ScopeDef) {
self.exhausted_scopedefs.insert(def);
}
/// Mark `ScopeDef` as used meaning we managed to produce something useful from it
fn mark_fulfilled(&mut self, def: ScopeDef) {
self.round_scopedef_hits.insert(def);
}
/// Start new round (meant to be called at the beginning of iteration in `term_search`)
///
/// This functions marks some `ScopeDef`s as exhausted if there have been
/// `MAX_ROUNDS_AFTER_HIT` rounds after first using a `ScopeDef`.
fn new_round(&mut self) {
for def in &self.round_scopedef_hits {
let hits =
self.rounds_since_sopedef_hit.entry(*def).and_modify(|n| *n += 1).or_insert(0);
const MAX_ROUNDS_AFTER_HIT: u32 = 2;
if *hits > MAX_ROUNDS_AFTER_HIT {
self.exhausted_scopedefs.insert(*def);
}
}
self.round_scopedef_hits.clear();
}
/// Get exhausted `ScopeDef`s
fn exhausted_scopedefs(&self) -> &FxHashSet<ScopeDef> {
&self.exhausted_scopedefs
}
/// Types queried but not found
fn types_wishlist(&mut self) -> &FxHashSet<Type> {
&self.types_wishlist
@ -275,7 +238,7 @@ pub struct TermSearchConfig {
impl Default for TermSearchConfig {
fn default() -> Self {
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 1200 }
}
}
@ -328,19 +291,12 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
while should_continue() {
lookup.new_round();
solutions.extend(tactics::data_constructor(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
// Discard not interesting `ScopeDef`s for speedup
for def in lookup.exhausted_scopedefs() {
defs.remove(def);
}
}
solutions.into_iter().filter(|it| !it.is_many()).unique().collect()

View file

@ -9,8 +9,8 @@ use hir_ty::{
use itertools::Itertools;
use crate::{
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, GenericDef, Local,
ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef,
SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
};
/// Helper function to get path to `ModuleDef`
@ -35,43 +35,6 @@ fn mod_item_path_str(
.ok_or(DisplaySourceCodeError::PathNotFound)
}
/// Helper function to get path to `Type`
fn type_path(
sema_scope: &SemanticsScope<'_>,
ty: &Type,
cfg: ImportPathConfig,
) -> Result<String, DisplaySourceCodeError> {
let db = sema_scope.db;
let m = sema_scope.module();
match ty.as_adt() {
Some(adt) => {
let ty_name = ty.display_source_code(db, m.id, true)?;
let mut path = mod_item_path(sema_scope, &ModuleDef::Adt(adt), cfg).unwrap();
path.pop_segment();
let path = path.display(db.upcast()).to_string();
let res = match path.is_empty() {
true => ty_name,
false => format!("{path}::{ty_name}"),
};
Ok(res)
}
None => ty.display_source_code(db, m.id, true),
}
}
/// Helper function to filter out generic parameters that are default
fn non_default_generics(db: &dyn HirDatabase, def: GenericDef, generics: &[Type]) -> Vec<Type> {
def.type_or_const_params(db)
.into_iter()
.filter_map(|it| it.as_type_param(db))
.zip(generics)
.filter(|(tp, arg)| tp.default(db).as_ref() != Some(arg))
.map(|(_, arg)| arg.clone())
.collect()
}
/// Type tree shows how can we get from set of types to some type.
///
/// Consider the following code as an example
@ -208,20 +171,7 @@ impl Expr {
None => Ok(format!("{target_str}.{func_name}({args})")),
}
}
Expr::Variant { variant, generics, params } => {
let generics = non_default_generics(db, (*variant).into(), generics);
let generics_str = match generics.is_empty() {
true => String::new(),
false => {
let generics = generics
.iter()
.map(|it| type_path(sema_scope, it, cfg))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("::<{generics}>")
}
};
Expr::Variant { variant, params, .. } => {
let inner = match variant.kind(db) {
StructKind::Tuple => {
let args = params
@ -230,7 +180,7 @@ impl Expr {
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("{generics_str}({args})")
format!("({args})")
}
StructKind::Record => {
let fields = variant.fields(db);
@ -248,16 +198,15 @@ impl Expr {
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("{generics_str}{{ {args} }}")
format!("{{ {args} }}")
}
StructKind::Unit => generics_str,
StructKind::Unit => String::new(),
};
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?;
Ok(format!("{prefix}{inner}"))
}
Expr::Struct { strukt, generics, params } => {
let generics = non_default_generics(db, (*strukt).into(), generics);
Expr::Struct { strukt, params, .. } => {
let inner = match strukt.kind(db) {
StructKind::Tuple => {
let args = params
@ -286,18 +235,7 @@ impl Expr {
.join(", ");
format!(" {{ {args} }}")
}
StructKind::Unit => match generics.is_empty() {
true => String::new(),
false => {
let generics = generics
.iter()
.map(|it| type_path(sema_scope, it, cfg))
.collect::<Result<Vec<String>, DisplaySourceCodeError>>()?
.into_iter()
.join(", ");
format!("::<{generics}>")
}
},
StructKind::Unit => String::new(),
};
let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)))?;

View file

@ -17,11 +17,11 @@ use itertools::Itertools;
use rustc_hash::FxHashSet;
use crate::{
Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
TypeParam, Variant,
Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef,
Type, TypeParam,
};
use crate::term_search::{Expr, TermSearchConfig};
use crate::term_search::Expr;
use super::{LookupTable, NewTypesKey, TermSearchCtx};
@ -74,8 +74,6 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
_ => None,
}?;
lookup.mark_exhausted(*def);
let ty = expr.ty(db);
lookup.insert(ty.clone(), std::iter::once(expr.clone()));
@ -124,6 +122,10 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
.filter(move |it| it.is_visible_from(db, module))
.filter_map(AssocItem::as_const)
.filter_map(|it| {
if it.attrs(db).is_unstable() {
return None;
}
let expr = Expr::Const(it);
let ty = it.ty(db);
@ -151,163 +153,27 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn data_constructor<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
defs: &'a FxHashSet<ScopeDef>,
_defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
fn variant_helper(
db: &dyn HirDatabase,
lookup: &mut LookupTable,
should_continue: &dyn std::ops::Fn() -> bool,
parent_enum: Enum,
variant: Variant,
config: &TermSearchConfig,
) -> Vec<(Type, Vec<Expr>)> {
// Ignore unstable
if variant.is_unstable(db) {
return Vec::new();
}
let generics = GenericDef::from(variant.parent_enum(db));
let Some(type_params) = generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()
else {
// Ignore enums with const generics
return Vec::new();
};
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
if !generics.lifetime_params(db).is_empty() {
return Vec::new();
}
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
return Vec::new();
}
let non_default_type_params_len =
type_params.iter().filter(|it| it.default(db).is_none()).count();
let enum_ty_shallow = Adt::from(parent_enum).ty(db);
let generic_params = lookup
.types_wishlist()
.clone()
.into_iter()
.filter(|ty| ty.could_unify_with(db, &enum_ty_shallow))
.map(|it| it.type_arguments().collect::<Vec<Type>>())
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
generic_params
.filter(|_| should_continue())
.filter_map(move |generics| {
// Insert default type params
let mut g = generics.into_iter();
let generics: Vec<_> = type_params
.iter()
.map(|it| it.default(db).or_else(|| g.next()))
.collect::<Option<_>>()?;
let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
// Ignore types that have something to do with lifetimes
if config.enable_borrowcheck && enum_ty.contains_reference(db) {
lookup
.types_wishlist()
.clone()
.into_iter()
.chain(iter::once(ctx.goal.clone()))
.filter_map(|ty| ty.as_adt().map(|adt| (adt, ty)))
.filter(|_| should_continue())
.filter_map(move |(adt, ty)| match adt {
Adt::Struct(strukt) => {
// Ignore unstable or not visible
if strukt.is_unstable(db) || !strukt.is_visible_from(db, module) {
return None;
}
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = variant
.fields(db)
.into_iter()
.map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
// product
let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Variant { variant, generics, params: Vec::new() }]
} else {
param_exprs
.into_iter()
.multi_cartesian_product()
.map(|params| Expr::Variant { variant, generics: generics.clone(), params })
.collect()
};
lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned());
Some((enum_ty, variant_exprs))
})
.collect()
}
defs.iter()
.filter_map(move |def| match def {
ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
let variant_exprs = variant_helper(
db,
lookup,
should_continue,
it.parent_enum(db),
*it,
&ctx.config,
);
if variant_exprs.is_empty() {
return None;
}
if GenericDef::from(it.parent_enum(db))
.type_or_const_params(db)
.into_iter()
.filter_map(|it| it.as_type_param(db))
.all(|it| it.default(db).is_some())
{
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Variant(*it)));
}
Some(variant_exprs)
}
ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(enum_))) => {
let exprs: Vec<(Type, Vec<Expr>)> = enum_
.variants(db)
.into_iter()
.flat_map(|it| {
variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
})
.collect();
if exprs.is_empty() {
return None;
}
if GenericDef::from(*enum_)
.type_or_const_params(db)
.into_iter()
.filter_map(|it| it.as_type_param(db))
.all(|it| it.default(db).is_some())
{
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(*enum_))));
}
Some(exprs)
}
ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => {
// Ignore unstable and not visible
if it.is_unstable(db) || !it.is_visible_from(db, module) {
return None;
}
let generics = GenericDef::from(*it);
// Ignore const params for now
let type_params = generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
let generics = GenericDef::from(strukt);
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
@ -315,48 +181,73 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
return None;
}
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
if ty.contains_unknown() {
return None;
}
let non_default_type_params_len =
type_params.iter().filter(|it| it.default(db).is_none()).count();
// Ignore types that have something to do with lifetimes
if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
return None;
}
let fields = strukt.fields(db);
// Check if all fields are visible, otherwise we cannot fill them
if fields.iter().any(|it| !it.is_visible_from(db, module)) {
return None;
}
let struct_ty_shallow = Adt::from(*it).ty(db);
let generic_params = lookup
.types_wishlist()
.clone()
let generics: Vec<_> = ty.type_arguments().collect();
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = fields
.into_iter()
.filter(|ty| ty.could_unify_with(db, &struct_ty_shallow))
.map(|it| it.type_arguments().collect::<Vec<Type>>())
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
.map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
.collect::<Option<_>>()?;
let exprs = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
let generics: Vec<_> = type_params
.iter()
.map(|it| it.default(db).or_else(|| g.next()))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
// product
let exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Struct { strukt, generics, params: Vec::new() }]
} else {
param_exprs
.into_iter()
.multi_cartesian_product()
.map(|params| Expr::Struct { strukt, generics: generics.clone(), params })
.collect()
};
let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
lookup.insert(ty.clone(), exprs.iter().cloned());
Some((ty, exprs))
}
Adt::Enum(enum_) => {
// Ignore unstable or not visible
if enum_.is_unstable(db) || !enum_.is_visible_from(db, module) {
return None;
}
// Ignore types that have something to do with lifetimes
if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) {
return None;
}
let fields = it.fields(db);
// Check if all fields are visible, otherwise we cannot fill them
if fields.iter().any(|it| !it.is_visible_from(db, module)) {
return None;
}
let generics = GenericDef::from(enum_);
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
if !generics.lifetime_params(db).is_empty() {
return None;
}
if ty.contains_unknown() {
return None;
}
// Ignore types that have something to do with lifetimes
if ctx.config.enable_borrowcheck && ty.contains_reference(db) {
return None;
}
let generics: Vec<_> = ty.type_arguments().collect();
let exprs = enum_
.variants(db)
.into_iter()
.filter_map(|variant| {
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = fields
let param_exprs: Vec<Vec<Expr>> = variant
.fields(db)
.into_iter()
.map(|field| {
lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))
@ -365,36 +256,33 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
// Note that we need special case for 0 param constructors because of multi cartesian
// product
let struct_exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Struct { strukt: *it, generics, params: Vec::new() }]
let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Variant {
variant,
generics: generics.clone(),
params: Vec::new(),
}]
} else {
param_exprs
.into_iter()
.multi_cartesian_product()
.map(|params| Expr::Struct {
strukt: *it,
.map(|params| Expr::Variant {
variant,
generics: generics.clone(),
params,
})
.collect()
};
if non_default_type_params_len == 0 {
// Fulfilled only if there are no generic parameters
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(
Adt::Struct(*it),
)));
}
lookup.insert(struct_ty.clone(), struct_exprs.iter().cloned());
Some((struct_ty, struct_exprs))
lookup.insert(ty.clone(), variant_exprs.iter().cloned());
Some(variant_exprs)
})
.flatten()
.collect();
Some(exprs)
Some((ty, exprs))
}
_ => None,
Adt::Union(_) => None,
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -515,7 +403,6 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
.collect()
};
lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Function(*it)));
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
Some((ret_ty, fn_exprs))
})
@ -555,6 +442,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
lookup
.new_types(NewTypesKey::ImplMethod)
.into_iter()
.filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown()))
.filter(|_| should_continue())
.flat_map(|ty| {
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
})
@ -563,26 +452,15 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
AssocItem::Function(f) => Some((imp, ty, f)),
_ => None,
})
.filter(|_| should_continue())
.filter_map(move |(imp, ty, it)| {
let fn_generics = GenericDef::from(it);
let imp_generics = GenericDef::from(imp);
// Ignore const params for now
let imp_type_params = imp_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore const params for now
let fn_type_params = fn_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty() {
if !fn_generics.lifetime_params(db).is_empty()
|| !imp_generics.lifetime_params(db).is_empty()
{
return None;
}
@ -596,112 +474,59 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
return None;
}
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
|| fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
// Ignore functions with generics for now as they kill the performance
// Also checking bounds for generics is problematic
if !fn_generics.type_or_const_params(db).is_empty() {
return None;
}
let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
// Filter out functions that return references
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
{
return None;
}
// Double check that we have fully known type
if ty.type_arguments().any(|it| it.contains_unknown()) {
// Ignore functions that do not change the type
if ty.could_unify_with_deeply(db, &ret_ty) {
return None;
}
let non_default_fn_type_params_len =
fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
let self_ty =
it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments());
// Ignore functions with generics for now as they kill the performance
// Also checking bounds for generics is problematic
if non_default_fn_type_params_len > 0 {
// Ignore functions that have different self type
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
return None;
}
let generic_params = lookup
.iter_types()
.collect::<Vec<_>>() // Force take ownership
let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_args(db, ty.type_arguments())
.into_iter()
.permutations(non_default_fn_type_params_len);
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
let generics: Vec<_> = ty
.type_arguments()
.map(Some)
.chain(fn_type_params.iter().map(|it| match it.default(db) {
Some(ty) => Some(ty),
None => {
let generic = g.next().expect("Missing type param");
// Filter out generics that do not unify due to trait bounds
it.ty(db).could_unify_with(db, &generic).then_some(generic)
}
}))
.collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
);
// Filter out functions that return references
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
|| ret_ty.is_raw_ptr()
{
return None;
let generics: Vec<_> = ty.type_arguments().collect();
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
.chain(param_exprs)
.multi_cartesian_product()
.map(|params| {
let mut params = params.into_iter();
let target = Box::new(params.next().unwrap());
Expr::Method {
func: it,
generics: generics.clone(),
target,
params: params.collect(),
}
// Ignore functions that do not change the type
if ty.could_unify_with_deeply(db, &ret_ty) {
return None;
}
let self_ty = it
.self_param(db)
.expect("No self param")
.ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
// Ignore functions that have different self type
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
return None;
}
let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
.chain(param_exprs)
.multi_cartesian_product()
.map(|params| {
let mut params = params.into_iter();
let target = Box::new(params.next().unwrap());
Expr::Method {
func: it,
generics: generics.clone(),
target,
params: params.collect(),
}
})
.collect();
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
Some((ret_ty, fn_exprs))
})
.collect();
Some(exprs)
Some((ret_ty, fn_exprs))
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@ -773,9 +598,8 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::unit()), value: "()" },
]
.into_iter()
.map(|exprs| {
.inspect(|exprs| {
lookup.insert(exprs.ty(db), std::iter::once(exprs.clone()));
exprs
})
.filter(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal))
}
@ -805,6 +629,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.clone()
.into_iter()
.chain(iter::once(ctx.goal.clone()))
.filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown()))
.filter(|_| should_continue())
.flat_map(|ty| {
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
@ -815,24 +640,11 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
AssocItem::Function(f) => Some((imp, ty, f)),
_ => None,
})
.filter(|_| should_continue())
.filter_map(move |(imp, ty, it)| {
let fn_generics = GenericDef::from(it);
let imp_generics = GenericDef::from(imp);
// Ignore const params for now
let imp_type_params = imp_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore const params for now
let fn_type_params = fn_generics
.type_or_const_params(db)
.into_iter()
.map(|it| it.as_type_param(db))
.collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty()
|| !imp_generics.lifetime_params(db).is_empty()
@ -850,104 +662,43 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
return None;
}
// Only account for stable type parameters for now, unstable params can be default
// tho, for example in `Box<T, #[unstable] A: Allocator>`
if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
|| fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
// Ignore functions with generics for now as they kill the performance
// Also checking bounds for generics is problematic
if !fn_generics.type_or_const_params(db).is_empty() {
return None;
}
let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
// Filter out functions that return references
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
{
return None;
}
// Double check that we have fully known type
if ty.type_arguments().any(|it| it.contains_unknown()) {
return None;
}
let non_default_fn_type_params_len =
fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
// Ignore functions with generics for now as they kill the performance
// Also checking bounds for generics is problematic
if non_default_fn_type_params_len > 0 {
return None;
}
let generic_params = lookup
.iter_types()
.collect::<Vec<_>>() // Force take ownership
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_args(db, ty.type_arguments())
.into_iter()
.permutations(non_default_fn_type_params_len);
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
let generics: Vec<_> = ty
.type_arguments()
.map(Some)
.chain(fn_type_params.iter().map(|it| match it.default(db) {
Some(ty) => Some(ty),
None => {
let generic = g.next().expect("Missing type param");
it.trait_bounds(db)
.into_iter()
.all(|bound| generic.impls_trait(db, bound, &[]));
// Filter out generics that do not unify due to trait bounds
it.ty(db).could_unify_with(db, &generic).then_some(generic)
}
}))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
// product
let generics = ty.type_arguments().collect();
let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Function { func: it, generics, params: Vec::new() }]
} else {
param_exprs
.into_iter()
.multi_cartesian_product()
.map(|params| Expr::Function { func: it, generics: generics.clone(), params })
.collect()
};
let ret_ty = it.ret_type_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
);
// Filter out functions that return references
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
|| ret_ty.is_raw_ptr()
{
return None;
}
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
// Ignore functions that do not change the type
// if ty.could_unify_with_deeply(db, &ret_ty) {
// return None;
// }
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
.map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
// product
let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
vec![Expr::Function { func: it, generics, params: Vec::new() }]
} else {
param_exprs
.into_iter()
.multi_cartesian_product()
.map(|params| Expr::Function {
func: it,
generics: generics.clone(),
params,
})
.collect()
};
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
Some((ret_ty, fn_exprs))
})
.collect();
Some(exprs)
Some((ret_ty, fn_exprs))
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}

View file

@ -15,6 +15,8 @@ pub struct AssistConfig {
pub insert_use: InsertUseConfig,
pub prefer_no_std: bool,
pub prefer_prelude: bool,
pub prefer_absolute: bool,
pub assist_emit_must_use: bool,
pub term_search_fuel: u64,
pub term_search_borrowck: bool,
}

View file

@ -74,6 +74,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let module = ctx.sema.scope(expr.syntax())?.module();

View file

@ -1,7 +1,7 @@
use either::Either;
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
ast::{self, make, HasArgList},
ast::{self, make, HasArgList, HasGenericArgs},
ted, AstNode,
};

View file

@ -93,6 +93,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;

View file

@ -1,3 +1,4 @@
use either::Either;
use hir::{ImportPathConfig, ModuleDef};
use ide_db::{
assists::{AssistId, AssistKind},
@ -76,7 +77,11 @@ pub(crate) fn bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
let usages = definition.usages(&ctx.sema).all();
add_enum_def(edit, ctx, &usages, target_node, &target_module);
replace_usages(edit, ctx, usages, definition, &target_module);
let mut delayed_mutations = Vec::new();
replace_usages(edit, ctx, usages, definition, &target_module, &mut delayed_mutations);
for (scope, path) in delayed_mutations {
insert_use(&scope, path, &ctx.config.insert_use);
}
},
)
}
@ -91,29 +96,32 @@ struct BoolNodeData {
/// Attempts to find an appropriate node to apply the action to.
fn find_bool_node(ctx: &AssistContext<'_>) -> Option<BoolNodeData> {
let name: ast::Name = ctx.find_node_at_offset()?;
let name = ctx.find_node_at_offset::<ast::Name>()?;
if let Some(let_stmt) = name.syntax().ancestors().find_map(ast::LetStmt::cast) {
let bind_pat = match let_stmt.pat()? {
ast::Pat::IdentPat(pat) => pat,
_ => {
cov_mark::hit!(not_applicable_in_non_ident_pat);
return None;
}
};
let def = ctx.sema.to_def(&bind_pat)?;
if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
let def = ctx.sema.to_def(&ident_pat)?;
if !def.ty(ctx.db()).is_bool() {
cov_mark::hit!(not_applicable_non_bool_local);
return None;
}
Some(BoolNodeData {
target_node: let_stmt.syntax().clone(),
name,
ty_annotation: let_stmt.ty(),
initializer: let_stmt.initializer(),
definition: Definition::Local(def),
})
let local_definition = Definition::Local(def);
match ident_pat.syntax().parent().and_then(Either::<ast::Param, ast::LetStmt>::cast)? {
Either::Left(param) => Some(BoolNodeData {
target_node: param.syntax().clone(),
name,
ty_annotation: param.ty(),
initializer: None,
definition: local_definition,
}),
Either::Right(let_stmt) => Some(BoolNodeData {
target_node: let_stmt.syntax().clone(),
name,
ty_annotation: let_stmt.ty(),
initializer: let_stmt.initializer(),
definition: local_definition,
}),
}
} else if let Some(const_) = name.syntax().parent().and_then(ast::Const::cast) {
let def = ctx.sema.to_def(&const_)?;
if !def.ty(ctx.db()).is_bool() {
@ -197,6 +205,7 @@ fn replace_usages(
usages: UsageSearchResult,
target_definition: Definition,
target_module: &hir::Module,
delayed_mutations: &mut Vec<(ImportScope, ast::Path)>,
) {
for (file_id, references) in usages {
edit.edit_file(file_id);
@ -217,6 +226,7 @@ fn replace_usages(
def.usages(&ctx.sema).all(),
target_definition,
target_module,
delayed_mutations,
)
}
} else if let Some(initializer) = find_assignment_usage(&name) {
@ -255,6 +265,7 @@ fn replace_usages(
def.usages(&ctx.sema).all(),
target_definition,
target_module,
delayed_mutations,
)
}
}
@ -306,7 +317,7 @@ fn replace_usages(
ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)),
ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)),
};
insert_use(&scope, path, &ctx.config.insert_use);
delayed_mutations.push((scope, path));
}
},
)
@ -329,6 +340,7 @@ fn augment_references_with_imports(
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
references
@ -449,7 +461,20 @@ fn add_enum_def(
usages: &UsageSearchResult,
target_node: SyntaxNode,
target_module: &hir::Module,
) {
) -> Option<()> {
let insert_before = node_to_insert_before(target_node);
if ctx
.sema
.scope(&insert_before)?
.module()
.scope(ctx.db(), Some(*target_module))
.iter()
.any(|(name, _)| name.as_str() == Some("Bool"))
{
return None;
}
let make_enum_pub = usages
.iter()
.flat_map(|(_, refs)| refs)
@ -460,7 +485,6 @@ fn add_enum_def(
.any(|module| module.nearest_non_block_module(ctx.db()) != *target_module);
let enum_def = make_bool_enum(make_enum_pub);
let insert_before = node_to_insert_before(target_node);
let indent = IndentLevel::from_node(&insert_before);
enum_def.reindent_to(indent);
@ -468,6 +492,8 @@ fn add_enum_def(
insert_before.text_range().start(),
format!("{}\n\n{indent}", enum_def.syntax().text()),
);
Some(())
}
/// Finds where to put the new enum definition.
@ -517,6 +543,125 @@ mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
#[test]
fn parameter_with_first_param_usage() {
check_assist(
bool_to_enum,
r#"
fn function($0foo: bool, bar: bool) {
if foo {
println!("foo");
}
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: Bool, bar: bool) {
if foo == Bool::True {
println!("foo");
}
}
"#,
)
}
#[test]
fn no_duplicate_enums() {
check_assist(
bool_to_enum,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, $0bar: bool) {
if bar {
println!("bar");
}
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, bar: Bool) {
if bar == Bool::True {
println!("bar");
}
}
"#,
)
}
#[test]
fn parameter_with_last_param_usage() {
check_assist(
bool_to_enum,
r#"
fn function(foo: bool, $0bar: bool) {
if bar {
println!("bar");
}
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, bar: Bool) {
if bar == Bool::True {
println!("bar");
}
}
"#,
)
}
#[test]
fn parameter_with_middle_param_usage() {
check_assist(
bool_to_enum,
r#"
fn function(foo: bool, $0bar: bool, baz: bool) {
if bar {
println!("bar");
}
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, bar: Bool, baz: bool) {
if bar == Bool::True {
println!("bar");
}
}
"#,
)
}
#[test]
fn parameter_with_closure_usage() {
check_assist(
bool_to_enum,
r#"
fn main() {
let foo = |$0bar: bool| bar;
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn main() {
let foo = |bar: Bool| bar == Bool::True;
}
"#,
)
}
#[test]
fn local_variable_with_usage() {
check_assist(
@ -784,7 +929,6 @@ fn main() {
#[test]
fn local_variable_non_ident_pat() {
cov_mark::check!(not_applicable_in_non_ident_pat);
check_assist_not_applicable(
bool_to_enum,
r#"

View file

@ -1,7 +1,7 @@
use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait};
use itertools::Itertools;
use syntax::{
ast::{self, make, AstNode, HasName},
ast::{self, make, AstNode, HasGenericArgs, HasName},
ted,
};

View file

@ -1,6 +1,6 @@
use hir::ImportPathConfig;
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait};
use syntax::ast::{self, AstNode, HasName};
use syntax::ast::{self, AstNode, HasGenericArgs, HasName};
use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -47,6 +47,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let src_type_path = {

View file

@ -186,6 +186,7 @@ fn augment_references_with_imports(
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
references

View file

@ -90,6 +90,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let module = ctx.sema.scope(ident_pat.syntax())?.module();

View file

@ -216,6 +216,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
);

View file

@ -393,6 +393,7 @@ fn process_references(
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
);
if let Some(mut mod_path) = mod_path {

View file

@ -1,7 +1,7 @@
use either::Either;
use ide_db::syntax_helpers::node_ext::walk_ty;
use syntax::{
ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName},
ast::{self, edit::IndentLevel, make, AstNode, HasGenericArgs, HasGenericParams, HasName},
ted,
};

View file

@ -17,8 +17,9 @@ use syntax::{
self,
edit::{self, AstNodeEdit},
edit_in_place::AttrsOwnerEdit,
make, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericParams, HasName,
HasTypeBounds, HasVisibility as astHasVisibility, Path, WherePred,
make, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs,
HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
WherePred,
},
ted::{self, Position},
AstNode, NodeOrToken, SmolStr, SyntaxKind,

View file

@ -64,6 +64,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)?;
@ -111,6 +112,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)?;

View file

@ -4,7 +4,7 @@ use itertools::Itertools;
use stdx::{format_to, to_lower_snake_case};
use syntax::{
algo::skip_whitespace_token,
ast::{self, edit::IndentLevel, HasDocComments, HasName},
ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName},
match_ast, AstNode, AstToken,
};

View file

@ -65,6 +65,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)?;

View file

@ -15,7 +15,9 @@ use ide_db::{
};
use itertools::{izip, Itertools};
use syntax::{
ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr},
ast::{
self, edit::IndentLevel, edit_in_place::Indent, HasArgList, HasGenericArgs, Pat, PathExpr,
},
ted, AstNode, NodeOrToken, SyntaxKind,
};

View file

@ -489,6 +489,25 @@ use foo::bar;
);
}
#[test]
fn test_merge_nested_empty_and_self_with_other() {
check_assist(
merge_imports,
r"
use foo::$0{bar};
use foo::{bar::{self, other}};
",
r"
use foo::bar::{self, other};
",
);
check_assist_import_one_variations!(
"foo::$0{bar}",
"foo::{bar::{self, other}}",
"use {foo::bar::{self, other}};"
);
}
#[test]
fn test_merge_nested_list_self_and_glob() {
check_assist(

View file

@ -119,10 +119,39 @@ mod tests {
);
}
#[test]
fn test_braces_kept() {
check_assist_not_applicable_variations!("foo::bar::{$0self}");
// This code compiles but transforming "bar::{self}" into "bar" causes a
// compilation error (the name `bar` is defined multiple times).
// Therefore, the normalize_input assist must not apply here.
check_assist_not_applicable(
normalize_import,
r"
mod foo {
pub mod bar {}
pub const bar: i32 = 8;
}
use foo::bar::{$0self};
const bar: u32 = 99;
fn main() {
let local_bar = bar;
}
",
);
}
#[test]
fn test_redundant_braces() {
check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}");
check_assist_variations!("foo::{bar::{self}}", "foo::bar");
check_assist_variations!("foo::{bar::{self}}", "foo::bar::{self}");
check_assist_variations!("foo::{bar::{*}}", "foo::bar::*");
check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux");
check_assist_variations!(

View file

@ -53,6 +53,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)?;

View file

@ -6,6 +6,7 @@ use ide_db::{
helpers::mod_path_to_ast,
imports::import_assets::{ImportCandidate, LocatedImport},
};
use syntax::ast::HasGenericArgs;
use syntax::{
ast,
ast::{make, HasArgList},
@ -40,6 +41,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let mut proposed_imports: Vec<_> =

View file

@ -239,4 +239,33 @@ mod tests {
check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(return 2) + 2 }"#);
}
#[test]
fn remove_parens_indirect_calls() {
check_assist(
remove_parentheses,
r#"fn f(call: fn(usize), arg: usize) { $0(call)(arg); }"#,
r#"fn f(call: fn(usize), arg: usize) { call(arg); }"#,
);
check_assist(
remove_parentheses,
r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { $0(call)(arg); }"#,
r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { call(arg); }"#,
);
// Parentheses are necessary when calling a function-like pointer that is a member of a struct or union.
check_assist_not_applicable(
remove_parentheses,
r#"
struct Foo<T> {
t: T,
}
impl Foo<fn(usize)> {
fn foo(&self, arg: usize) {
$0(self.t)(arg);
}
}"#,
);
}
}

View file

@ -89,6 +89,7 @@ pub(crate) fn replace_derive_with_manual_impl(
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)
.as_ref()

View file

@ -4,7 +4,7 @@ use ide_db::{
imports::insert_use::{insert_use, ImportScope},
};
use syntax::{
ast::{self, make},
ast::{self, make, HasGenericArgs},
match_ast, ted, AstNode, SyntaxNode,
};
@ -70,6 +70,7 @@ pub(crate) fn replace_qualified_name_with_use(
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)
})

View file

@ -1,7 +1,6 @@
use hir::HirDisplay;
use syntax::{
ast::{Expr, GenericArg, GenericArgList},
ast::{LetStmt, Type::InferType},
ast::{Expr, GenericArg, GenericArgList, HasGenericArgs, LetStmt, Type::InferType},
AstNode, TextRange,
};

View file

@ -37,7 +37,11 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
sema: &ctx.sema,
scope: &scope,
goal: target_ty,
config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
config: TermSearchConfig {
fuel: ctx.config.term_search_fuel,
enable_borrowcheck: ctx.config.term_search_borrowck,
..Default::default()
},
};
let paths = hir::term_search::term_search(&term_search_ctx);
@ -56,6 +60,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)
.ok()
@ -144,7 +149,7 @@ fn f() { let a = A { x: 1, y: true }; let b: i32 = a.x; }"#,
term_search,
r#"//- minicore: todo, unimplemented, option
fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
r#"fn f() { let a: i32 = 1; let b: Option<i32> = None; }"#,
r#"fn f() { let a: i32 = 1; let b: Option<i32> = Some(a); }"#,
)
}

View file

@ -4,7 +4,7 @@ use ide_db::{
famous_defs::FamousDefs,
};
use syntax::{
ast::{self, HasVisibility},
ast::{self, HasGenericArgs, HasVisibility},
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
};
@ -142,6 +142,7 @@ pub(crate) fn desugar_async_into_impl_future(
ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
)?;
let trait_path = trait_path.display(ctx.db());

Some files were not shown because too many files have changed in this diff Show more