mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Auto merge of #127617 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
commit
a91f7d72f1
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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"] }
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,8 +245,14 @@ 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) => {
|
||||
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()))
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,19 +133,48 @@ impl ItemTree {
|
||||
if let Some(attrs) = top_attrs {
|
||||
item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
|
||||
}
|
||||
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);
|
||||
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
|
||||
/// `ItemTree` was created from.
|
||||
@ -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())],
|
||||
}
|
||||
}
|
||||
|
@ -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 ¶ms.type_or_consts[*id].name() {
|
||||
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));
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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) = ¶m.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(¶m.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),
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
|
||||
span,
|
||||
DocCommentDesugarMode::Mbe,
|
||||
)
|
||||
});
|
||||
let body = mbe::syntax_node_to_token_tree(
|
||||
body.syntax(),
|
||||
map.as_ref(),
|
||||
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(),
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -275,8 +275,10 @@ pub mod known {
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
f16,
|
||||
f32,
|
||||
f64,
|
||||
f128,
|
||||
bool,
|
||||
char,
|
||||
str,
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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()),
|
||||
|
@ -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 => {
|
||||
|
@ -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]
|
||||
|
@ -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" {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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(_)
|
||||
|
@ -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,
|
||||
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 bounds =
|
||||
(*rpits).map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter()));
|
||||
let Some(impl_traits) = impl_traits else {
|
||||
return ty;
|
||||
};
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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| {
|
||||
|
@ -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,
|
||||
}),
|
||||
),
|
||||
},
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,45 +836,65 @@ 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();
|
||||
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));
|
||||
}
|
||||
}
|
||||
let expected_num = if generic_args.has_self_type {
|
||||
self_param as usize + type_params + const_params
|
||||
} 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() {
|
||||
had_explicit_args = true;
|
||||
let arg = generic_arg_to_chalk(
|
||||
self.db,
|
||||
id,
|
||||
@ -883,82 +904,53 @@ impl<'a> TyLoweringContext<'a> {
|
||||
|_, 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);
|
||||
}
|
||||
}
|
||||
} 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(),
|
||||
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),
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(remaining_params.len() + substs.len(), total_len);
|
||||
|
||||
};
|
||||
// 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<_>>();
|
||||
|
||||
if generics.len() > 0 {
|
||||
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
if !subst.is_empty(Interner) {
|
||||
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 {
|
||||
|
@ -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,
|
||||
|
@ -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(_)));
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -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]
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
@ -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 '{}': ()
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -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 } => {
|
||||
|
@ -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 = ¶ms.type_or_consts[self.id.local_id()];
|
||||
let param_data = ¶ms[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;
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = ¶ms.type_or_consts[self.id.local_id()];
|
||||
let data = ¶ms[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 ¶ms.type_or_consts[self.id.local_id] {
|
||||
match ¶ms[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 ¶ms.type_or_consts[self.id.local_id] {
|
||||
match ¶ms[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 ¶ms.type_or_consts[self.id.local_id] {
|
||||
match ¶ms[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()),
|
||||
},
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
|
@ -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()
|
||||
|
@ -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)))?;
|
||||
|
@ -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,212 +153,101 @@ 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();
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
};
|
||||
let generics = GenericDef::from(strukt);
|
||||
|
||||
// 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) {
|
||||
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 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 generics: Vec<_> = ty.type_arguments().collect();
|
||||
|
||||
// Early exit if some param cannot be filled from lookup
|
||||
let param_exprs: Vec<Vec<Expr>> = variant
|
||||
.fields(db)
|
||||
let param_exprs: Vec<Vec<Expr>> = fields
|
||||
.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() }]
|
||||
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::Variant { variant, generics: generics.clone(), params })
|
||||
.map(|params| Expr::Struct { strukt, generics: generics.clone(), params })
|
||||
.collect()
|
||||
};
|
||||
lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned());
|
||||
|
||||
Some((enum_ty, variant_exprs))
|
||||
})
|
||||
.collect()
|
||||
lookup.insert(ty.clone(), exprs.iter().cloned());
|
||||
Some((ty, exprs))
|
||||
}
|
||||
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() {
|
||||
Adt::Enum(enum_) => {
|
||||
// Ignore unstable or not visible
|
||||
if enum_.is_unstable(db) || !enum_.is_visible_from(db, module) {
|
||||
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(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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
let struct_ty_shallow = Adt::from(*it).ty(db);
|
||||
let generic_params = lookup
|
||||
.types_wishlist()
|
||||
.clone()
|
||||
.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()));
|
||||
|
||||
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<_>>()?;
|
||||
|
||||
let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
|
||||
|
||||
// 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)) {
|
||||
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))
|
||||
})
|
||||
.collect();
|
||||
Some(exprs)
|
||||
}
|
||||
_ => None,
|
||||
lookup.insert(ty.clone(), variant_exprs.iter().cloned());
|
||||
Some(variant_exprs)
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
Some((ty, exprs))
|
||||
}
|
||||
Adt::Union(_) => None,
|
||||
})
|
||||
.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,59 +474,15 @@ 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())
|
||||
{
|
||||
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 {
|
||||
if !fn_generics.type_or_const_params(db).is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let generic_params = lookup
|
||||
.iter_types()
|
||||
.collect::<Vec<_>>() // Force take ownership
|
||||
.into_iter()
|
||||
.permutations(non_default_fn_type_params_len);
|
||||
|
||||
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()),
|
||||
);
|
||||
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()
|
||||
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@ -658,10 +492,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
|
||||
return None;
|
||||
}
|
||||
|
||||
let self_ty = it
|
||||
.self_param(db)
|
||||
.expect("No self param")
|
||||
.ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
|
||||
let self_ty =
|
||||
it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments());
|
||||
|
||||
// Ignore functions that have different self type
|
||||
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
|
||||
@ -672,14 +504,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
|
||||
|
||||
// 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()),
|
||||
)
|
||||
.params_without_self_with_args(db, ty.type_arguments())
|
||||
.into_iter()
|
||||
.map(|field| lookup.find_autoref(db, field.ty()))
|
||||
.collect::<Option<_>>()?;
|
||||
|
||||
let generics: Vec<_> = ty.type_arguments().collect();
|
||||
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
|
||||
.chain(param_exprs)
|
||||
.multi_cartesian_product()
|
||||
@ -695,13 +525,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
|
||||
})
|
||||
.collect();
|
||||
|
||||
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
|
||||
Some((ret_ty, fn_exprs))
|
||||
})
|
||||
.collect();
|
||||
Some(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())
|
||||
{
|
||||
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 {
|
||||
if !fn_generics.type_or_const_params(db).is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let generic_params = lookup
|
||||
.iter_types()
|
||||
.collect::<Vec<_>>() // Force take ownership
|
||||
.into_iter()
|
||||
.permutations(non_default_fn_type_params_len);
|
||||
|
||||
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<_>>()?;
|
||||
|
||||
let ret_ty = it.ret_type_with_args(
|
||||
db,
|
||||
ty.type_arguments().chain(generics.iter().cloned()),
|
||||
);
|
||||
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()
|
||||
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
// 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()),
|
||||
)
|
||||
.params_without_self_with_args(db, ty.type_arguments())
|
||||
.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 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,
|
||||
})
|
||||
.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)
|
||||
})
|
||||
.flatten()
|
||||
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
|
||||
.flatten()
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)?;
|
||||
|
@ -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 {
|
||||
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: Definition::Local(def),
|
||||
})
|
||||
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#"
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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!(
|
||||
|
@ -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,
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -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<_> =
|
||||
|
@ -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);
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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); }"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user